Merge branches 'clk-davinci', 'clk-si544', 'clk-rockchip', 'clk-uniphier' and 'clk-ti-flag-fix' into clk-next
* clk-davinci: clk: davinci: Remove redundant dev_err calls clk: davinci: cfgchip: Add TI DA8XX USB PHY clocks clk: davinci: New driver for TI DA8XX CFGCHIP clocks dt-bindings: clock: Add bindings for DA8XX CFGCHIP clocks clk: davinci: Add platform information for TI DM646x PSC clk: davinci: Add platform information for TI DM644x PSC clk: davinci: Add platform information for TI DM365 PSC clk: davinci: Add platform information for TI DM355 PSC clk: davinci: Add platform information for TI DA850 PSC clk: davinci: Add platform information for TI DA830 PSC clk: davinci: New driver for davinci PSC clocks dt-bindings: clock: New bindings for TI Davinci PSC clk: davinci: Add platform information for TI DM646x PLL clk: davinci: Add platform information for TI DM644x PLL clk: davinci: Add platform information for TI DM365 PLL clk: davinci: Add platform information for TI DM355 PLL clk: davinci: Add platform information for TI DA850 PLL clk: davinci: Add platform information for TI DA830 PLL clk: davinci: New driver for davinci PLL clocks dt-bindings: clock: Add new bindings for TI Davinci PLL clocks * clk-si544: clk: Add driver for the si544 clock generator chip * clk-rockchip: clk: rockchip: assign correct id for pclk_ddr and hclk_sd in rk3399 clk: rockchip: Fix error return in phase clock registration clk: rockchip: Correct the behaviour of restoring cached phase clk: rockchip: Fix wrong parents for MMC phase clock for rk3328 clk: rockchip: Fix wrong parent for SDMMC phase clock for rk3228 clk: rockchip: Add 1.6GHz PLL rate for rk3399 clk: rockchip: Restore the clock phase after the rate was changed clk: rockchip: Prevent calculating mmc phase if clock rate is zero clk: rockchip: Free the memory on the error path clk: rockchip: document hdmi_phy external input for rk3328 clk: rockchip: add flags for rk3328 dclk_lcdc clk: rockchip: remove ignore_unused flag from rk3328 vio_h2p clocks clk: rockchip: protect all remaining rk3328 interconnect clocks clk: rockchip: export sclk_hdmi_sfc on rk3328 clk: rockchip: remove HCLK_VIO from rk3328 dt header clk: rockchip: fix hclk_vio_niu on rk3328 * clk-uniphier: clk: uniphier: add additional ethernet clock lines for Pro4 clk: uniphier: add SATA clock control support clk: uniphier: add PCIe clock control support clk: uniphier: add ethernet clock control support for PXs3 clk: uniphier: add Pro4/Pro5/PXs2 audio system clock * clk-ti-flag-fix: clk: ti: fix flag space conflict with clkctrl clocks clk: ti: clkctrl: add support for CLK_SET_RATE_PARENT flag
This commit is contained in:
commit
a83fdfae5a
|
@ -32,6 +32,7 @@ clock-output-names:
|
|||
- "clkin_i2s" - external I2S clock - optional,
|
||||
- "gmac_clkin" - external GMAC clock - optional
|
||||
- "phy_50m_out" - output clock of the pll in the mac phy
|
||||
- "hdmi_phy" - output clock of the hdmi phy pll - optional
|
||||
|
||||
Example: Clock controller node:
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
Binding for Silicon Labs 544 programmable I2C clock generator.
|
||||
|
||||
Reference
|
||||
This binding uses the common clock binding[1]. Details about the device can be
|
||||
found in the datasheet[2].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Si544 datasheet
|
||||
https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf
|
||||
|
||||
Required properties:
|
||||
- compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according
|
||||
to the speed grade of the chip.
|
||||
- reg: I2C device address.
|
||||
- #clock-cells: From common clock bindings: Shall be 0.
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names: From common clock bindings. Recommended to be "si544".
|
||||
|
||||
Example:
|
||||
si544: clock-controller@55 {
|
||||
reg = <0x55>;
|
||||
#clock-cells = <0>;
|
||||
compatible = "silabs,si544b";
|
||||
};
|
|
@ -0,0 +1,93 @@
|
|||
Binding for TI DA8XX/OMAP-L13X/AM17XX/AM18XX CFGCHIP clocks
|
||||
|
||||
TI DA8XX/OMAP-L13X/AM17XX/AM18XX SoCs contain a general purpose set of
|
||||
registers call CFGCHIPn. Some of these registers function as clock
|
||||
gates. This document describes the bindings for those clocks.
|
||||
|
||||
All of the clock nodes described below must be child nodes of a CFGCHIP node
|
||||
(compatible = "ti,da830-cfgchip").
|
||||
|
||||
USB PHY clocks
|
||||
--------------
|
||||
Required properties:
|
||||
- compatible: shall be "ti,da830-usb-phy-clocks".
|
||||
- #clock-cells: from common clock binding; shall be set to 1.
|
||||
- clocks: phandles to the parent clocks corresponding to clock-names
|
||||
- clock-names: shall be "fck", "usb_refclkin", "auxclk"
|
||||
|
||||
This node provides two clocks. The clock at index 0 is the USB 2.0 PHY 48MHz
|
||||
clock and the clock at index 1 is the USB 1.1 PHY 48MHz clock.
|
||||
|
||||
eHRPWM Time Base Clock (TBCLK)
|
||||
------------------------------
|
||||
Required properties:
|
||||
- compatible: shall be "ti,da830-tbclksync".
|
||||
- #clock-cells: from common clock binding; shall be set to 0.
|
||||
- clocks: phandle to the parent clock
|
||||
- clock-names: shall be "fck"
|
||||
|
||||
PLL DIV4.5 divider
|
||||
------------------
|
||||
Required properties:
|
||||
- compatible: shall be "ti,da830-div4p5ena".
|
||||
- #clock-cells: from common clock binding; shall be set to 0.
|
||||
- clocks: phandle to the parent clock
|
||||
- clock-names: shall be "pll0_pllout"
|
||||
|
||||
EMIFA clock source (ASYNC1)
|
||||
---------------------------
|
||||
Required properties:
|
||||
- compatible: shall be "ti,da850-async1-clksrc".
|
||||
- #clock-cells: from common clock binding; shall be set to 0.
|
||||
- clocks: phandles to the parent clocks corresponding to clock-names
|
||||
- clock-names: shall be "pll0_sysclk3", "div4.5"
|
||||
|
||||
ASYNC3 clock source
|
||||
-------------------
|
||||
Required properties:
|
||||
- compatible: shall be "ti,da850-async3-clksrc".
|
||||
- #clock-cells: from common clock binding; shall be set to 0.
|
||||
- clocks: phandles to the parent clocks corresponding to clock-names
|
||||
- clock-names: shall be "pll0_sysclk2", "pll1_sysclk2"
|
||||
|
||||
Examples:
|
||||
|
||||
cfgchip: syscon@1417c {
|
||||
compatible = "ti,da830-cfgchip", "syscon", "simple-mfd";
|
||||
reg = <0x1417c 0x14>;
|
||||
|
||||
usb_phy_clk: usb-phy-clocks {
|
||||
compatible = "ti,da830-usb-phy-clocks";
|
||||
#clock-cells = <1>;
|
||||
clocks = <&psc1 1>, <&usb_refclkin>, <&pll0_auxclk>;
|
||||
clock-names = "fck", "usb_refclkin", "auxclk";
|
||||
};
|
||||
ehrpwm_tbclk: ehrpwm_tbclk {
|
||||
compatible = "ti,da830-tbclksync";
|
||||
#clock-cells = <0>;
|
||||
clocks = <&psc1 17>;
|
||||
clock-names = "fck";
|
||||
};
|
||||
div4p5_clk: div4.5 {
|
||||
compatible = "ti,da830-div4p5ena";
|
||||
#clock-cells = <0>;
|
||||
clocks = <&pll0_pllout>;
|
||||
clock-names = "pll0_pllout";
|
||||
};
|
||||
async1_clk: async1 {
|
||||
compatible = "ti,da850-async1-clksrc";
|
||||
#clock-cells = <0>;
|
||||
clocks = <&pll0_sysclk 3>, <&div4p5_clk>;
|
||||
clock-names = "pll0_sysclk3", "div4.5";
|
||||
};
|
||||
async3_clk: async3 {
|
||||
compatible = "ti,da850-async3-clksrc";
|
||||
#clock-cells = <0>;
|
||||
clocks = <&pll0_sysclk 2>, <&pll1_sysclk 2>;
|
||||
clock-names = "pll0_sysclk2", "pll1_sysclk2";
|
||||
};
|
||||
};
|
||||
|
||||
Also see:
|
||||
- Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
Binding for TI DaVinci PLL Controllers
|
||||
|
||||
The PLL provides clocks to most of the components on the SoC. In addition
|
||||
to the PLL itself, this controller also contains bypasses, gates, dividers,
|
||||
an multiplexers for various clock signals.
|
||||
|
||||
Required properties:
|
||||
- compatible: shall be one of:
|
||||
- "ti,da850-pll0" for PLL0 on DA850/OMAP-L138/AM18XX
|
||||
- "ti,da850-pll1" for PLL1 on DA850/OMAP-L138/AM18XX
|
||||
- reg: physical base address and size of the controller's register area.
|
||||
- clocks: phandles corresponding to the clock names
|
||||
- clock-names: names of the clock sources - depends on compatible string
|
||||
- for "ti,da850-pll0", shall be "clksrc", "extclksrc"
|
||||
- for "ti,da850-pll1", shall be "clksrc"
|
||||
|
||||
Optional properties:
|
||||
- ti,clkmode-square-wave: Indicates that the the board is supplying a square
|
||||
wave input on the OSCIN pin instead of using a crystal oscillator.
|
||||
This property is only valid when compatible = "ti,da850-pll0".
|
||||
|
||||
|
||||
Optional child nodes:
|
||||
|
||||
pllout
|
||||
Describes the main PLL clock output (before POSTDIV). The node name must
|
||||
be "pllout".
|
||||
|
||||
Required properties:
|
||||
- #clock-cells: shall be 0
|
||||
|
||||
sysclk
|
||||
Describes the PLLDIVn divider clocks that provide the SYSCLKn clock
|
||||
domains. The node name must be "sysclk". Consumers of this node should
|
||||
use "n" in "SYSCLKn" as the index parameter for the clock cell.
|
||||
|
||||
Required properties:
|
||||
- #clock-cells: shall be 1
|
||||
|
||||
auxclk
|
||||
Describes the AUXCLK output of the PLL. The node name must be "auxclk".
|
||||
This child node is only valid when compatible = "ti,da850-pll0".
|
||||
|
||||
Required properties:
|
||||
- #clock-cells: shall be 0
|
||||
|
||||
obsclk
|
||||
Describes the OBSCLK output of the PLL. The node name must be "obsclk".
|
||||
|
||||
Required properties:
|
||||
- #clock-cells: shall be 0
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
pll0: clock-controller@11000 {
|
||||
compatible = "ti,da850-pll0";
|
||||
reg = <0x11000 0x1000>;
|
||||
clocks = <&ref_clk>, <&pll1_sysclk 3>;
|
||||
clock-names = "clksrc", "extclksrc";
|
||||
ti,clkmode-square-wave;
|
||||
|
||||
pll0_pllout: pllout {
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
pll0_sysclk: sysclk {
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
pll0_auxclk: auxclk {
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
pll0_obsclk: obsclk {
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
pll1: clock-controller@21a000 {
|
||||
compatible = "ti,da850-pll1";
|
||||
reg = <0x21a000 0x1000>;
|
||||
clocks = <&ref_clk>;
|
||||
clock-names = "clksrc";
|
||||
|
||||
pll0_sysclk: sysclk {
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
pll0_obsclk: obsclk {
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
Also see:
|
||||
- Documentation/devicetree/bindings/clock/clock-bindings.txt
|
|
@ -0,0 +1,71 @@
|
|||
Binding for TI DaVinci Power Sleep Controller (PSC)
|
||||
|
||||
The PSC provides power management, clock gating and reset functionality. It is
|
||||
primarily used for clocking.
|
||||
|
||||
Required properties:
|
||||
- compatible: shall be one of:
|
||||
- "ti,da850-psc0" for PSC0 on DA850/OMAP-L138/AM18XX
|
||||
- "ti,da850-psc1" for PSC1 on DA850/OMAP-L138/AM18XX
|
||||
- reg: physical base address and size of the controller's register area
|
||||
- #clock-cells: from common clock binding; shall be set to 1
|
||||
- #power-domain-cells: from generic power domain binding; shall be set to 1.
|
||||
- clocks: phandles to clocks corresponding to the clock-names property
|
||||
- clock-names: list of parent clock names - depends on compatible value
|
||||
- for "ti,da850-psc0", shall be "pll0_sysclk1", "pll0_sysclk2",
|
||||
"pll0_sysclk4", "pll0_sysclk6", "async1"
|
||||
- for "ti,da850-psc1", shall be "pll0_sysclk2", "pll0_sysclk4", "async3"
|
||||
|
||||
Optional properties:
|
||||
- #reset-cells: from reset binding; shall be set to 1 - only applicable when
|
||||
at least one local domain provides a local reset.
|
||||
|
||||
Consumers:
|
||||
|
||||
Clock, power domain and reset consumers shall use the local power domain
|
||||
module ID (LPSC) as the index corresponding to the clock cell. Refer to
|
||||
the device-specific datasheet to find these numbers. NB: Most local
|
||||
domains only provide a clock/power domain and not a reset.
|
||||
|
||||
Examples:
|
||||
|
||||
psc0: clock-controller@10000 {
|
||||
compatible = "ti,da850-psc0";
|
||||
reg = <0x10000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
clocks = <&pll0_sysclk 1>, <&pll0_sysclk 2>,
|
||||
<&pll0_sysclk 4>, <&pll0_sysclk 6>, <&async1_clk>;
|
||||
clock_names = "pll0_sysclk1", "pll0_sysclk2",
|
||||
"pll0_sysclk4", "pll0_sysclk6", "async1";
|
||||
};
|
||||
psc1: clock-controller@227000 {
|
||||
compatible = "ti,da850-psc1";
|
||||
reg = <0x227000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
clocks = <&pll0_sysclk 2>, <&pll0_sysclk 4>, <&async3_clk>;
|
||||
clock_names = "pll0_sysclk2", "pll0_sysclk4", "async3";
|
||||
};
|
||||
|
||||
/* consumer */
|
||||
dsp: dsp@11800000 {
|
||||
compatible = "ti,da850-dsp";
|
||||
reg = <0x11800000 0x40000>,
|
||||
<0x11e00000 0x8000>,
|
||||
<0x11f00000 0x8000>,
|
||||
<0x01c14044 0x4>,
|
||||
<0x01c14174 0x8>;
|
||||
reg-names = "l2sram", "l1pram", "l1dram", "host1cfg", "chipsig";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <28>;
|
||||
clocks = <&psc0 15>;
|
||||
power-domains = <&psc0 15>;
|
||||
resets = <&psc0 15>;
|
||||
};
|
||||
|
||||
Also see:
|
||||
- Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
- Documentation/devicetree/bindings/power/power_domain.txt
|
||||
- Documentation/devicetree/bindings/reset/reset.txt
|
|
@ -13793,6 +13793,13 @@ F: arch/arm/mach-davinci/
|
|||
F: drivers/i2c/busses/i2c-davinci.c
|
||||
F: arch/arm/boot/dts/da850*
|
||||
|
||||
TI DAVINCI SERIES CLOCK DRIVER
|
||||
M: David Lechner <david@lechnology.com>
|
||||
R: Sekhar Nori <nsekhar@ti.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/clock/ti/davinci/
|
||||
F: drivers/clk/davinci/
|
||||
|
||||
TI DAVINCI SERIES GPIO DRIVER
|
||||
M: Keerthy <j-keerthy@ti.com>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
|
|
|
@ -93,6 +93,15 @@ config COMMON_CLK_SI514
|
|||
This driver supports the Silicon Labs 514 programmable clock
|
||||
generator.
|
||||
|
||||
config COMMON_CLK_SI544
|
||||
tristate "Clock driver for SiLabs 544 devices"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
---help---
|
||||
This driver supports the Silicon Labs 544 programmable clock
|
||||
generator.
|
||||
|
||||
config COMMON_CLK_SI570
|
||||
tristate "Clock driver for SiLabs 570 and compatible devices"
|
||||
depends on I2C
|
||||
|
|
|
@ -44,6 +44,7 @@ obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
|
|||
obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o
|
||||
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
|
||||
obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
|
||||
obj-$(CONFIG_COMMON_CLK_SI544) += clk-si544.o
|
||||
obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
|
||||
obj-$(CONFIG_COMMON_CLK_STM32F) += clk-stm32f4.o
|
||||
obj-$(CONFIG_COMMON_CLK_STM32H7) += clk-stm32h7.o
|
||||
|
@ -62,6 +63,7 @@ obj-$(CONFIG_ARCH_ARTPEC) += axis/
|
|||
obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/
|
||||
obj-y += bcm/
|
||||
obj-$(CONFIG_ARCH_BERLIN) += berlin/
|
||||
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
|
||||
obj-$(CONFIG_H8300) += h8300/
|
||||
obj-$(CONFIG_ARCH_HISI) += hisilicon/
|
||||
obj-y += imgtec/
|
||||
|
|
|
@ -0,0 +1,411 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Driver for Silicon Labs Si544 Programmable Oscillator
|
||||
* Copyright (C) 2018 Topic Embedded Products
|
||||
* Author: Mike Looijmans <mike.looijmans@topic.nl>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* I2C registers (decimal as in datasheet) */
|
||||
#define SI544_REG_CONTROL 7
|
||||
#define SI544_REG_OE_STATE 17
|
||||
#define SI544_REG_HS_DIV 23
|
||||
#define SI544_REG_LS_HS_DIV 24
|
||||
#define SI544_REG_FBDIV0 26
|
||||
#define SI544_REG_FBDIV8 27
|
||||
#define SI544_REG_FBDIV16 28
|
||||
#define SI544_REG_FBDIV24 29
|
||||
#define SI544_REG_FBDIV32 30
|
||||
#define SI544_REG_FBDIV40 31
|
||||
#define SI544_REG_FCAL_OVR 69
|
||||
#define SI544_REG_ADPLL_DELTA_M0 231
|
||||
#define SI544_REG_ADPLL_DELTA_M8 232
|
||||
#define SI544_REG_ADPLL_DELTA_M16 233
|
||||
#define SI544_REG_PAGE_SELECT 255
|
||||
|
||||
/* Register values */
|
||||
#define SI544_CONTROL_RESET BIT(7)
|
||||
#define SI544_CONTROL_MS_ICAL2 BIT(3)
|
||||
|
||||
#define SI544_OE_STATE_ODC_OE BIT(0)
|
||||
|
||||
/* Max freq depends on speed grade */
|
||||
#define SI544_MIN_FREQ 200000U
|
||||
|
||||
/* Si544 Internal oscilator runs at 55.05 MHz */
|
||||
#define FXO 55050000U
|
||||
|
||||
/* VCO range is 10.8 .. 12.1 GHz, max depends on speed grade */
|
||||
#define FVCO_MIN 10800000000ULL
|
||||
|
||||
#define HS_DIV_MAX 2046
|
||||
#define HS_DIV_MAX_ODD 33
|
||||
|
||||
/* Lowest frequency synthesizeable using only the HS divider */
|
||||
#define MIN_HSDIV_FREQ (FVCO_MIN / HS_DIV_MAX)
|
||||
|
||||
enum si544_speed_grade {
|
||||
si544a,
|
||||
si544b,
|
||||
si544c,
|
||||
};
|
||||
|
||||
struct clk_si544 {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
struct i2c_client *i2c_client;
|
||||
enum si544_speed_grade speed_grade;
|
||||
};
|
||||
#define to_clk_si544(_hw) container_of(_hw, struct clk_si544, hw)
|
||||
|
||||
/**
|
||||
* struct clk_si544_muldiv - Multiplier/divider settings
|
||||
* @fb_div_frac: integer part of feedback divider (32 bits)
|
||||
* @fb_div_int: fractional part of feedback divider (11 bits)
|
||||
* @hs_div: 1st divider, 5..2046, must be even when >33
|
||||
* @ls_div_bits: 2nd divider, as 2^x, range 0..5
|
||||
* If ls_div_bits is non-zero, hs_div must be even
|
||||
*/
|
||||
struct clk_si544_muldiv {
|
||||
u32 fb_div_frac;
|
||||
u16 fb_div_int;
|
||||
u16 hs_div;
|
||||
u8 ls_div_bits;
|
||||
};
|
||||
|
||||
/* Enables or disables the output driver */
|
||||
static int si544_enable_output(struct clk_si544 *data, bool enable)
|
||||
{
|
||||
return regmap_update_bits(data->regmap, SI544_REG_OE_STATE,
|
||||
SI544_OE_STATE_ODC_OE, enable ? SI544_OE_STATE_ODC_OE : 0);
|
||||
}
|
||||
|
||||
/* Retrieve clock multiplier and dividers from hardware */
|
||||
static int si544_get_muldiv(struct clk_si544 *data,
|
||||
struct clk_si544_muldiv *settings)
|
||||
{
|
||||
int err;
|
||||
u8 reg[6];
|
||||
|
||||
err = regmap_bulk_read(data->regmap, SI544_REG_HS_DIV, reg, 2);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
settings->ls_div_bits = (reg[1] >> 4) & 0x07;
|
||||
settings->hs_div = (reg[1] & 0x07) << 8 | reg[0];
|
||||
|
||||
err = regmap_bulk_read(data->regmap, SI544_REG_FBDIV0, reg, 6);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
settings->fb_div_int = reg[4] | (reg[5] & 0x07) << 8;
|
||||
settings->fb_div_frac = reg[0] | reg[1] << 8 | reg[2] << 16 |
|
||||
reg[3] << 24;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si544_set_muldiv(struct clk_si544 *data,
|
||||
struct clk_si544_muldiv *settings)
|
||||
{
|
||||
int err;
|
||||
u8 reg[6];
|
||||
|
||||
reg[0] = settings->hs_div;
|
||||
reg[1] = settings->hs_div >> 8 | settings->ls_div_bits << 4;
|
||||
|
||||
err = regmap_bulk_write(data->regmap, SI544_REG_HS_DIV, reg, 2);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
reg[0] = settings->fb_div_frac;
|
||||
reg[1] = settings->fb_div_frac >> 8;
|
||||
reg[2] = settings->fb_div_frac >> 16;
|
||||
reg[3] = settings->fb_div_frac >> 24;
|
||||
reg[4] = settings->fb_div_int;
|
||||
reg[5] = settings->fb_div_int >> 8;
|
||||
|
||||
/*
|
||||
* Writing to SI544_REG_FBDIV40 triggers the clock change, so that
|
||||
* must be written last
|
||||
*/
|
||||
return regmap_bulk_write(data->regmap, SI544_REG_FBDIV0, reg, 6);
|
||||
}
|
||||
|
||||
static bool is_valid_frequency(const struct clk_si544 *data,
|
||||
unsigned long frequency)
|
||||
{
|
||||
unsigned long max_freq = 0;
|
||||
|
||||
if (frequency < SI544_MIN_FREQ)
|
||||
return false;
|
||||
|
||||
switch (data->speed_grade) {
|
||||
case si544a:
|
||||
max_freq = 1500000000;
|
||||
break;
|
||||
case si544b:
|
||||
max_freq = 800000000;
|
||||
break;
|
||||
case si544c:
|
||||
max_freq = 350000000;
|
||||
break;
|
||||
}
|
||||
|
||||
return frequency <= max_freq;
|
||||
}
|
||||
|
||||
/* Calculate divider settings for a given frequency */
|
||||
static int si544_calc_muldiv(struct clk_si544_muldiv *settings,
|
||||
unsigned long frequency)
|
||||
{
|
||||
u64 vco;
|
||||
u32 ls_freq;
|
||||
u32 tmp;
|
||||
u8 res;
|
||||
|
||||
/* Determine the minimum value of LS_DIV and resulting target freq. */
|
||||
ls_freq = frequency;
|
||||
settings->ls_div_bits = 0;
|
||||
|
||||
if (frequency >= MIN_HSDIV_FREQ) {
|
||||
settings->ls_div_bits = 0;
|
||||
} else {
|
||||
res = 1;
|
||||
tmp = 2 * HS_DIV_MAX;
|
||||
while (tmp <= (HS_DIV_MAX * 32)) {
|
||||
if (((u64)frequency * tmp) >= FVCO_MIN)
|
||||
break;
|
||||
++res;
|
||||
tmp <<= 1;
|
||||
}
|
||||
settings->ls_div_bits = res;
|
||||
ls_freq = frequency << res;
|
||||
}
|
||||
|
||||
/* Determine minimum HS_DIV by rounding up */
|
||||
vco = FVCO_MIN + ls_freq - 1;
|
||||
do_div(vco, ls_freq);
|
||||
settings->hs_div = vco;
|
||||
|
||||
/* round up to even number when required */
|
||||
if ((settings->hs_div & 1) &&
|
||||
(settings->hs_div > HS_DIV_MAX_ODD || settings->ls_div_bits))
|
||||
++settings->hs_div;
|
||||
|
||||
/* Calculate VCO frequency (in 10..12GHz range) */
|
||||
vco = (u64)ls_freq * settings->hs_div;
|
||||
|
||||
/* Calculate the integer part of the feedback divider */
|
||||
tmp = do_div(vco, FXO);
|
||||
settings->fb_div_int = vco;
|
||||
|
||||
/* And the fractional bits using the remainder */
|
||||
vco = (u64)tmp << 32;
|
||||
do_div(vco, FXO);
|
||||
settings->fb_div_frac = vco;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate resulting frequency given the register settings */
|
||||
static unsigned long si544_calc_rate(struct clk_si544_muldiv *settings)
|
||||
{
|
||||
u32 d = settings->hs_div * BIT(settings->ls_div_bits);
|
||||
u64 vco;
|
||||
|
||||
/* Calculate VCO from the fractional part */
|
||||
vco = (u64)settings->fb_div_frac * FXO;
|
||||
vco += (FXO / 2);
|
||||
vco >>= 32;
|
||||
|
||||
/* Add the integer part of the VCO frequency */
|
||||
vco += (u64)settings->fb_div_int * FXO;
|
||||
|
||||
/* Apply divider to obtain the generated frequency */
|
||||
do_div(vco, d);
|
||||
|
||||
return vco;
|
||||
}
|
||||
|
||||
static unsigned long si544_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_si544 *data = to_clk_si544(hw);
|
||||
struct clk_si544_muldiv settings;
|
||||
int err;
|
||||
|
||||
err = si544_get_muldiv(data, &settings);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
return si544_calc_rate(&settings);
|
||||
}
|
||||
|
||||
static long si544_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct clk_si544 *data = to_clk_si544(hw);
|
||||
struct clk_si544_muldiv settings;
|
||||
int err;
|
||||
|
||||
if (!is_valid_frequency(data, rate))
|
||||
return -EINVAL;
|
||||
|
||||
err = si544_calc_muldiv(&settings, rate);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return si544_calc_rate(&settings);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update output frequency for "big" frequency changes
|
||||
*/
|
||||
static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_si544 *data = to_clk_si544(hw);
|
||||
struct clk_si544_muldiv settings;
|
||||
int err;
|
||||
|
||||
if (!is_valid_frequency(data, rate))
|
||||
return -EINVAL;
|
||||
|
||||
err = si544_calc_muldiv(&settings, rate);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
si544_enable_output(data, false);
|
||||
|
||||
/* Allow FCAL for this frequency update */
|
||||
err = regmap_write(data->regmap, SI544_REG_FCAL_OVR, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
||||
err = si544_set_muldiv(data, &settings);
|
||||
if (err < 0)
|
||||
return err; /* Undefined state now, best to leave disabled */
|
||||
|
||||
/* Trigger calibration */
|
||||
err = regmap_write(data->regmap, SI544_REG_CONTROL,
|
||||
SI544_CONTROL_MS_ICAL2);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Applying a new frequency can take up to 10ms */
|
||||
usleep_range(10000, 12000);
|
||||
|
||||
si544_enable_output(data, true);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct clk_ops si544_clk_ops = {
|
||||
.recalc_rate = si544_recalc_rate,
|
||||
.round_rate = si544_round_rate,
|
||||
.set_rate = si544_set_rate,
|
||||
};
|
||||
|
||||
static bool si544_regmap_is_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case SI544_REG_CONTROL:
|
||||
case SI544_REG_FCAL_OVR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config si544_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.max_register = SI544_REG_PAGE_SELECT,
|
||||
.volatile_reg = si544_regmap_is_volatile,
|
||||
};
|
||||
|
||||
static int si544_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct clk_si544 *data;
|
||||
struct clk_init_data init;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
init.ops = &si544_clk_ops;
|
||||
init.flags = 0;
|
||||
init.num_parents = 0;
|
||||
data->hw.init = &init;
|
||||
data->i2c_client = client;
|
||||
data->speed_grade = id->driver_data;
|
||||
|
||||
if (of_property_read_string(client->dev.of_node, "clock-output-names",
|
||||
&init.name))
|
||||
init.name = client->dev.of_node->name;
|
||||
|
||||
data->regmap = devm_regmap_init_i2c(client, &si544_regmap_config);
|
||||
if (IS_ERR(data->regmap))
|
||||
return PTR_ERR(data->regmap);
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
/* Select page 0, just to be sure, there appear to be no more */
|
||||
err = regmap_write(data->regmap, SI544_REG_PAGE_SELECT, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = devm_clk_hw_register(&client->dev, &data->hw);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "clock registration failed\n");
|
||||
return err;
|
||||
}
|
||||
err = devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_simple_get,
|
||||
&data->hw);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "unable to add clk provider\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id si544_id[] = {
|
||||
{ "si544a", si544a },
|
||||
{ "si544b", si544b },
|
||||
{ "si544c", si544c },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, si544_id);
|
||||
|
||||
static const struct of_device_id clk_si544_of_match[] = {
|
||||
{ .compatible = "silabs,si544a" },
|
||||
{ .compatible = "silabs,si544b" },
|
||||
{ .compatible = "silabs,si544c" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clk_si544_of_match);
|
||||
|
||||
static struct i2c_driver si544_driver = {
|
||||
.driver = {
|
||||
.name = "si544",
|
||||
.of_match_table = clk_si544_of_match,
|
||||
},
|
||||
.probe = si544_probe,
|
||||
.id_table = si544_id,
|
||||
};
|
||||
module_i2c_driver(si544_driver);
|
||||
|
||||
MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
|
||||
MODULE_DESCRIPTION("Si544 driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,21 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
ifeq ($(CONFIG_COMMON_CLK), y)
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DA8XX) += da8xx-cfgchip.o
|
||||
|
||||
obj-y += pll.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DA830) += pll-da830.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DA850) += pll-da850.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DM355) += pll-dm355.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DM365) += pll-dm365.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DM644x) += pll-dm644x.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DM646x) += pll-dm646x.o
|
||||
|
||||
obj-y += psc.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DA830) += psc-da830.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DA850) += psc-da850.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DM355) += psc-dm355.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DM365) += psc-dm365.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DM644x) += psc-dm644x.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DM646x) += psc-dm646x.o
|
||||
endif
|
|
@ -0,0 +1,790 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Clock driver for DA8xx/AM17xx/AM18xx/OMAP-L13x CFGCHIP
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mfd/da8xx-cfgchip.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/clk-da8xx-cfgchip.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* --- Gate clocks --- */
|
||||
|
||||
#define DA8XX_GATE_CLOCK_IS_DIV4P5 BIT(1)
|
||||
|
||||
struct da8xx_cfgchip_gate_clk_info {
|
||||
const char *name;
|
||||
u32 cfgchip;
|
||||
u32 bit;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct da8xx_cfgchip_gate_clk {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
u32 reg;
|
||||
u32 mask;
|
||||
};
|
||||
|
||||
#define to_da8xx_cfgchip_gate_clk(_hw) \
|
||||
container_of((_hw), struct da8xx_cfgchip_gate_clk, hw)
|
||||
|
||||
static int da8xx_cfgchip_gate_clk_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct da8xx_cfgchip_gate_clk *clk = to_da8xx_cfgchip_gate_clk(hw);
|
||||
|
||||
return regmap_write_bits(clk->regmap, clk->reg, clk->mask, clk->mask);
|
||||
}
|
||||
|
||||
static void da8xx_cfgchip_gate_clk_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct da8xx_cfgchip_gate_clk *clk = to_da8xx_cfgchip_gate_clk(hw);
|
||||
|
||||
regmap_write_bits(clk->regmap, clk->reg, clk->mask, 0);
|
||||
}
|
||||
|
||||
static int da8xx_cfgchip_gate_clk_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct da8xx_cfgchip_gate_clk *clk = to_da8xx_cfgchip_gate_clk(hw);
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(clk->regmap, clk->reg, &val);
|
||||
|
||||
return !!(val & clk->mask);
|
||||
}
|
||||
|
||||
static unsigned long da8xx_cfgchip_div4p5_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
/* this clock divides by 4.5 */
|
||||
return parent_rate * 2 / 9;
|
||||
}
|
||||
|
||||
static const struct clk_ops da8xx_cfgchip_gate_clk_ops = {
|
||||
.enable = da8xx_cfgchip_gate_clk_enable,
|
||||
.disable = da8xx_cfgchip_gate_clk_disable,
|
||||
.is_enabled = da8xx_cfgchip_gate_clk_is_enabled,
|
||||
};
|
||||
|
||||
static const struct clk_ops da8xx_cfgchip_div4p5_clk_ops = {
|
||||
.enable = da8xx_cfgchip_gate_clk_enable,
|
||||
.disable = da8xx_cfgchip_gate_clk_disable,
|
||||
.is_enabled = da8xx_cfgchip_gate_clk_is_enabled,
|
||||
.recalc_rate = da8xx_cfgchip_div4p5_recalc_rate,
|
||||
};
|
||||
|
||||
static struct da8xx_cfgchip_gate_clk * __init
|
||||
da8xx_cfgchip_gate_clk_register(struct device *dev,
|
||||
const struct da8xx_cfgchip_gate_clk_info *info,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
struct clk *parent;
|
||||
const char *parent_name;
|
||||
struct da8xx_cfgchip_gate_clk *gate;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
parent = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(parent))
|
||||
return ERR_CAST(parent);
|
||||
|
||||
parent_name = __clk_get_name(parent);
|
||||
|
||||
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = info->name;
|
||||
if (info->flags & DA8XX_GATE_CLOCK_IS_DIV4P5)
|
||||
init.ops = &da8xx_cfgchip_div4p5_clk_ops;
|
||||
else
|
||||
init.ops = &da8xx_cfgchip_gate_clk_ops;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.flags = 0;
|
||||
|
||||
gate->hw.init = &init;
|
||||
gate->regmap = regmap;
|
||||
gate->reg = info->cfgchip;
|
||||
gate->mask = info->bit;
|
||||
|
||||
ret = devm_clk_hw_register(dev, &gate->hw);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return gate;
|
||||
}
|
||||
|
||||
static const struct da8xx_cfgchip_gate_clk_info da8xx_tbclksync_info __initconst = {
|
||||
.name = "ehrpwm_tbclk",
|
||||
.cfgchip = CFGCHIP(1),
|
||||
.bit = CFGCHIP1_TBCLKSYNC,
|
||||
};
|
||||
|
||||
static int __init da8xx_cfgchip_register_tbclk(struct device *dev,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
struct da8xx_cfgchip_gate_clk *gate;
|
||||
|
||||
gate = da8xx_cfgchip_gate_clk_register(dev, &da8xx_tbclksync_info,
|
||||
regmap);
|
||||
if (IS_ERR(gate))
|
||||
return PTR_ERR(gate);
|
||||
|
||||
clk_hw_register_clkdev(&gate->hw, "tbclk", "ehrpwm.0");
|
||||
clk_hw_register_clkdev(&gate->hw, "tbclk", "ehrpwm.1");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct da8xx_cfgchip_gate_clk_info da8xx_div4p5ena_info __initconst = {
|
||||
.name = "div4.5",
|
||||
.cfgchip = CFGCHIP(3),
|
||||
.bit = CFGCHIP3_DIV45PENA,
|
||||
.flags = DA8XX_GATE_CLOCK_IS_DIV4P5,
|
||||
};
|
||||
|
||||
static int __init da8xx_cfgchip_register_div4p5(struct device *dev,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
struct da8xx_cfgchip_gate_clk *gate;
|
||||
|
||||
gate = da8xx_cfgchip_gate_clk_register(dev, &da8xx_div4p5ena_info, regmap);
|
||||
if (IS_ERR(gate))
|
||||
return PTR_ERR(gate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init
|
||||
of_da8xx_cfgchip_gate_clk_init(struct device *dev,
|
||||
const struct da8xx_cfgchip_gate_clk_info *info,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
struct da8xx_cfgchip_gate_clk *gate;
|
||||
|
||||
gate = da8xx_cfgchip_gate_clk_register(dev, info, regmap);
|
||||
if (IS_ERR(gate))
|
||||
return PTR_ERR(gate);
|
||||
|
||||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, gate);
|
||||
}
|
||||
|
||||
static int __init of_da8xx_tbclksync_init(struct device *dev,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
return of_da8xx_cfgchip_gate_clk_init(dev, &da8xx_tbclksync_info, regmap);
|
||||
}
|
||||
|
||||
static int __init of_da8xx_div4p5ena_init(struct device *dev,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
return of_da8xx_cfgchip_gate_clk_init(dev, &da8xx_div4p5ena_info, regmap);
|
||||
}
|
||||
|
||||
/* --- MUX clocks --- */
|
||||
|
||||
struct da8xx_cfgchip_mux_clk_info {
|
||||
const char *name;
|
||||
const char *parent0;
|
||||
const char *parent1;
|
||||
u32 cfgchip;
|
||||
u32 bit;
|
||||
};
|
||||
|
||||
struct da8xx_cfgchip_mux_clk {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
u32 reg;
|
||||
u32 mask;
|
||||
};
|
||||
|
||||
#define to_da8xx_cfgchip_mux_clk(_hw) \
|
||||
container_of((_hw), struct da8xx_cfgchip_mux_clk, hw)
|
||||
|
||||
static int da8xx_cfgchip_mux_clk_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct da8xx_cfgchip_mux_clk *clk = to_da8xx_cfgchip_mux_clk(hw);
|
||||
unsigned int val = index ? clk->mask : 0;
|
||||
|
||||
return regmap_write_bits(clk->regmap, clk->reg, clk->mask, val);
|
||||
}
|
||||
|
||||
static u8 da8xx_cfgchip_mux_clk_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct da8xx_cfgchip_mux_clk *clk = to_da8xx_cfgchip_mux_clk(hw);
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(clk->regmap, clk->reg, &val);
|
||||
|
||||
return (val & clk->mask) ? 1 : 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops da8xx_cfgchip_mux_clk_ops = {
|
||||
.set_parent = da8xx_cfgchip_mux_clk_set_parent,
|
||||
.get_parent = da8xx_cfgchip_mux_clk_get_parent,
|
||||
};
|
||||
|
||||
static struct da8xx_cfgchip_mux_clk * __init
|
||||
da8xx_cfgchip_mux_clk_register(struct device *dev,
|
||||
const struct da8xx_cfgchip_mux_clk_info *info,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
const char * const parent_names[] = { info->parent0, info->parent1 };
|
||||
struct da8xx_cfgchip_mux_clk *mux;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = info->name;
|
||||
init.ops = &da8xx_cfgchip_mux_clk_ops;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = 2;
|
||||
init.flags = 0;
|
||||
|
||||
mux->hw.init = &init;
|
||||
mux->regmap = regmap;
|
||||
mux->reg = info->cfgchip;
|
||||
mux->mask = info->bit;
|
||||
|
||||
ret = devm_clk_hw_register(dev, &mux->hw);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return mux;
|
||||
}
|
||||
|
||||
static const struct da8xx_cfgchip_mux_clk_info da850_async1_info __initconst = {
|
||||
.name = "async1",
|
||||
.parent0 = "pll0_sysclk3",
|
||||
.parent1 = "div4.5",
|
||||
.cfgchip = CFGCHIP(3),
|
||||
.bit = CFGCHIP3_EMA_CLKSRC,
|
||||
};
|
||||
|
||||
static int __init da8xx_cfgchip_register_async1(struct device *dev,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
struct da8xx_cfgchip_mux_clk *mux;
|
||||
|
||||
mux = da8xx_cfgchip_mux_clk_register(dev, &da850_async1_info, regmap);
|
||||
if (IS_ERR(mux))
|
||||
return PTR_ERR(mux);
|
||||
|
||||
clk_hw_register_clkdev(&mux->hw, "async1", "da850-psc0");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct da8xx_cfgchip_mux_clk_info da850_async3_info __initconst = {
|
||||
.name = "async3",
|
||||
.parent0 = "pll0_sysclk2",
|
||||
.parent1 = "pll1_sysclk2",
|
||||
.cfgchip = CFGCHIP(3),
|
||||
.bit = CFGCHIP3_ASYNC3_CLKSRC,
|
||||
};
|
||||
|
||||
static int __init da850_cfgchip_register_async3(struct device *dev,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
struct da8xx_cfgchip_mux_clk *mux;
|
||||
struct clk_hw *parent;
|
||||
|
||||
mux = da8xx_cfgchip_mux_clk_register(dev, &da850_async3_info, regmap);
|
||||
if (IS_ERR(mux))
|
||||
return PTR_ERR(mux);
|
||||
|
||||
clk_hw_register_clkdev(&mux->hw, "async3", "da850-psc1");
|
||||
|
||||
/* pll1_sysclk2 is not affected by CPU scaling, so use it for async3 */
|
||||
parent = clk_hw_get_parent_by_index(&mux->hw, 1);
|
||||
if (parent)
|
||||
clk_set_parent(mux->hw.clk, parent->clk);
|
||||
else
|
||||
dev_warn(dev, "Failed to find async3 parent clock\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init
|
||||
of_da8xx_cfgchip_init_mux_clock(struct device *dev,
|
||||
const struct da8xx_cfgchip_mux_clk_info *info,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
struct da8xx_cfgchip_mux_clk *mux;
|
||||
|
||||
mux = da8xx_cfgchip_mux_clk_register(dev, info, regmap);
|
||||
if (IS_ERR(mux))
|
||||
return PTR_ERR(mux);
|
||||
|
||||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &mux->hw);
|
||||
}
|
||||
|
||||
static int __init of_da850_async1_init(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
return of_da8xx_cfgchip_init_mux_clock(dev, &da850_async1_info, regmap);
|
||||
}
|
||||
|
||||
static int __init of_da850_async3_init(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
return of_da8xx_cfgchip_init_mux_clock(dev, &da850_async3_info, regmap);
|
||||
}
|
||||
|
||||
/* --- USB 2.0 PHY clock --- */
|
||||
|
||||
struct da8xx_usb0_clk48 {
|
||||
struct clk_hw hw;
|
||||
struct clk *fck;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
#define to_da8xx_usb0_clk48(_hw) \
|
||||
container_of((_hw), struct da8xx_usb0_clk48, hw)
|
||||
|
||||
static int da8xx_usb0_clk48_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw);
|
||||
|
||||
/* The USB 2.0 PSC clock is only needed temporarily during the USB 2.0
|
||||
* PHY clock enable, but since clk_prepare() can't be called in an
|
||||
* atomic context (i.e. in clk_enable()), we have to prepare it here.
|
||||
*/
|
||||
return clk_prepare(usb0->fck);
|
||||
}
|
||||
|
||||
static void da8xx_usb0_clk48_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw);
|
||||
|
||||
clk_unprepare(usb0->fck);
|
||||
}
|
||||
|
||||
static int da8xx_usb0_clk48_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw);
|
||||
unsigned int mask, val;
|
||||
int ret;
|
||||
|
||||
/* Locking the USB 2.O PLL requires that the USB 2.O PSC is enabled
|
||||
* temporaily. It can be turned back off once the PLL is locked.
|
||||
*/
|
||||
clk_enable(usb0->fck);
|
||||
|
||||
/* Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1
|
||||
* PHY may use the USB 2.0 PLL clock without USB 2.0 OTG being used.
|
||||
*/
|
||||
mask = CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_PHY_PLLON;
|
||||
val = CFGCHIP2_PHY_PLLON;
|
||||
|
||||
regmap_write_bits(usb0->regmap, CFGCHIP(2), mask, val);
|
||||
ret = regmap_read_poll_timeout(usb0->regmap, CFGCHIP(2), val,
|
||||
val & CFGCHIP2_PHYCLKGD, 0, 500000);
|
||||
|
||||
clk_disable(usb0->fck);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void da8xx_usb0_clk48_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw);
|
||||
unsigned int val;
|
||||
|
||||
val = CFGCHIP2_PHYPWRDN;
|
||||
regmap_write_bits(usb0->regmap, CFGCHIP(2), val, val);
|
||||
}
|
||||
|
||||
static int da8xx_usb0_clk48_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw);
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(usb0->regmap, CFGCHIP(2), &val);
|
||||
|
||||
return !!(val & CFGCHIP2_PHYCLKGD);
|
||||
}
|
||||
|
||||
static unsigned long da8xx_usb0_clk48_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw);
|
||||
unsigned int mask, val;
|
||||
|
||||
/* The parent clock rate must be one of the following */
|
||||
mask = CFGCHIP2_REFFREQ_MASK;
|
||||
switch (parent_rate) {
|
||||
case 12000000:
|
||||
val = CFGCHIP2_REFFREQ_12MHZ;
|
||||
break;
|
||||
case 13000000:
|
||||
val = CFGCHIP2_REFFREQ_13MHZ;
|
||||
break;
|
||||
case 19200000:
|
||||
val = CFGCHIP2_REFFREQ_19_2MHZ;
|
||||
break;
|
||||
case 20000000:
|
||||
val = CFGCHIP2_REFFREQ_20MHZ;
|
||||
break;
|
||||
case 24000000:
|
||||
val = CFGCHIP2_REFFREQ_24MHZ;
|
||||
break;
|
||||
case 26000000:
|
||||
val = CFGCHIP2_REFFREQ_26MHZ;
|
||||
break;
|
||||
case 38400000:
|
||||
val = CFGCHIP2_REFFREQ_38_4MHZ;
|
||||
break;
|
||||
case 40000000:
|
||||
val = CFGCHIP2_REFFREQ_40MHZ;
|
||||
break;
|
||||
case 48000000:
|
||||
val = CFGCHIP2_REFFREQ_48MHZ;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
regmap_write_bits(usb0->regmap, CFGCHIP(2), mask, val);
|
||||
|
||||
/* USB 2.0 PLL always supplies 48MHz */
|
||||
return 48000000;
|
||||
}
|
||||
|
||||
static long da8xx_usb0_clk48_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
return 48000000;
|
||||
}
|
||||
|
||||
static int da8xx_usb0_clk48_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw);
|
||||
|
||||
return regmap_write_bits(usb0->regmap, CFGCHIP(2),
|
||||
CFGCHIP2_USB2PHYCLKMUX,
|
||||
index ? CFGCHIP2_USB2PHYCLKMUX : 0);
|
||||
}
|
||||
|
||||
static u8 da8xx_usb0_clk48_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw);
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(usb0->regmap, CFGCHIP(2), &val);
|
||||
|
||||
return (val & CFGCHIP2_USB2PHYCLKMUX) ? 1 : 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops da8xx_usb0_clk48_ops = {
|
||||
.prepare = da8xx_usb0_clk48_prepare,
|
||||
.unprepare = da8xx_usb0_clk48_unprepare,
|
||||
.enable = da8xx_usb0_clk48_enable,
|
||||
.disable = da8xx_usb0_clk48_disable,
|
||||
.is_enabled = da8xx_usb0_clk48_is_enabled,
|
||||
.recalc_rate = da8xx_usb0_clk48_recalc_rate,
|
||||
.round_rate = da8xx_usb0_clk48_round_rate,
|
||||
.set_parent = da8xx_usb0_clk48_set_parent,
|
||||
.get_parent = da8xx_usb0_clk48_get_parent,
|
||||
};
|
||||
|
||||
static struct da8xx_usb0_clk48 *
|
||||
da8xx_cfgchip_register_usb0_clk48(struct device *dev,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
const char * const parent_names[] = { "usb_refclkin", "pll0_auxclk" };
|
||||
struct clk *fck_clk;
|
||||
struct da8xx_usb0_clk48 *usb0;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
fck_clk = devm_clk_get(dev, "fck");
|
||||
if (IS_ERR(fck_clk)) {
|
||||
if (PTR_ERR(fck_clk) != -EPROBE_DEFER)
|
||||
dev_err(dev, "Missing fck clock\n");
|
||||
return ERR_CAST(fck_clk);
|
||||
}
|
||||
|
||||
usb0 = devm_kzalloc(dev, sizeof(*usb0), GFP_KERNEL);
|
||||
if (!usb0)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = "usb0_clk48";
|
||||
init.ops = &da8xx_usb0_clk48_ops;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = 2;
|
||||
|
||||
usb0->hw.init = &init;
|
||||
usb0->fck = fck_clk;
|
||||
usb0->regmap = regmap;
|
||||
|
||||
ret = devm_clk_hw_register(dev, &usb0->hw);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return usb0;
|
||||
}
|
||||
|
||||
/* --- USB 1.1 PHY clock --- */
|
||||
|
||||
struct da8xx_usb1_clk48 {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
#define to_da8xx_usb1_clk48(_hw) \
|
||||
container_of((_hw), struct da8xx_usb1_clk48, hw)
|
||||
|
||||
static int da8xx_usb1_clk48_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct da8xx_usb1_clk48 *usb1 = to_da8xx_usb1_clk48(hw);
|
||||
|
||||
return regmap_write_bits(usb1->regmap, CFGCHIP(2),
|
||||
CFGCHIP2_USB1PHYCLKMUX,
|
||||
index ? CFGCHIP2_USB1PHYCLKMUX : 0);
|
||||
}
|
||||
|
||||
static u8 da8xx_usb1_clk48_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct da8xx_usb1_clk48 *usb1 = to_da8xx_usb1_clk48(hw);
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(usb1->regmap, CFGCHIP(2), &val);
|
||||
|
||||
return (val & CFGCHIP2_USB1PHYCLKMUX) ? 1 : 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops da8xx_usb1_clk48_ops = {
|
||||
.set_parent = da8xx_usb1_clk48_set_parent,
|
||||
.get_parent = da8xx_usb1_clk48_get_parent,
|
||||
};
|
||||
|
||||
/**
|
||||
* da8xx_cfgchip_register_usb1_clk48 - Register a new USB 1.1 PHY clock
|
||||
* @regmap: The CFGCHIP regmap
|
||||
*/
|
||||
static struct da8xx_usb1_clk48 *
|
||||
da8xx_cfgchip_register_usb1_clk48(struct device *dev,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
const char * const parent_names[] = { "usb0_clk48", "usb_refclkin" };
|
||||
struct da8xx_usb1_clk48 *usb1;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
usb1 = devm_kzalloc(dev, sizeof(*usb1), GFP_KERNEL);
|
||||
if (!usb1)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = "usb1_clk48";
|
||||
init.ops = &da8xx_usb1_clk48_ops;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = 2;
|
||||
|
||||
usb1->hw.init = &init;
|
||||
usb1->regmap = regmap;
|
||||
|
||||
ret = devm_clk_hw_register(dev, &usb1->hw);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return usb1;
|
||||
}
|
||||
|
||||
static int da8xx_cfgchip_register_usb_phy_clk(struct device *dev,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
struct da8xx_usb0_clk48 *usb0;
|
||||
struct da8xx_usb1_clk48 *usb1;
|
||||
struct clk_hw *parent;
|
||||
|
||||
usb0 = da8xx_cfgchip_register_usb0_clk48(dev, regmap);
|
||||
if (IS_ERR(usb0))
|
||||
return PTR_ERR(usb0);
|
||||
|
||||
/*
|
||||
* All existing boards use pll0_auxclk as the parent and new boards
|
||||
* should use device tree, so hard-coding the value (1) here.
|
||||
*/
|
||||
parent = clk_hw_get_parent_by_index(&usb0->hw, 1);
|
||||
if (parent)
|
||||
clk_set_parent(usb0->hw.clk, parent->clk);
|
||||
else
|
||||
dev_warn(dev, "Failed to find usb0 parent clock\n");
|
||||
|
||||
usb1 = da8xx_cfgchip_register_usb1_clk48(dev, regmap);
|
||||
if (IS_ERR(usb1))
|
||||
return PTR_ERR(usb1);
|
||||
|
||||
/*
|
||||
* All existing boards use usb0_clk48 as the parent and new boards
|
||||
* should use device tree, so hard-coding the value (0) here.
|
||||
*/
|
||||
parent = clk_hw_get_parent_by_index(&usb1->hw, 0);
|
||||
if (parent)
|
||||
clk_set_parent(usb1->hw.clk, parent->clk);
|
||||
else
|
||||
dev_warn(dev, "Failed to find usb1 parent clock\n");
|
||||
|
||||
clk_hw_register_clkdev(&usb0->hw, "usb0_clk48", "da8xx-usb-phy");
|
||||
clk_hw_register_clkdev(&usb1->hw, "usb1_clk48", "da8xx-usb-phy");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int of_da8xx_usb_phy_clk_init(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
struct da8xx_usb0_clk48 *usb0;
|
||||
struct da8xx_usb1_clk48 *usb1;
|
||||
|
||||
clk_data = devm_kzalloc(dev, sizeof(*clk_data) + 2 *
|
||||
sizeof(*clk_data->hws), GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
clk_data->num = 2;
|
||||
|
||||
usb0 = da8xx_cfgchip_register_usb0_clk48(dev, regmap);
|
||||
if (IS_ERR(usb0)) {
|
||||
if (PTR_ERR(usb0) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev_warn(dev, "Failed to register usb0_clk48 (%ld)\n",
|
||||
PTR_ERR(usb0));
|
||||
|
||||
clk_data->hws[0] = ERR_PTR(-ENOENT);
|
||||
} else {
|
||||
clk_data->hws[0] = &usb0->hw;
|
||||
}
|
||||
|
||||
usb1 = da8xx_cfgchip_register_usb1_clk48(dev, regmap);
|
||||
if (IS_ERR(usb1)) {
|
||||
if (PTR_ERR(usb0) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev_warn(dev, "Failed to register usb1_clk48 (%ld)\n",
|
||||
PTR_ERR(usb1));
|
||||
|
||||
clk_data->hws[1] = ERR_PTR(-ENOENT);
|
||||
} else {
|
||||
clk_data->hws[1] = &usb1->hw;
|
||||
}
|
||||
|
||||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
|
||||
}
|
||||
|
||||
/* --- platform device --- */
|
||||
|
||||
static const struct of_device_id da8xx_cfgchip_of_match[] = {
|
||||
{
|
||||
.compatible = "ti,da830-tbclksync",
|
||||
.data = of_da8xx_tbclksync_init,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,da830-div4p5ena",
|
||||
.data = of_da8xx_div4p5ena_init,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,da850-async1-clksrc",
|
||||
.data = of_da850_async1_init,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,da850-async3-clksrc",
|
||||
.data = of_da850_async3_init,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,da830-usb-phy-clocks",
|
||||
.data = of_da8xx_usb_phy_clk_init,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct platform_device_id da8xx_cfgchip_id_table[] = {
|
||||
{
|
||||
.name = "da830-tbclksync",
|
||||
.driver_data = (kernel_ulong_t)da8xx_cfgchip_register_tbclk,
|
||||
},
|
||||
{
|
||||
.name = "da830-div4p5ena",
|
||||
.driver_data = (kernel_ulong_t)da8xx_cfgchip_register_div4p5,
|
||||
},
|
||||
{
|
||||
.name = "da850-async1-clksrc",
|
||||
.driver_data = (kernel_ulong_t)da8xx_cfgchip_register_async1,
|
||||
},
|
||||
{
|
||||
.name = "da850-async3-clksrc",
|
||||
.driver_data = (kernel_ulong_t)da850_cfgchip_register_async3,
|
||||
},
|
||||
{
|
||||
.name = "da830-usb-phy-clks",
|
||||
.driver_data = (kernel_ulong_t)da8xx_cfgchip_register_usb_phy_clk,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
typedef int (*da8xx_cfgchip_init)(struct device *dev, struct regmap *regmap);
|
||||
|
||||
static int da8xx_cfgchip_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct da8xx_cfgchip_clk_platform_data *pdata = dev->platform_data;
|
||||
const struct of_device_id *of_id;
|
||||
da8xx_cfgchip_init clk_init = NULL;
|
||||
struct regmap *regmap = NULL;
|
||||
|
||||
of_id = of_match_device(da8xx_cfgchip_of_match, dev);
|
||||
if (of_id) {
|
||||
struct device_node *parent;
|
||||
|
||||
clk_init = of_id->data;
|
||||
parent = of_get_parent(dev->of_node);
|
||||
regmap = syscon_node_to_regmap(parent);
|
||||
of_node_put(parent);
|
||||
} else if (pdev->id_entry && pdata) {
|
||||
clk_init = (void *)pdev->id_entry->driver_data;
|
||||
regmap = pdata->cfgchip;
|
||||
}
|
||||
|
||||
if (!clk_init) {
|
||||
dev_err(dev, "unable to find driver data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(regmap)) {
|
||||
dev_err(dev, "no regmap for CFGCHIP syscon\n");
|
||||
return regmap ? PTR_ERR(regmap) : -ENOENT;
|
||||
}
|
||||
|
||||
return clk_init(dev, regmap);
|
||||
}
|
||||
|
||||
static struct platform_driver da8xx_cfgchip_driver = {
|
||||
.probe = da8xx_cfgchip_probe,
|
||||
.driver = {
|
||||
.name = "da8xx-cfgchip-clk",
|
||||
.of_match_table = da8xx_cfgchip_of_match,
|
||||
},
|
||||
.id_table = da8xx_cfgchip_id_table,
|
||||
};
|
||||
|
||||
static int __init da8xx_cfgchip_driver_init(void)
|
||||
{
|
||||
return platform_driver_register(&da8xx_cfgchip_driver);
|
||||
}
|
||||
|
||||
/* has to be postcore_initcall because PSC devices depend on the async3 clock */
|
||||
postcore_initcall(da8xx_cfgchip_driver_init);
|
|
@ -0,0 +1,70 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PLL clock descriptions for TI DA830/OMAP-L137/AM17XX
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "pll.h"
|
||||
|
||||
static const struct davinci_pll_clk_info da830_pll_info = {
|
||||
.name = "pll0",
|
||||
.pllm_mask = GENMASK(4, 0),
|
||||
.pllm_min = 4,
|
||||
.pllm_max = 32,
|
||||
.pllout_min_rate = 300000000,
|
||||
.pllout_max_rate = 600000000,
|
||||
.flags = PLL_HAS_CLKMODE | PLL_HAS_PREDIV | PLL_HAS_POSTDIV,
|
||||
};
|
||||
|
||||
/*
|
||||
* NB: Technically, the clocks flagged as SYSCLK_FIXED_DIV are "fixed ratio",
|
||||
* meaning that we could change the divider as long as we keep the correct
|
||||
* ratio between all of the clocks, but we don't support that because there is
|
||||
* currently not a need for it.
|
||||
*/
|
||||
|
||||
SYSCLK(2, pll0_sysclk2, pll0_pllen, 5, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(3, pll0_sysclk3, pll0_pllen, 5, 0);
|
||||
SYSCLK(4, pll0_sysclk4, pll0_pllen, 5, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(5, pll0_sysclk5, pll0_pllen, 5, 0);
|
||||
SYSCLK(6, pll0_sysclk6, pll0_pllen, 5, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(7, pll0_sysclk7, pll0_pllen, 5, 0);
|
||||
|
||||
int da830_pll_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &da830_pll_info, "ref_clk", base);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk2, base);
|
||||
clk_register_clkdev(clk, "pll0_sysclk2", "da830-psc0");
|
||||
clk_register_clkdev(clk, "pll0_sysclk2", "da830-psc1");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk3, base);
|
||||
clk_register_clkdev(clk, "pll0_sysclk3", "da830-psc0");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk4, base);
|
||||
clk_register_clkdev(clk, "pll0_sysclk4", "da830-psc0");
|
||||
clk_register_clkdev(clk, "pll0_sysclk4", "da830-psc1");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk5, base);
|
||||
clk_register_clkdev(clk, "pll0_sysclk5", "da830-psc1");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk6, base);
|
||||
clk_register_clkdev(clk, "pll0_sysclk6", "da830-psc0");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk7, base);
|
||||
|
||||
clk = davinci_pll_auxclk_register(dev, "pll0_auxclk", base);
|
||||
clk_register_clkdev(clk, NULL, "i2c_davinci.1");
|
||||
clk_register_clkdev(clk, "timer0", NULL);
|
||||
clk_register_clkdev(clk, NULL, "davinci-wdt");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PLL clock descriptions for TI DA850/OMAP-L138/AM18XX
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/da8xx-cfgchip.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "pll.h"
|
||||
|
||||
#define OCSEL_OCSRC_OSCIN 0x14
|
||||
#define OCSEL_OCSRC_PLL0_SYSCLK(n) (0x16 + (n))
|
||||
#define OCSEL_OCSRC_PLL1_OBSCLK 0x1e
|
||||
#define OCSEL_OCSRC_PLL1_SYSCLK(n) (0x16 + (n))
|
||||
|
||||
static const struct davinci_pll_clk_info da850_pll0_info = {
|
||||
.name = "pll0",
|
||||
.unlock_reg = CFGCHIP(0),
|
||||
.unlock_mask = CFGCHIP0_PLL_MASTER_LOCK,
|
||||
.pllm_mask = GENMASK(4, 0),
|
||||
.pllm_min = 4,
|
||||
.pllm_max = 32,
|
||||
.pllout_min_rate = 300000000,
|
||||
.pllout_max_rate = 600000000,
|
||||
.flags = PLL_HAS_CLKMODE | PLL_HAS_PREDIV | PLL_HAS_POSTDIV |
|
||||
PLL_HAS_EXTCLKSRC,
|
||||
};
|
||||
|
||||
/*
|
||||
* NB: Technically, the clocks flagged as SYSCLK_FIXED_DIV are "fixed ratio",
|
||||
* meaning that we could change the divider as long as we keep the correct
|
||||
* ratio between all of the clocks, but we don't support that because there is
|
||||
* currently not a need for it.
|
||||
*/
|
||||
|
||||
SYSCLK(1, pll0_sysclk1, pll0_pllen, 5, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(2, pll0_sysclk2, pll0_pllen, 5, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(3, pll0_sysclk3, pll0_pllen, 5, 0);
|
||||
SYSCLK(4, pll0_sysclk4, pll0_pllen, 5, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(5, pll0_sysclk5, pll0_pllen, 5, 0);
|
||||
SYSCLK(6, pll0_sysclk6, pll0_pllen, 5, SYSCLK_ARM_RATE | SYSCLK_FIXED_DIV);
|
||||
SYSCLK(7, pll0_sysclk7, pll0_pllen, 5, 0);
|
||||
|
||||
static const char * const da850_pll0_obsclk_parent_names[] = {
|
||||
"oscin",
|
||||
"pll0_sysclk1",
|
||||
"pll0_sysclk2",
|
||||
"pll0_sysclk3",
|
||||
"pll0_sysclk4",
|
||||
"pll0_sysclk5",
|
||||
"pll0_sysclk6",
|
||||
"pll0_sysclk7",
|
||||
"pll1_obsclk",
|
||||
};
|
||||
|
||||
static u32 da850_pll0_obsclk_table[] = {
|
||||
OCSEL_OCSRC_OSCIN,
|
||||
OCSEL_OCSRC_PLL0_SYSCLK(1),
|
||||
OCSEL_OCSRC_PLL0_SYSCLK(2),
|
||||
OCSEL_OCSRC_PLL0_SYSCLK(3),
|
||||
OCSEL_OCSRC_PLL0_SYSCLK(4),
|
||||
OCSEL_OCSRC_PLL0_SYSCLK(5),
|
||||
OCSEL_OCSRC_PLL0_SYSCLK(6),
|
||||
OCSEL_OCSRC_PLL0_SYSCLK(7),
|
||||
OCSEL_OCSRC_PLL1_OBSCLK,
|
||||
};
|
||||
|
||||
static const struct davinci_pll_obsclk_info da850_pll0_obsclk_info = {
|
||||
.name = "pll0_obsclk",
|
||||
.parent_names = da850_pll0_obsclk_parent_names,
|
||||
.num_parents = ARRAY_SIZE(da850_pll0_obsclk_parent_names),
|
||||
.table = da850_pll0_obsclk_table,
|
||||
.ocsrc_mask = GENMASK(4, 0),
|
||||
};
|
||||
|
||||
int da850_pll0_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &da850_pll0_info, "ref_clk", base);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk1, base);
|
||||
clk_register_clkdev(clk, "pll0_sysclk1", "da850-psc0");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk2, base);
|
||||
clk_register_clkdev(clk, "pll0_sysclk2", "da850-psc0");
|
||||
clk_register_clkdev(clk, "pll0_sysclk2", "da850-psc1");
|
||||
clk_register_clkdev(clk, "pll0_sysclk2", "da850-async3-clksrc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk3, base);
|
||||
clk_register_clkdev(clk, "pll0_sysclk3", "da850-async1-clksrc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk4, base);
|
||||
clk_register_clkdev(clk, "pll0_sysclk4", "da850-psc0");
|
||||
clk_register_clkdev(clk, "pll0_sysclk4", "da850-psc1");
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll0_sysclk5, base);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk6, base);
|
||||
clk_register_clkdev(clk, "pll0_sysclk6", "da850-psc0");
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll0_sysclk7, base);
|
||||
|
||||
davinci_pll_auxclk_register(dev, "pll0_auxclk", base);
|
||||
|
||||
clk = clk_register_fixed_factor(dev, "async2", "pll0_auxclk",
|
||||
CLK_IS_CRITICAL, 1, 1);
|
||||
|
||||
clk_register_clkdev(clk, NULL, "i2c_davinci.1");
|
||||
clk_register_clkdev(clk, "timer0", NULL);
|
||||
clk_register_clkdev(clk, NULL, "davinci-wdt");
|
||||
|
||||
davinci_pll_obsclk_register(dev, &da850_pll0_obsclk_info, base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct davinci_pll_sysclk_info *da850_pll0_sysclk_info[] = {
|
||||
&pll0_sysclk1,
|
||||
&pll0_sysclk2,
|
||||
&pll0_sysclk3,
|
||||
&pll0_sysclk4,
|
||||
&pll0_sysclk5,
|
||||
&pll0_sysclk6,
|
||||
&pll0_sysclk7,
|
||||
NULL
|
||||
};
|
||||
|
||||
int of_da850_pll0_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return of_davinci_pll_init(dev, &da850_pll0_info,
|
||||
&da850_pll0_obsclk_info,
|
||||
da850_pll0_sysclk_info, 7, base);
|
||||
}
|
||||
|
||||
static const struct davinci_pll_clk_info da850_pll1_info = {
|
||||
.name = "pll1",
|
||||
.unlock_reg = CFGCHIP(3),
|
||||
.unlock_mask = CFGCHIP3_PLL1_MASTER_LOCK,
|
||||
.pllm_mask = GENMASK(4, 0),
|
||||
.pllm_min = 4,
|
||||
.pllm_max = 32,
|
||||
.pllout_min_rate = 300000000,
|
||||
.pllout_max_rate = 600000000,
|
||||
.flags = PLL_HAS_POSTDIV,
|
||||
};
|
||||
|
||||
SYSCLK(1, pll1_sysclk1, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(2, pll1_sysclk2, pll1_pllen, 5, 0);
|
||||
SYSCLK(3, pll1_sysclk3, pll1_pllen, 5, 0);
|
||||
|
||||
static const char * const da850_pll1_obsclk_parent_names[] = {
|
||||
"oscin",
|
||||
"pll1_sysclk1",
|
||||
"pll1_sysclk2",
|
||||
"pll1_sysclk3",
|
||||
};
|
||||
|
||||
static u32 da850_pll1_obsclk_table[] = {
|
||||
OCSEL_OCSRC_OSCIN,
|
||||
OCSEL_OCSRC_PLL1_SYSCLK(1),
|
||||
OCSEL_OCSRC_PLL1_SYSCLK(2),
|
||||
OCSEL_OCSRC_PLL1_SYSCLK(3),
|
||||
};
|
||||
|
||||
static const struct davinci_pll_obsclk_info da850_pll1_obsclk_info = {
|
||||
.name = "pll1_obsclk",
|
||||
.parent_names = da850_pll1_obsclk_parent_names,
|
||||
.num_parents = ARRAY_SIZE(da850_pll1_obsclk_parent_names),
|
||||
.table = da850_pll1_obsclk_table,
|
||||
.ocsrc_mask = GENMASK(4, 0),
|
||||
};
|
||||
|
||||
int da850_pll1_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &da850_pll1_info, "oscin", base);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk2, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk2", "da850-async3-clksrc");
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll1_sysclk3, base);
|
||||
|
||||
davinci_pll_obsclk_register(dev, &da850_pll1_obsclk_info, base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct davinci_pll_sysclk_info *da850_pll1_sysclk_info[] = {
|
||||
&pll1_sysclk1,
|
||||
&pll1_sysclk2,
|
||||
&pll1_sysclk3,
|
||||
NULL
|
||||
};
|
||||
|
||||
int of_da850_pll1_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return of_davinci_pll_init(dev, &da850_pll1_info,
|
||||
&da850_pll1_obsclk_info,
|
||||
da850_pll1_sysclk_info, 3, base);
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PLL clock descriptions for TI DM355
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "pll.h"
|
||||
|
||||
static const struct davinci_pll_clk_info dm355_pll1_info = {
|
||||
.name = "pll1",
|
||||
.pllm_mask = GENMASK(7, 0),
|
||||
.pllm_min = 92,
|
||||
.pllm_max = 184,
|
||||
.flags = PLL_HAS_CLKMODE | PLL_HAS_PREDIV | PLL_PREDIV_ALWAYS_ENABLED |
|
||||
PLL_PREDIV_FIXED8 | PLL_HAS_POSTDIV |
|
||||
PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
|
||||
};
|
||||
|
||||
SYSCLK(1, pll1_sysclk1, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(2, pll1_sysclk2, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(3, pll1_sysclk3, pll1, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(4, pll1_sysclk4, pll1, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
|
||||
int dm355_pll1_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &dm355_pll1_info, "ref_clk", base);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk1", "dm355-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk2, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk2", "dm355-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk3, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk3", "dm355-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk4, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk4", "dm355-psc");
|
||||
|
||||
clk = davinci_pll_auxclk_register(dev, "pll1_auxclk", base);
|
||||
clk_register_clkdev(clk, "pll1_auxclk", "dm355-psc");
|
||||
|
||||
davinci_pll_sysclkbp_clk_register(dev, "pll1_sysclkbp", base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct davinci_pll_clk_info dm355_pll2_info = {
|
||||
.name = "pll2",
|
||||
.pllm_mask = GENMASK(7, 0),
|
||||
.pllm_min = 92,
|
||||
.pllm_max = 184,
|
||||
.flags = PLL_HAS_PREDIV | PLL_PREDIV_ALWAYS_ENABLED | PLL_HAS_POSTDIV |
|
||||
PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
|
||||
};
|
||||
|
||||
SYSCLK(1, pll2_sysclk1, pll2, 5, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(2, pll2_sysclk2, pll2, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
|
||||
|
||||
int dm355_pll2_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
davinci_pll_clk_register(dev, &dm355_pll2_info, "oscin", base);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk1, base);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk2, base);
|
||||
|
||||
davinci_pll_sysclkbp_clk_register(dev, "pll2_sysclkbp", base);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PLL clock descriptions for TI DM365
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "pll.h"
|
||||
|
||||
#define OCSEL_OCSRC_ENABLE 0
|
||||
|
||||
static const struct davinci_pll_clk_info dm365_pll1_info = {
|
||||
.name = "pll1",
|
||||
.pllm_mask = GENMASK(9, 0),
|
||||
.pllm_min = 1,
|
||||
.pllm_max = 1023,
|
||||
.flags = PLL_HAS_CLKMODE | PLL_HAS_PREDIV | PLL_HAS_POSTDIV |
|
||||
PLL_POSTDIV_ALWAYS_ENABLED | PLL_PLLM_2X,
|
||||
};
|
||||
|
||||
SYSCLK(1, pll1_sysclk1, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(2, pll1_sysclk2, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(3, pll1_sysclk3, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(4, pll1_sysclk4, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(5, pll1_sysclk5, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(6, pll1_sysclk6, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(7, pll1_sysclk7, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(8, pll1_sysclk8, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(9, pll1_sysclk9, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
|
||||
/*
|
||||
* This is a bit of a hack to make OCSEL[OCSRC] on DM365 look like OCSEL[OCSRC]
|
||||
* on DA850. On DM365, OCSEL[OCSRC] is just an enable/disable bit instead of a
|
||||
* multiplexer. By modeling it as a single parent mux clock, the clock code will
|
||||
* still do the right thing in this case.
|
||||
*/
|
||||
static const char * const dm365_pll_obsclk_parent_names[] = {
|
||||
"oscin",
|
||||
};
|
||||
|
||||
static u32 dm365_pll_obsclk_table[] = {
|
||||
OCSEL_OCSRC_ENABLE,
|
||||
};
|
||||
|
||||
static const struct davinci_pll_obsclk_info dm365_pll1_obsclk_info = {
|
||||
.name = "pll1_obsclk",
|
||||
.parent_names = dm365_pll_obsclk_parent_names,
|
||||
.num_parents = ARRAY_SIZE(dm365_pll_obsclk_parent_names),
|
||||
.table = dm365_pll_obsclk_table,
|
||||
.ocsrc_mask = BIT(4),
|
||||
};
|
||||
|
||||
int dm365_pll1_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &dm365_pll1_info, "ref_clk", base);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk1", "dm365-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk2, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk2", "dm365-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk3, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk3", "dm365-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk4, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk4", "dm365-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk5, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk5", "dm365-psc");
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll1_sysclk6, base);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll1_sysclk7, base);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk8, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk8", "dm365-psc");
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll1_sysclk9, base);
|
||||
|
||||
clk = davinci_pll_auxclk_register(dev, "pll1_auxclk", base);
|
||||
clk_register_clkdev(clk, "pll1_auxclk", "dm355-psc");
|
||||
|
||||
davinci_pll_sysclkbp_clk_register(dev, "pll1_sysclkbp", base);
|
||||
|
||||
davinci_pll_obsclk_register(dev, &dm365_pll1_obsclk_info, base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct davinci_pll_clk_info dm365_pll2_info = {
|
||||
.name = "pll2",
|
||||
.pllm_mask = GENMASK(9, 0),
|
||||
.pllm_min = 1,
|
||||
.pllm_max = 1023,
|
||||
.flags = PLL_HAS_PREDIV | PLL_HAS_POSTDIV | PLL_POSTDIV_ALWAYS_ENABLED |
|
||||
PLL_PLLM_2X,
|
||||
};
|
||||
|
||||
SYSCLK(1, pll2_sysclk1, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(2, pll2_sysclk2, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(3, pll2_sysclk3, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(4, pll2_sysclk4, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(5, pll2_sysclk5, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
|
||||
static const struct davinci_pll_obsclk_info dm365_pll2_obsclk_info = {
|
||||
.name = "pll2_obsclk",
|
||||
.parent_names = dm365_pll_obsclk_parent_names,
|
||||
.num_parents = ARRAY_SIZE(dm365_pll_obsclk_parent_names),
|
||||
.table = dm365_pll_obsclk_table,
|
||||
.ocsrc_mask = BIT(4),
|
||||
};
|
||||
|
||||
int dm365_pll2_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &dm365_pll2_info, "oscin", base);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk1, base);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll2_sysclk2, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk2", "dm365-psc");
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk3, base);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll2_sysclk4, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk4", "dm365-psc");
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk5, base);
|
||||
|
||||
davinci_pll_auxclk_register(dev, "pll2_auxclk", base);
|
||||
|
||||
davinci_pll_obsclk_register(dev, &dm365_pll2_obsclk_info, base);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PLL clock descriptions for TI DM644X
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "pll.h"
|
||||
|
||||
static const struct davinci_pll_clk_info dm644x_pll1_info = {
|
||||
.name = "pll1",
|
||||
.pllm_mask = GENMASK(4, 0),
|
||||
.pllm_min = 1,
|
||||
.pllm_max = 32,
|
||||
.pllout_min_rate = 400000000,
|
||||
.pllout_max_rate = 600000000, /* 810MHz @ 1.3V, -810 only */
|
||||
.flags = PLL_HAS_CLKMODE | PLL_HAS_POSTDIV,
|
||||
};
|
||||
|
||||
SYSCLK(1, pll1_sysclk1, pll1_pllen, 4, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(2, pll1_sysclk2, pll1_pllen, 4, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(3, pll1_sysclk3, pll1_pllen, 4, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(5, pll1_sysclk5, pll1_pllen, 4, SYSCLK_FIXED_DIV);
|
||||
|
||||
int dm644x_pll1_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &dm644x_pll1_info, "ref_clk", base);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk1", "dm644x-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk2, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk2", "dm644x-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk3, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk3", "dm644x-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk5, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk5", "dm644x-psc");
|
||||
|
||||
clk = davinci_pll_auxclk_register(dev, "pll1_auxclk", base);
|
||||
clk_register_clkdev(clk, "pll1_auxclk", "dm644x-psc");
|
||||
|
||||
davinci_pll_sysclkbp_clk_register(dev, "pll1_sysclkbp", base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct davinci_pll_clk_info dm644x_pll2_info = {
|
||||
.name = "pll2",
|
||||
.pllm_mask = GENMASK(4, 0),
|
||||
.pllm_min = 1,
|
||||
.pllm_max = 32,
|
||||
.pllout_min_rate = 400000000,
|
||||
.pllout_max_rate = 900000000,
|
||||
.flags = PLL_HAS_POSTDIV | PLL_POSTDIV_FIXED_DIV,
|
||||
};
|
||||
|
||||
SYSCLK(1, pll2_sysclk1, pll2_pllen, 4, 0);
|
||||
SYSCLK(2, pll2_sysclk2, pll2_pllen, 4, 0);
|
||||
|
||||
int dm644x_pll2_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
davinci_pll_clk_register(dev, &dm644x_pll2_info, "oscin", base);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk1, base);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk2, base);
|
||||
|
||||
davinci_pll_sysclkbp_clk_register(dev, "pll2_sysclkbp", base);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PLL clock descriptions for TI DM646X
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "pll.h"
|
||||
|
||||
static const struct davinci_pll_clk_info dm646x_pll1_info = {
|
||||
.name = "pll1",
|
||||
.pllm_mask = GENMASK(4, 0),
|
||||
.pllm_min = 14,
|
||||
.pllm_max = 32,
|
||||
.flags = PLL_HAS_CLKMODE,
|
||||
};
|
||||
|
||||
SYSCLK(1, pll1_sysclk1, pll1_pllen, 4, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(2, pll1_sysclk2, pll1_pllen, 4, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(3, pll1_sysclk3, pll1_pllen, 4, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(4, pll1_sysclk4, pll1_pllen, 4, 0);
|
||||
SYSCLK(5, pll1_sysclk5, pll1_pllen, 4, 0);
|
||||
SYSCLK(6, pll1_sysclk6, pll1_pllen, 4, 0);
|
||||
SYSCLK(8, pll1_sysclk8, pll1_pllen, 4, 0);
|
||||
SYSCLK(9, pll1_sysclk9, pll1_pllen, 4, 0);
|
||||
|
||||
int dm646x_pll1_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &dm646x_pll1_info, "ref_clk", base);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk1", "dm646x-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk2, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk2", "dm646x-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk3, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk3", "dm646x-psc");
|
||||
clk_register_clkdev(clk, NULL, "davinci-wdt");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk4, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk4", "dm646x-psc");
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk5, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk5", "dm646x-psc");
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll1_sysclk6, base);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll1_sysclk8, base);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll1_sysclk9, base);
|
||||
|
||||
davinci_pll_sysclkbp_clk_register(dev, "pll1_sysclkbp", base);
|
||||
|
||||
davinci_pll_auxclk_register(dev, "pll1_auxclk", base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct davinci_pll_clk_info dm646x_pll2_info = {
|
||||
.name = "pll2",
|
||||
.pllm_mask = GENMASK(4, 0),
|
||||
.pllm_min = 14,
|
||||
.pllm_max = 32,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
SYSCLK(1, pll2_sysclk1, pll2_pllen, 4, 0);
|
||||
|
||||
int dm646x_pll2_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
davinci_pll_clk_register(dev, &dm646x_pll2_info, "oscin", base);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk1, base);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,899 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PLL clock driver for TI Davinci SoCs
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*
|
||||
* Based on arch/arm/mach-davinci/clock.c
|
||||
* Copyright (C) 2006-2007 Texas Instruments.
|
||||
* Copyright (C) 2008-2009 Deep Root Systems, LLC
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/clk-davinci-pll.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "pll.h"
|
||||
|
||||
#define MAX_NAME_SIZE 20
|
||||
#define OSCIN_CLK_NAME "oscin"
|
||||
|
||||
#define REVID 0x000
|
||||
#define PLLCTL 0x100
|
||||
#define OCSEL 0x104
|
||||
#define PLLSECCTL 0x108
|
||||
#define PLLM 0x110
|
||||
#define PREDIV 0x114
|
||||
#define PLLDIV1 0x118
|
||||
#define PLLDIV2 0x11c
|
||||
#define PLLDIV3 0x120
|
||||
#define OSCDIV 0x124
|
||||
#define POSTDIV 0x128
|
||||
#define BPDIV 0x12c
|
||||
#define PLLCMD 0x138
|
||||
#define PLLSTAT 0x13c
|
||||
#define ALNCTL 0x140
|
||||
#define DCHANGE 0x144
|
||||
#define CKEN 0x148
|
||||
#define CKSTAT 0x14c
|
||||
#define SYSTAT 0x150
|
||||
#define PLLDIV4 0x160
|
||||
#define PLLDIV5 0x164
|
||||
#define PLLDIV6 0x168
|
||||
#define PLLDIV7 0x16c
|
||||
#define PLLDIV8 0x170
|
||||
#define PLLDIV9 0x174
|
||||
|
||||
#define PLLCTL_PLLEN BIT(0)
|
||||
#define PLLCTL_PLLPWRDN BIT(1)
|
||||
#define PLLCTL_PLLRST BIT(3)
|
||||
#define PLLCTL_PLLDIS BIT(4)
|
||||
#define PLLCTL_PLLENSRC BIT(5)
|
||||
#define PLLCTL_CLKMODE BIT(8)
|
||||
|
||||
/* shared by most *DIV registers */
|
||||
#define DIV_RATIO_SHIFT 0
|
||||
#define DIV_RATIO_WIDTH 5
|
||||
#define DIV_ENABLE_SHIFT 15
|
||||
|
||||
#define PLLCMD_GOSET BIT(0)
|
||||
#define PLLSTAT_GOSTAT BIT(0)
|
||||
|
||||
#define CKEN_OBSCLK_SHIFT 1
|
||||
#define CKEN_AUXEN_SHIFT 0
|
||||
|
||||
/*
|
||||
* OMAP-L138 system reference guide recommends a wait for 4 OSCIN/CLKIN
|
||||
* cycles to ensure that the PLLC has switched to bypass mode. Delay of 1us
|
||||
* ensures we are good for all > 4MHz OSCIN/CLKIN inputs. Typically the input
|
||||
* is ~25MHz. Units are micro seconds.
|
||||
*/
|
||||
#define PLL_BYPASS_TIME 1
|
||||
|
||||
/* From OMAP-L138 datasheet table 6-4. Units are micro seconds */
|
||||
#define PLL_RESET_TIME 1
|
||||
|
||||
/*
|
||||
* From OMAP-L138 datasheet table 6-4; assuming prediv = 1, sqrt(pllm) = 4
|
||||
* Units are micro seconds.
|
||||
*/
|
||||
#define PLL_LOCK_TIME 20
|
||||
|
||||
/**
|
||||
* struct davinci_pll_clk - Main PLL clock (aka PLLOUT)
|
||||
* @hw: clk_hw for the pll
|
||||
* @base: Base memory address
|
||||
* @pllm_min: The minimum allowable PLLM[PLLM] value
|
||||
* @pllm_max: The maxiumum allowable PLLM[PLLM] value
|
||||
* @pllm_mask: Bitmask for PLLM[PLLM] value
|
||||
*/
|
||||
struct davinci_pll_clk {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
u32 pllm_min;
|
||||
u32 pllm_max;
|
||||
u32 pllm_mask;
|
||||
};
|
||||
|
||||
#define to_davinci_pll_clk(_hw) \
|
||||
container_of((_hw), struct davinci_pll_clk, hw)
|
||||
|
||||
static unsigned long davinci_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct davinci_pll_clk *pll = to_davinci_pll_clk(hw);
|
||||
unsigned long rate = parent_rate;
|
||||
u32 mult;
|
||||
|
||||
mult = readl(pll->base + PLLM) & pll->pllm_mask;
|
||||
rate *= mult + 1;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int davinci_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct davinci_pll_clk *pll = to_davinci_pll_clk(hw);
|
||||
struct clk_hw *parent = req->best_parent_hw;
|
||||
unsigned long parent_rate = req->best_parent_rate;
|
||||
unsigned long rate = req->rate;
|
||||
unsigned long best_rate, r;
|
||||
u32 mult;
|
||||
|
||||
/* there is a limited range of valid outputs (see datasheet) */
|
||||
if (rate < req->min_rate)
|
||||
return -EINVAL;
|
||||
|
||||
rate = min(rate, req->max_rate);
|
||||
mult = rate / parent_rate;
|
||||
best_rate = parent_rate * mult;
|
||||
|
||||
/* easy case when there is no PREDIV */
|
||||
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
|
||||
if (best_rate < req->min_rate)
|
||||
return -EINVAL;
|
||||
|
||||
if (mult < pll->pllm_min || mult > pll->pllm_max)
|
||||
return -EINVAL;
|
||||
|
||||
req->rate = best_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* see if the PREDIV clock can help us */
|
||||
best_rate = 0;
|
||||
|
||||
for (mult = pll->pllm_min; mult <= pll->pllm_max; mult++) {
|
||||
parent_rate = clk_hw_round_rate(parent, rate / mult);
|
||||
r = parent_rate * mult;
|
||||
if (r < req->min_rate)
|
||||
continue;
|
||||
if (r > rate || r > req->max_rate)
|
||||
break;
|
||||
if (r > best_rate) {
|
||||
best_rate = r;
|
||||
req->rate = best_rate;
|
||||
req->best_parent_rate = parent_rate;
|
||||
if (best_rate == rate)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct davinci_pll_clk *pll = to_davinci_pll_clk(hw);
|
||||
u32 mult;
|
||||
|
||||
mult = rate / parent_rate;
|
||||
writel(mult - 1, pll->base + PLLM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static int davinci_pll_debug_init(struct clk_hw *hw, struct dentry *dentry);
|
||||
#else
|
||||
#define davinci_pll_debug_init NULL
|
||||
#endif
|
||||
|
||||
static const struct clk_ops davinci_pll_ops = {
|
||||
.recalc_rate = davinci_pll_recalc_rate,
|
||||
.determine_rate = davinci_pll_determine_rate,
|
||||
.set_rate = davinci_pll_set_rate,
|
||||
.debug_init = davinci_pll_debug_init,
|
||||
};
|
||||
|
||||
/* PLLM works differently on DM365 */
|
||||
static unsigned long dm365_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct davinci_pll_clk *pll = to_davinci_pll_clk(hw);
|
||||
unsigned long rate = parent_rate;
|
||||
u32 mult;
|
||||
|
||||
mult = readl(pll->base + PLLM) & pll->pllm_mask;
|
||||
rate *= mult * 2;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static const struct clk_ops dm365_pll_ops = {
|
||||
.recalc_rate = dm365_pll_recalc_rate,
|
||||
.debug_init = davinci_pll_debug_init,
|
||||
};
|
||||
|
||||
/**
|
||||
* davinci_pll_div_register - common *DIV clock implementation
|
||||
* @name: the clock name
|
||||
* @parent_name: the parent clock name
|
||||
* @reg: the *DIV register
|
||||
* @fixed: if true, the divider is a fixed value
|
||||
* @flags: bitmap of CLK_* flags from clock-provider.h
|
||||
*/
|
||||
static struct clk *davinci_pll_div_register(struct device *dev,
|
||||
const char *name,
|
||||
const char *parent_name,
|
||||
void __iomem *reg,
|
||||
bool fixed, u32 flags)
|
||||
{
|
||||
const char * const *parent_names = parent_name ? &parent_name : NULL;
|
||||
int num_parents = parent_name ? 1 : 0;
|
||||
const struct clk_ops *divider_ops = &clk_divider_ops;
|
||||
struct clk_gate *gate;
|
||||
struct clk_divider *divider;
|
||||
|
||||
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
gate->reg = reg;
|
||||
gate->bit_idx = DIV_ENABLE_SHIFT;
|
||||
|
||||
divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL);
|
||||
if (!divider)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
divider->reg = reg;
|
||||
divider->shift = DIV_RATIO_SHIFT;
|
||||
divider->width = DIV_RATIO_WIDTH;
|
||||
|
||||
if (fixed) {
|
||||
divider->flags |= CLK_DIVIDER_READ_ONLY;
|
||||
divider_ops = &clk_divider_ro_ops;
|
||||
}
|
||||
|
||||
return clk_register_composite(dev, name, parent_names, num_parents,
|
||||
NULL, NULL, ÷r->hw, divider_ops,
|
||||
&gate->hw, &clk_gate_ops, flags);
|
||||
}
|
||||
|
||||
struct davinci_pllen_clk {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
#define to_davinci_pllen_clk(_hw) \
|
||||
container_of((_hw), struct davinci_pllen_clk, hw)
|
||||
|
||||
static const struct clk_ops davinci_pllen_ops = {
|
||||
/* this clocks just uses the clock notification feature */
|
||||
};
|
||||
|
||||
/*
|
||||
* The PLL has to be switched into bypass mode while we are chaning the rate,
|
||||
* so we do that on the PLLEN clock since it is the end of the line. This will
|
||||
* switch to bypass before any of the parent clocks (PREDIV, PLL, POSTDIV) are
|
||||
* changed and will switch back to the PLL after the changes have been made.
|
||||
*/
|
||||
static int davinci_pllen_rate_change(struct notifier_block *nb,
|
||||
unsigned long flags, void *data)
|
||||
{
|
||||
struct clk_notifier_data *cnd = data;
|
||||
struct clk_hw *hw = __clk_get_hw(cnd->clk);
|
||||
struct davinci_pllen_clk *pll = to_davinci_pllen_clk(hw);
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = readl(pll->base + PLLCTL);
|
||||
|
||||
if (flags == PRE_RATE_CHANGE) {
|
||||
/* Switch the PLL to bypass mode */
|
||||
ctrl &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN);
|
||||
writel(ctrl, pll->base + PLLCTL);
|
||||
|
||||
udelay(PLL_BYPASS_TIME);
|
||||
|
||||
/* Reset and enable PLL */
|
||||
ctrl &= ~(PLLCTL_PLLRST | PLLCTL_PLLDIS);
|
||||
writel(ctrl, pll->base + PLLCTL);
|
||||
} else {
|
||||
udelay(PLL_RESET_TIME);
|
||||
|
||||
/* Bring PLL out of reset */
|
||||
ctrl |= PLLCTL_PLLRST;
|
||||
writel(ctrl, pll->base + PLLCTL);
|
||||
|
||||
udelay(PLL_LOCK_TIME);
|
||||
|
||||
/* Remove PLL from bypass mode */
|
||||
ctrl |= PLLCTL_PLLEN;
|
||||
writel(ctrl, pll->base + PLLCTL);
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct davinci_pll_platform_data *davinci_pll_get_pdata(struct device *dev)
|
||||
{
|
||||
struct davinci_pll_platform_data *pdata = dev_get_platdata(dev);
|
||||
|
||||
/*
|
||||
* Platform data is optional, so allocate a new struct if one was not
|
||||
* provided. For device tree, this will always be the case.
|
||||
*/
|
||||
if (!pdata)
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return NULL;
|
||||
|
||||
/* for device tree, we need to fill in the struct */
|
||||
if (dev->of_node)
|
||||
pdata->cfgchip =
|
||||
syscon_regmap_lookup_by_compatible("ti,da830-cfgchip");
|
||||
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static struct notifier_block davinci_pllen_notifier = {
|
||||
.notifier_call = davinci_pllen_rate_change,
|
||||
};
|
||||
|
||||
/**
|
||||
* davinci_pll_clk_register - Register a PLL clock
|
||||
* @info: The device-specific clock info
|
||||
* @parent_name: The parent clock name
|
||||
* @base: The PLL's memory region
|
||||
*
|
||||
* This creates a series of clocks that represent the PLL.
|
||||
*
|
||||
* OSCIN > [PREDIV >] PLL > [POSTDIV >] PLLEN
|
||||
*
|
||||
* - OSCIN is the parent clock (on secondary PLL, may come from primary PLL)
|
||||
* - PREDIV and POSTDIV are optional (depends on the PLL controller)
|
||||
* - PLL is the PLL output (aka PLLOUT)
|
||||
* - PLLEN is the bypass multiplexer
|
||||
*
|
||||
* Returns: The PLLOUT clock or a negative error code.
|
||||
*/
|
||||
struct clk *davinci_pll_clk_register(struct device *dev,
|
||||
const struct davinci_pll_clk_info *info,
|
||||
const char *parent_name,
|
||||
void __iomem *base)
|
||||
{
|
||||
struct davinci_pll_platform_data *pdata;
|
||||
char prediv_name[MAX_NAME_SIZE];
|
||||
char pllout_name[MAX_NAME_SIZE];
|
||||
char postdiv_name[MAX_NAME_SIZE];
|
||||
char pllen_name[MAX_NAME_SIZE];
|
||||
struct clk_init_data init;
|
||||
struct davinci_pll_clk *pllout;
|
||||
struct davinci_pllen_clk *pllen;
|
||||
struct clk *pllout_clk, *clk;
|
||||
|
||||
pdata = davinci_pll_get_pdata(dev);
|
||||
if (!pdata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (info->flags & PLL_HAS_CLKMODE) {
|
||||
/*
|
||||
* If a PLL has PLLCTL[CLKMODE], then it is the primary PLL.
|
||||
* We register a clock named "oscin" that serves as the internal
|
||||
* "input clock" domain shared by both PLLs (if there are 2)
|
||||
* and will be the parent clock to the AUXCLK, SYSCLKBP and
|
||||
* OBSCLK domains. NB: The various TRMs use "OSCIN" to mean
|
||||
* a number of different things. In this driver we use it to
|
||||
* mean the signal after the PLLCTL[CLKMODE] switch.
|
||||
*/
|
||||
clk = clk_register_fixed_factor(dev, OSCIN_CLK_NAME,
|
||||
parent_name, 0, 1, 1);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
parent_name = OSCIN_CLK_NAME;
|
||||
}
|
||||
|
||||
if (info->flags & PLL_HAS_PREDIV) {
|
||||
bool fixed = info->flags & PLL_PREDIV_FIXED_DIV;
|
||||
u32 flags = 0;
|
||||
|
||||
snprintf(prediv_name, MAX_NAME_SIZE, "%s_prediv", info->name);
|
||||
|
||||
if (info->flags & PLL_PREDIV_ALWAYS_ENABLED)
|
||||
flags |= CLK_IS_CRITICAL;
|
||||
|
||||
/* Some? DM355 chips don't correctly report the PREDIV value */
|
||||
if (info->flags & PLL_PREDIV_FIXED8)
|
||||
clk = clk_register_fixed_factor(dev, prediv_name,
|
||||
parent_name, flags, 1, 8);
|
||||
else
|
||||
clk = davinci_pll_div_register(dev, prediv_name,
|
||||
parent_name, base + PREDIV, fixed, flags);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
parent_name = prediv_name;
|
||||
}
|
||||
|
||||
/* Unlock writing to PLL registers */
|
||||
if (info->unlock_reg) {
|
||||
if (IS_ERR_OR_NULL(pdata->cfgchip))
|
||||
dev_warn(dev, "Failed to get CFGCHIP (%ld)\n",
|
||||
PTR_ERR(pdata->cfgchip));
|
||||
else
|
||||
regmap_write_bits(pdata->cfgchip, info->unlock_reg,
|
||||
info->unlock_mask, 0);
|
||||
}
|
||||
|
||||
pllout = devm_kzalloc(dev, sizeof(*pllout), GFP_KERNEL);
|
||||
if (!pllout)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
snprintf(pllout_name, MAX_NAME_SIZE, "%s_pllout", info->name);
|
||||
|
||||
init.name = pllout_name;
|
||||
if (info->flags & PLL_PLLM_2X)
|
||||
init.ops = &dm365_pll_ops;
|
||||
else
|
||||
init.ops = &davinci_pll_ops;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.flags = 0;
|
||||
|
||||
if (info->flags & PLL_HAS_PREDIV)
|
||||
init.flags |= CLK_SET_RATE_PARENT;
|
||||
|
||||
pllout->hw.init = &init;
|
||||
pllout->base = base;
|
||||
pllout->pllm_mask = info->pllm_mask;
|
||||
pllout->pllm_min = info->pllm_min;
|
||||
pllout->pllm_max = info->pllm_max;
|
||||
|
||||
pllout_clk = devm_clk_register(dev, &pllout->hw);
|
||||
if (IS_ERR(pllout_clk))
|
||||
return pllout_clk;
|
||||
|
||||
clk_hw_set_rate_range(&pllout->hw, info->pllout_min_rate,
|
||||
info->pllout_max_rate);
|
||||
|
||||
parent_name = pllout_name;
|
||||
|
||||
if (info->flags & PLL_HAS_POSTDIV) {
|
||||
bool fixed = info->flags & PLL_POSTDIV_FIXED_DIV;
|
||||
u32 flags = CLK_SET_RATE_PARENT;
|
||||
|
||||
snprintf(postdiv_name, MAX_NAME_SIZE, "%s_postdiv", info->name);
|
||||
|
||||
if (info->flags & PLL_POSTDIV_ALWAYS_ENABLED)
|
||||
flags |= CLK_IS_CRITICAL;
|
||||
|
||||
clk = davinci_pll_div_register(dev, postdiv_name, parent_name,
|
||||
base + POSTDIV, fixed, flags);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
parent_name = postdiv_name;
|
||||
}
|
||||
|
||||
pllen = devm_kzalloc(dev, sizeof(*pllout), GFP_KERNEL);
|
||||
if (!pllen)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
snprintf(pllen_name, MAX_NAME_SIZE, "%s_pllen", info->name);
|
||||
|
||||
init.name = pllen_name;
|
||||
init.ops = &davinci_pllen_ops;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
|
||||
pllen->hw.init = &init;
|
||||
pllen->base = base;
|
||||
|
||||
clk = devm_clk_register(dev, &pllen->hw);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
clk_notifier_register(clk, &davinci_pllen_notifier);
|
||||
|
||||
return pllout_clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* davinci_pll_auxclk_register - Register bypass clock (AUXCLK)
|
||||
* @name: The clock name
|
||||
* @base: The PLL memory region
|
||||
*/
|
||||
struct clk *davinci_pll_auxclk_register(struct device *dev,
|
||||
const char *name,
|
||||
void __iomem *base)
|
||||
{
|
||||
return clk_register_gate(dev, name, OSCIN_CLK_NAME, 0, base + CKEN,
|
||||
CKEN_AUXEN_SHIFT, 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* davinci_pll_sysclkbp_clk_register - Register bypass divider clock (SYSCLKBP)
|
||||
* @name: The clock name
|
||||
* @base: The PLL memory region
|
||||
*/
|
||||
struct clk *davinci_pll_sysclkbp_clk_register(struct device *dev,
|
||||
const char *name,
|
||||
void __iomem *base)
|
||||
{
|
||||
return clk_register_divider(dev, name, OSCIN_CLK_NAME, 0, base + BPDIV,
|
||||
DIV_RATIO_SHIFT, DIV_RATIO_WIDTH,
|
||||
CLK_DIVIDER_READ_ONLY, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* davinci_pll_obsclk_register - Register oscillator divider clock (OBSCLK)
|
||||
* @info: The clock info
|
||||
* @base: The PLL memory region
|
||||
*/
|
||||
struct clk *
|
||||
davinci_pll_obsclk_register(struct device *dev,
|
||||
const struct davinci_pll_obsclk_info *info,
|
||||
void __iomem *base)
|
||||
{
|
||||
struct clk_mux *mux;
|
||||
struct clk_gate *gate;
|
||||
struct clk_divider *divider;
|
||||
u32 oscdiv;
|
||||
|
||||
mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mux->reg = base + OCSEL;
|
||||
mux->table = info->table;
|
||||
mux->mask = info->ocsrc_mask;
|
||||
|
||||
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
gate->reg = base + CKEN;
|
||||
gate->bit_idx = CKEN_OBSCLK_SHIFT;
|
||||
|
||||
divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL);
|
||||
if (!divider)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
divider->reg = base + OSCDIV;
|
||||
divider->shift = DIV_RATIO_SHIFT;
|
||||
divider->width = DIV_RATIO_WIDTH;
|
||||
|
||||
/* make sure divider is enabled just in case bootloader disabled it */
|
||||
oscdiv = readl(base + OSCDIV);
|
||||
oscdiv |= BIT(DIV_ENABLE_SHIFT);
|
||||
writel(oscdiv, base + OSCDIV);
|
||||
|
||||
return clk_register_composite(dev, info->name, info->parent_names,
|
||||
info->num_parents,
|
||||
&mux->hw, &clk_mux_ops,
|
||||
÷r->hw, &clk_divider_ops,
|
||||
&gate->hw, &clk_gate_ops, 0);
|
||||
}
|
||||
|
||||
/* The PLL SYSCLKn clocks have a mechanism for synchronizing rate changes. */
|
||||
static int davinci_pll_sysclk_rate_change(struct notifier_block *nb,
|
||||
unsigned long flags, void *data)
|
||||
{
|
||||
struct clk_notifier_data *cnd = data;
|
||||
struct clk_hw *hw = __clk_get_hw(clk_get_parent(cnd->clk));
|
||||
struct davinci_pllen_clk *pll = to_davinci_pllen_clk(hw);
|
||||
u32 pllcmd, pllstat;
|
||||
|
||||
switch (flags) {
|
||||
case POST_RATE_CHANGE:
|
||||
/* apply the changes */
|
||||
pllcmd = readl(pll->base + PLLCMD);
|
||||
pllcmd |= PLLCMD_GOSET;
|
||||
writel(pllcmd, pll->base + PLLCMD);
|
||||
/* fallthrough */
|
||||
case PRE_RATE_CHANGE:
|
||||
/* Wait until for outstanding changes to take effect */
|
||||
do {
|
||||
pllstat = readl(pll->base + PLLSTAT);
|
||||
} while (pllstat & PLLSTAT_GOSTAT);
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block davinci_pll_sysclk_notifier = {
|
||||
.notifier_call = davinci_pll_sysclk_rate_change,
|
||||
};
|
||||
|
||||
/**
|
||||
* davinci_pll_sysclk_register - Register divider clocks (SYSCLKn)
|
||||
* @info: The clock info
|
||||
* @base: The PLL memory region
|
||||
*/
|
||||
struct clk *
|
||||
davinci_pll_sysclk_register(struct device *dev,
|
||||
const struct davinci_pll_sysclk_info *info,
|
||||
void __iomem *base)
|
||||
{
|
||||
const struct clk_ops *divider_ops = &clk_divider_ops;
|
||||
struct clk_gate *gate;
|
||||
struct clk_divider *divider;
|
||||
struct clk *clk;
|
||||
u32 reg;
|
||||
u32 flags = 0;
|
||||
|
||||
/* PLLDIVn registers are not entirely consecutive */
|
||||
if (info->id < 4)
|
||||
reg = PLLDIV1 + 4 * (info->id - 1);
|
||||
else
|
||||
reg = PLLDIV4 + 4 * (info->id - 4);
|
||||
|
||||
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
gate->reg = base + reg;
|
||||
gate->bit_idx = DIV_ENABLE_SHIFT;
|
||||
|
||||
divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL);
|
||||
if (!divider)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
divider->reg = base + reg;
|
||||
divider->shift = DIV_RATIO_SHIFT;
|
||||
divider->width = info->ratio_width;
|
||||
divider->flags = 0;
|
||||
|
||||
if (info->flags & SYSCLK_FIXED_DIV) {
|
||||
divider->flags |= CLK_DIVIDER_READ_ONLY;
|
||||
divider_ops = &clk_divider_ro_ops;
|
||||
}
|
||||
|
||||
/* Only the ARM clock can change the parent PLL rate */
|
||||
if (info->flags & SYSCLK_ARM_RATE)
|
||||
flags |= CLK_SET_RATE_PARENT;
|
||||
|
||||
if (info->flags & SYSCLK_ALWAYS_ENABLED)
|
||||
flags |= CLK_IS_CRITICAL;
|
||||
|
||||
clk = clk_register_composite(dev, info->name, &info->parent_name, 1,
|
||||
NULL, NULL, ÷r->hw, divider_ops,
|
||||
&gate->hw, &clk_gate_ops, flags);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
clk_notifier_register(clk, &davinci_pll_sysclk_notifier);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
int of_davinci_pll_init(struct device *dev,
|
||||
const struct davinci_pll_clk_info *info,
|
||||
const struct davinci_pll_obsclk_info *obsclk_info,
|
||||
const struct davinci_pll_sysclk_info **div_info,
|
||||
u8 max_sysclk_id,
|
||||
void __iomem *base)
|
||||
{
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *child;
|
||||
const char *parent_name;
|
||||
struct clk *clk;
|
||||
|
||||
if (info->flags & PLL_HAS_CLKMODE)
|
||||
parent_name = of_clk_get_parent_name(node, 0);
|
||||
else
|
||||
parent_name = OSCIN_CLK_NAME;
|
||||
|
||||
clk = davinci_pll_clk_register(dev, info, parent_name, base);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "failed to register %s\n", info->name);
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
child = of_get_child_by_name(node, "pllout");
|
||||
if (of_device_is_available(child))
|
||||
of_clk_add_provider(child, of_clk_src_simple_get, clk);
|
||||
of_node_put(child);
|
||||
|
||||
child = of_get_child_by_name(node, "sysclk");
|
||||
if (of_device_is_available(child)) {
|
||||
struct clk_onecell_data *clk_data;
|
||||
struct clk **clks;
|
||||
int n_clks = max_sysclk_id + 1;
|
||||
int i;
|
||||
|
||||
clk_data = devm_kzalloc(dev, sizeof(*clk_data), GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
clks = devm_kmalloc_array(dev, n_clks, sizeof(*clks), GFP_KERNEL);
|
||||
if (!clks)
|
||||
return -ENOMEM;
|
||||
|
||||
clk_data->clks = clks;
|
||||
clk_data->clk_num = n_clks;
|
||||
|
||||
for (i = 0; i < n_clks; i++)
|
||||
clks[i] = ERR_PTR(-ENOENT);
|
||||
|
||||
for (; *div_info; div_info++) {
|
||||
clk = davinci_pll_sysclk_register(dev, *div_info, base);
|
||||
if (IS_ERR(clk))
|
||||
dev_warn(dev, "failed to register %s (%ld)\n",
|
||||
(*div_info)->name, PTR_ERR(clk));
|
||||
else
|
||||
clks[(*div_info)->id] = clk;
|
||||
}
|
||||
of_clk_add_provider(child, of_clk_src_onecell_get, clk_data);
|
||||
}
|
||||
of_node_put(child);
|
||||
|
||||
child = of_get_child_by_name(node, "auxclk");
|
||||
if (of_device_is_available(child)) {
|
||||
char child_name[MAX_NAME_SIZE];
|
||||
|
||||
snprintf(child_name, MAX_NAME_SIZE, "%s_auxclk", info->name);
|
||||
|
||||
clk = davinci_pll_auxclk_register(dev, child_name, base);
|
||||
if (IS_ERR(clk))
|
||||
dev_warn(dev, "failed to register %s (%ld)\n",
|
||||
child_name, PTR_ERR(clk));
|
||||
else
|
||||
of_clk_add_provider(child, of_clk_src_simple_get, clk);
|
||||
}
|
||||
of_node_put(child);
|
||||
|
||||
child = of_get_child_by_name(node, "obsclk");
|
||||
if (of_device_is_available(child)) {
|
||||
if (obsclk_info)
|
||||
clk = davinci_pll_obsclk_register(dev, obsclk_info, base);
|
||||
else
|
||||
clk = ERR_PTR(-EINVAL);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
dev_warn(dev, "failed to register obsclk (%ld)\n",
|
||||
PTR_ERR(clk));
|
||||
else
|
||||
of_clk_add_provider(child, of_clk_src_simple_get, clk);
|
||||
}
|
||||
of_node_put(child);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id davinci_pll_of_match[] = {
|
||||
{ .compatible = "ti,da850-pll0", .data = of_da850_pll0_init },
|
||||
{ .compatible = "ti,da850-pll1", .data = of_da850_pll1_init },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct platform_device_id davinci_pll_id_table[] = {
|
||||
{ .name = "da830-pll", .driver_data = (kernel_ulong_t)da830_pll_init },
|
||||
{ .name = "da850-pll0", .driver_data = (kernel_ulong_t)da850_pll0_init },
|
||||
{ .name = "da850-pll1", .driver_data = (kernel_ulong_t)da850_pll1_init },
|
||||
{ .name = "dm355-pll1", .driver_data = (kernel_ulong_t)dm355_pll1_init },
|
||||
{ .name = "dm355-pll2", .driver_data = (kernel_ulong_t)dm355_pll2_init },
|
||||
{ .name = "dm365-pll1", .driver_data = (kernel_ulong_t)dm365_pll1_init },
|
||||
{ .name = "dm365-pll2", .driver_data = (kernel_ulong_t)dm365_pll2_init },
|
||||
{ .name = "dm644x-pll1", .driver_data = (kernel_ulong_t)dm644x_pll1_init },
|
||||
{ .name = "dm644x-pll2", .driver_data = (kernel_ulong_t)dm644x_pll2_init },
|
||||
{ .name = "dm646x-pll1", .driver_data = (kernel_ulong_t)dm646x_pll1_init },
|
||||
{ .name = "dm646x-pll2", .driver_data = (kernel_ulong_t)dm646x_pll2_init },
|
||||
{ }
|
||||
};
|
||||
|
||||
typedef int (*davinci_pll_init)(struct device *dev, void __iomem *base);
|
||||
|
||||
static int davinci_pll_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct of_device_id *of_id;
|
||||
davinci_pll_init pll_init = NULL;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
|
||||
of_id = of_match_device(davinci_pll_of_match, dev);
|
||||
if (of_id)
|
||||
pll_init = of_id->data;
|
||||
else if (pdev->id_entry)
|
||||
pll_init = (void *)pdev->id_entry->driver_data;
|
||||
|
||||
if (!pll_init) {
|
||||
dev_err(dev, "unable to find driver data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
return pll_init(dev, base);
|
||||
}
|
||||
|
||||
static struct platform_driver davinci_pll_driver = {
|
||||
.probe = davinci_pll_probe,
|
||||
.driver = {
|
||||
.name = "davinci-pll-clk",
|
||||
.of_match_table = davinci_pll_of_match,
|
||||
},
|
||||
.id_table = davinci_pll_id_table,
|
||||
};
|
||||
|
||||
static int __init davinci_pll_driver_init(void)
|
||||
{
|
||||
return platform_driver_register(&davinci_pll_driver);
|
||||
}
|
||||
|
||||
/* has to be postcore_initcall because PSC devices depend on PLL parent clocks */
|
||||
postcore_initcall(davinci_pll_driver_init);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#define DEBUG_REG(n) \
|
||||
{ \
|
||||
.name = #n, \
|
||||
.offset = n, \
|
||||
}
|
||||
|
||||
static const struct debugfs_reg32 davinci_pll_regs[] = {
|
||||
DEBUG_REG(REVID),
|
||||
DEBUG_REG(PLLCTL),
|
||||
DEBUG_REG(OCSEL),
|
||||
DEBUG_REG(PLLSECCTL),
|
||||
DEBUG_REG(PLLM),
|
||||
DEBUG_REG(PREDIV),
|
||||
DEBUG_REG(PLLDIV1),
|
||||
DEBUG_REG(PLLDIV2),
|
||||
DEBUG_REG(PLLDIV3),
|
||||
DEBUG_REG(OSCDIV),
|
||||
DEBUG_REG(POSTDIV),
|
||||
DEBUG_REG(BPDIV),
|
||||
DEBUG_REG(PLLCMD),
|
||||
DEBUG_REG(PLLSTAT),
|
||||
DEBUG_REG(ALNCTL),
|
||||
DEBUG_REG(DCHANGE),
|
||||
DEBUG_REG(CKEN),
|
||||
DEBUG_REG(CKSTAT),
|
||||
DEBUG_REG(SYSTAT),
|
||||
DEBUG_REG(PLLDIV4),
|
||||
DEBUG_REG(PLLDIV5),
|
||||
DEBUG_REG(PLLDIV6),
|
||||
DEBUG_REG(PLLDIV7),
|
||||
DEBUG_REG(PLLDIV8),
|
||||
DEBUG_REG(PLLDIV9),
|
||||
};
|
||||
|
||||
static int davinci_pll_debug_init(struct clk_hw *hw, struct dentry *dentry)
|
||||
{
|
||||
struct davinci_pll_clk *pll = to_davinci_pll_clk(hw);
|
||||
struct debugfs_regset32 *regset;
|
||||
struct dentry *d;
|
||||
|
||||
regset = kzalloc(sizeof(*regset), GFP_KERNEL);
|
||||
if (!regset)
|
||||
return -ENOMEM;
|
||||
|
||||
regset->regs = davinci_pll_regs;
|
||||
regset->nregs = ARRAY_SIZE(davinci_pll_regs);
|
||||
regset->base = pll->base;
|
||||
|
||||
d = debugfs_create_regset32("registers", 0400, dentry, regset);
|
||||
if (IS_ERR(d)) {
|
||||
kfree(regset);
|
||||
return PTR_ERR(d);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,141 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Clock driver for TI Davinci PSC controllers
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#ifndef __CLK_DAVINCI_PLL_H___
|
||||
#define __CLK_DAVINCI_PLL_H___
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define PLL_HAS_CLKMODE BIT(0) /* PLL has PLLCTL[CLKMODE] */
|
||||
#define PLL_HAS_PREDIV BIT(1) /* has prediv before PLL */
|
||||
#define PLL_PREDIV_ALWAYS_ENABLED BIT(2) /* don't clear DEN bit */
|
||||
#define PLL_PREDIV_FIXED_DIV BIT(3) /* fixed divider value */
|
||||
#define PLL_HAS_POSTDIV BIT(4) /* has postdiv after PLL */
|
||||
#define PLL_POSTDIV_ALWAYS_ENABLED BIT(5) /* don't clear DEN bit */
|
||||
#define PLL_POSTDIV_FIXED_DIV BIT(6) /* fixed divider value */
|
||||
#define PLL_HAS_EXTCLKSRC BIT(7) /* has selectable bypass */
|
||||
#define PLL_PLLM_2X BIT(8) /* PLLM value is 2x (DM365) */
|
||||
#define PLL_PREDIV_FIXED8 BIT(9) /* DM355 quirk */
|
||||
|
||||
/** davinci_pll_clk_info - controller-specific PLL info
|
||||
* @name: The name of the PLL
|
||||
* @unlock_reg: Option CFGCHIP register for unlocking PLL
|
||||
* @unlock_mask: Bitmask used with @unlock_reg
|
||||
* @pllm_mask: Bitmask for PLLM[PLLM] value
|
||||
* @pllm_min: Minimum allowable value for PLLM[PLLM]
|
||||
* @pllm_max: Maximum allowable value for PLLM[PLLM]
|
||||
* @pllout_min_rate: Minimum allowable rate for PLLOUT
|
||||
* @pllout_max_rate: Maximum allowable rate for PLLOUT
|
||||
* @flags: Bitmap of PLL_* flags.
|
||||
*/
|
||||
struct davinci_pll_clk_info {
|
||||
const char *name;
|
||||
u32 unlock_reg;
|
||||
u32 unlock_mask;
|
||||
u32 pllm_mask;
|
||||
u32 pllm_min;
|
||||
u32 pllm_max;
|
||||
unsigned long pllout_min_rate;
|
||||
unsigned long pllout_max_rate;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
#define SYSCLK_ARM_RATE BIT(0) /* Controls ARM rate */
|
||||
#define SYSCLK_ALWAYS_ENABLED BIT(1) /* Or bad things happen */
|
||||
#define SYSCLK_FIXED_DIV BIT(2) /* Fixed divider */
|
||||
|
||||
/** davinci_pll_sysclk_info - SYSCLKn-specific info
|
||||
* @name: The name of the clock
|
||||
* @parent_name: The name of the parent clock
|
||||
* @id: "n" in "SYSCLKn"
|
||||
* @ratio_width: Width (in bits) of RATIO in PLLDIVn register
|
||||
* @flags: Bitmap of SYSCLK_* flags.
|
||||
*/
|
||||
struct davinci_pll_sysclk_info {
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
u32 id;
|
||||
u32 ratio_width;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
#define SYSCLK(i, n, p, w, f) \
|
||||
static const struct davinci_pll_sysclk_info n = { \
|
||||
.name = #n, \
|
||||
.parent_name = #p, \
|
||||
.id = (i), \
|
||||
.ratio_width = (w), \
|
||||
.flags = (f), \
|
||||
}
|
||||
|
||||
/** davinci_pll_obsclk_info - OBSCLK-specific info
|
||||
* @name: The name of the clock
|
||||
* @parent_names: Array of names of the parent clocks
|
||||
* @num_parents: Length of @parent_names
|
||||
* @table: Array of values to write to OCSEL[OCSRC] cooresponding to
|
||||
* @parent_names
|
||||
* @ocsrc_mask: Bitmask for OCSEL[OCSRC]
|
||||
*/
|
||||
struct davinci_pll_obsclk_info {
|
||||
const char *name;
|
||||
const char * const *parent_names;
|
||||
u8 num_parents;
|
||||
u32 *table;
|
||||
u32 ocsrc_mask;
|
||||
};
|
||||
|
||||
struct clk *davinci_pll_clk_register(struct device *dev,
|
||||
const struct davinci_pll_clk_info *info,
|
||||
const char *parent_name,
|
||||
void __iomem *base);
|
||||
struct clk *davinci_pll_auxclk_register(struct device *dev,
|
||||
const char *name,
|
||||
void __iomem *base);
|
||||
struct clk *davinci_pll_sysclkbp_clk_register(struct device *dev,
|
||||
const char *name,
|
||||
void __iomem *base);
|
||||
struct clk *
|
||||
davinci_pll_obsclk_register(struct device *dev,
|
||||
const struct davinci_pll_obsclk_info *info,
|
||||
void __iomem *base);
|
||||
struct clk *
|
||||
davinci_pll_sysclk_register(struct device *dev,
|
||||
const struct davinci_pll_sysclk_info *info,
|
||||
void __iomem *base);
|
||||
|
||||
int of_davinci_pll_init(struct device *dev,
|
||||
const struct davinci_pll_clk_info *info,
|
||||
const struct davinci_pll_obsclk_info *obsclk_info,
|
||||
const struct davinci_pll_sysclk_info **div_info,
|
||||
u8 max_sysclk_id,
|
||||
void __iomem *base);
|
||||
|
||||
/* Platform-specific callbacks */
|
||||
|
||||
int da830_pll_init(struct device *dev, void __iomem *base);
|
||||
|
||||
int da850_pll0_init(struct device *dev, void __iomem *base);
|
||||
int da850_pll1_init(struct device *dev, void __iomem *base);
|
||||
int of_da850_pll0_init(struct device *dev, void __iomem *base);
|
||||
int of_da850_pll1_init(struct device *dev, void __iomem *base);
|
||||
|
||||
int dm355_pll1_init(struct device *dev, void __iomem *base);
|
||||
int dm355_pll2_init(struct device *dev, void __iomem *base);
|
||||
|
||||
int dm365_pll1_init(struct device *dev, void __iomem *base);
|
||||
int dm365_pll2_init(struct device *dev, void __iomem *base);
|
||||
|
||||
int dm644x_pll1_init(struct device *dev, void __iomem *base);
|
||||
int dm644x_pll2_init(struct device *dev, void __iomem *base);
|
||||
|
||||
int dm646x_pll1_init(struct device *dev, void __iomem *base);
|
||||
int dm646x_pll2_init(struct device *dev, void __iomem *base);
|
||||
|
||||
#endif /* __CLK_DAVINCI_PLL_H___ */
|
|
@ -0,0 +1,116 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PSC clock descriptions for TI DA830/OMAP-L137/AM17XX
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "psc.h"
|
||||
|
||||
LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0");
|
||||
LPSC_CLKDEV1(mmcsd_clkdev, NULL, "da830-mmc.0");
|
||||
LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0");
|
||||
|
||||
static const struct davinci_lpsc_clk_info da830_psc0_info[] = {
|
||||
LPSC(0, 0, tpcc, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(1, 0, tptc0, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(2, 0, tptc1, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(3, 0, aemif, pll0_sysclk3, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(4, 0, spi0, pll0_sysclk2, spi0_clkdev, 0),
|
||||
LPSC(5, 0, mmcsd, pll0_sysclk2, mmcsd_clkdev, 0),
|
||||
LPSC(6, 0, aintc, pll0_sysclk4, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(7, 0, arm_rom, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(8, 0, secu_mgr, pll0_sysclk4, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(9, 0, uart0, pll0_sysclk2, uart0_clkdev, 0),
|
||||
LPSC(10, 0, scr0_ss, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(11, 0, scr1_ss, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(12, 0, scr2_ss, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(13, 0, pruss, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(14, 0, arm, pll0_sysclk6, NULL, LPSC_ALWAYS_ENABLED),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int da830_psc0_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return davinci_psc_register_clocks(dev, da830_psc0_info, 16, base);
|
||||
}
|
||||
|
||||
static struct clk_bulk_data da830_psc0_parent_clks[] = {
|
||||
{ .id = "pll0_sysclk2" },
|
||||
{ .id = "pll0_sysclk3" },
|
||||
{ .id = "pll0_sysclk4" },
|
||||
{ .id = "pll0_sysclk6" },
|
||||
};
|
||||
|
||||
const struct davinci_psc_init_data da830_psc0_init_data = {
|
||||
.parent_clks = da830_psc0_parent_clks,
|
||||
.num_parent_clks = ARRAY_SIZE(da830_psc0_parent_clks),
|
||||
.psc_init = &da830_psc0_init,
|
||||
};
|
||||
|
||||
LPSC_CLKDEV2(usb0_clkdev, NULL, "musb-da8xx",
|
||||
NULL, "cppi41-dmaengine");
|
||||
LPSC_CLKDEV1(usb1_clkdev, NULL, "ohci-da8xx");
|
||||
/* REVISIT: gpio-davinci.c should be modified to drop con_id */
|
||||
LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL);
|
||||
LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1",
|
||||
"fck", "davinci_mdio.0");
|
||||
LPSC_CLKDEV1(mcasp0_clkdev, NULL, "davinci-mcasp.0");
|
||||
LPSC_CLKDEV1(mcasp1_clkdev, NULL, "davinci-mcasp.1");
|
||||
LPSC_CLKDEV1(mcasp2_clkdev, NULL, "davinci-mcasp.2");
|
||||
LPSC_CLKDEV1(spi1_clkdev, NULL, "spi_davinci.1");
|
||||
LPSC_CLKDEV1(i2c1_clkdev, NULL, "i2c_davinci.2");
|
||||
LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1");
|
||||
LPSC_CLKDEV1(uart2_clkdev, NULL, "serial8250.2");
|
||||
LPSC_CLKDEV1(lcdc_clkdev, "fck", "da8xx_lcdc.0");
|
||||
LPSC_CLKDEV2(pwm_clkdev, "fck", "ehrpwm.0",
|
||||
"fck", "ehrpwm.1");
|
||||
LPSC_CLKDEV3(ecap_clkdev, "fck", "ecap.0",
|
||||
"fck", "ecap.1",
|
||||
"fck", "ecap.2");
|
||||
LPSC_CLKDEV2(eqep_clkdev, NULL, "eqep.0",
|
||||
NULL, "eqep.1");
|
||||
|
||||
static const struct davinci_lpsc_clk_info da830_psc1_info[] = {
|
||||
LPSC(1, 0, usb0, pll0_sysclk2, usb0_clkdev, 0),
|
||||
LPSC(2, 0, usb1, pll0_sysclk4, usb1_clkdev, 0),
|
||||
LPSC(3, 0, gpio, pll0_sysclk4, gpio_clkdev, 0),
|
||||
LPSC(5, 0, emac, pll0_sysclk4, emac_clkdev, 0),
|
||||
LPSC(6, 0, emif3, pll0_sysclk5, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(7, 0, mcasp0, pll0_sysclk2, mcasp0_clkdev, 0),
|
||||
LPSC(8, 0, mcasp1, pll0_sysclk2, mcasp1_clkdev, 0),
|
||||
LPSC(9, 0, mcasp2, pll0_sysclk2, mcasp2_clkdev, 0),
|
||||
LPSC(10, 0, spi1, pll0_sysclk2, spi1_clkdev, 0),
|
||||
LPSC(11, 0, i2c1, pll0_sysclk4, i2c1_clkdev, 0),
|
||||
LPSC(12, 0, uart1, pll0_sysclk2, uart1_clkdev, 0),
|
||||
LPSC(13, 0, uart2, pll0_sysclk2, uart2_clkdev, 0),
|
||||
LPSC(16, 0, lcdc, pll0_sysclk2, lcdc_clkdev, 0),
|
||||
LPSC(17, 0, pwm, pll0_sysclk2, pwm_clkdev, 0),
|
||||
LPSC(20, 0, ecap, pll0_sysclk2, ecap_clkdev, 0),
|
||||
LPSC(21, 0, eqep, pll0_sysclk2, eqep_clkdev, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int da830_psc1_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return davinci_psc_register_clocks(dev, da830_psc1_info, 32, base);
|
||||
}
|
||||
|
||||
static struct clk_bulk_data da830_psc1_parent_clks[] = {
|
||||
{ .id = "pll0_sysclk2" },
|
||||
{ .id = "pll0_sysclk4" },
|
||||
{ .id = "pll0_sysclk5" },
|
||||
};
|
||||
|
||||
const struct davinci_psc_init_data da830_psc1_init_data = {
|
||||
.parent_clks = da830_psc1_parent_clks,
|
||||
.num_parent_clks = ARRAY_SIZE(da830_psc1_parent_clks),
|
||||
.psc_init = &da830_psc1_init,
|
||||
};
|
|
@ -0,0 +1,149 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PSC clock descriptions for TI DA850/OMAP-L138/AM18XX
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "psc.h"
|
||||
|
||||
LPSC_CLKDEV2(emifa_clkdev, NULL, "ti-aemif",
|
||||
"aemif", "davinci_nand.0");
|
||||
LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0");
|
||||
LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "da830-mmc.0");
|
||||
LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0");
|
||||
/* REVISIT: used dev_id instead of con_id */
|
||||
LPSC_CLKDEV1(arm_clkdev, "arm", NULL);
|
||||
LPSC_CLKDEV1(dsp_clkdev, NULL, "davinci-rproc.0");
|
||||
|
||||
static const struct davinci_lpsc_clk_info da850_psc0_info[] = {
|
||||
LPSC(0, 0, tpcc0, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(1, 0, tptc0, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(2, 0, tptc1, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(3, 0, emifa, async1, emifa_clkdev, 0),
|
||||
LPSC(4, 0, spi0, pll0_sysclk2, spi0_clkdev, 0),
|
||||
LPSC(5, 0, mmcsd0, pll0_sysclk2, mmcsd0_clkdev, 0),
|
||||
LPSC(6, 0, aintc, pll0_sysclk4, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(7, 0, arm_rom, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(9, 0, uart0, pll0_sysclk2, uart0_clkdev, 0),
|
||||
LPSC(13, 0, pruss, pll0_sysclk2, NULL, 0),
|
||||
LPSC(14, 0, arm, pll0_sysclk6, arm_clkdev, LPSC_ALWAYS_ENABLED | LPSC_SET_RATE_PARENT),
|
||||
LPSC(15, 1, dsp, pll0_sysclk1, dsp_clkdev, LPSC_FORCE | LPSC_LOCAL_RESET),
|
||||
{ }
|
||||
};
|
||||
|
||||
LPSC_CLKDEV3(usb0_clkdev, "fck", "da830-usb-phy-clks",
|
||||
NULL, "musb-da8xx",
|
||||
NULL, "cppi41-dmaengine");
|
||||
LPSC_CLKDEV1(usb1_clkdev, NULL, "ohci-da8xx");
|
||||
/* REVISIT: gpio-davinci.c should be modified to drop con_id */
|
||||
LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL);
|
||||
LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1",
|
||||
"fck", "davinci_mdio.0");
|
||||
LPSC_CLKDEV1(mcasp0_clkdev, NULL, "davinci-mcasp.0");
|
||||
LPSC_CLKDEV1(sata_clkdev, "fck", "ahci_da850");
|
||||
LPSC_CLKDEV1(vpif_clkdev, NULL, "vpif");
|
||||
LPSC_CLKDEV1(spi1_clkdev, NULL, "spi_davinci.1");
|
||||
LPSC_CLKDEV1(i2c1_clkdev, NULL, "i2c_davinci.2");
|
||||
LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1");
|
||||
LPSC_CLKDEV1(uart2_clkdev, NULL, "serial8250.2");
|
||||
LPSC_CLKDEV1(mcbsp0_clkdev, NULL, "davinci-mcbsp.0");
|
||||
LPSC_CLKDEV1(mcbsp1_clkdev, NULL, "davinci-mcbsp.1");
|
||||
LPSC_CLKDEV1(lcdc_clkdev, "fck", "da8xx_lcdc.0");
|
||||
LPSC_CLKDEV3(ehrpwm_clkdev, "fck", "ehrpwm.0",
|
||||
"fck", "ehrpwm.1",
|
||||
NULL, "da830-tbclksync");
|
||||
LPSC_CLKDEV1(mmcsd1_clkdev, NULL, "da830-mmc.1");
|
||||
LPSC_CLKDEV3(ecap_clkdev, "fck", "ecap.0",
|
||||
"fck", "ecap.1",
|
||||
"fck", "ecap.2");
|
||||
|
||||
static int da850_psc0_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return davinci_psc_register_clocks(dev, da850_psc0_info, 16, base);
|
||||
}
|
||||
|
||||
static int of_da850_psc0_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return of_davinci_psc_clk_init(dev, da850_psc0_info, 16, base);
|
||||
}
|
||||
|
||||
static struct clk_bulk_data da850_psc0_parent_clks[] = {
|
||||
{ .id = "pll0_sysclk1" },
|
||||
{ .id = "pll0_sysclk2" },
|
||||
{ .id = "pll0_sysclk4" },
|
||||
{ .id = "pll0_sysclk6" },
|
||||
{ .id = "async1" },
|
||||
};
|
||||
|
||||
const struct davinci_psc_init_data da850_psc0_init_data = {
|
||||
.parent_clks = da850_psc0_parent_clks,
|
||||
.num_parent_clks = ARRAY_SIZE(da850_psc0_parent_clks),
|
||||
.psc_init = &da850_psc0_init,
|
||||
};
|
||||
|
||||
const struct davinci_psc_init_data of_da850_psc0_init_data = {
|
||||
.parent_clks = da850_psc0_parent_clks,
|
||||
.num_parent_clks = ARRAY_SIZE(da850_psc0_parent_clks),
|
||||
.psc_init = &of_da850_psc0_init,
|
||||
};
|
||||
|
||||
static const struct davinci_lpsc_clk_info da850_psc1_info[] = {
|
||||
LPSC(0, 0, tpcc1, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(1, 0, usb0, pll0_sysclk2, usb0_clkdev, 0),
|
||||
LPSC(2, 0, usb1, pll0_sysclk4, usb1_clkdev, 0),
|
||||
LPSC(3, 0, gpio, pll0_sysclk4, gpio_clkdev, 0),
|
||||
LPSC(5, 0, emac, pll0_sysclk4, emac_clkdev, 0),
|
||||
LPSC(6, 0, ddr, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(7, 0, mcasp0, async3, mcasp0_clkdev, 0),
|
||||
LPSC(8, 0, sata, pll0_sysclk2, sata_clkdev, LPSC_FORCE),
|
||||
LPSC(9, 0, vpif, pll0_sysclk2, vpif_clkdev, 0),
|
||||
LPSC(10, 0, spi1, async3, spi1_clkdev, 0),
|
||||
LPSC(11, 0, i2c1, pll0_sysclk4, i2c1_clkdev, 0),
|
||||
LPSC(12, 0, uart1, async3, uart1_clkdev, 0),
|
||||
LPSC(13, 0, uart2, async3, uart2_clkdev, 0),
|
||||
LPSC(14, 0, mcbsp0, async3, mcbsp0_clkdev, 0),
|
||||
LPSC(15, 0, mcbsp1, async3, mcbsp1_clkdev, 0),
|
||||
LPSC(16, 0, lcdc, pll0_sysclk2, lcdc_clkdev, 0),
|
||||
LPSC(17, 0, ehrpwm, async3, ehrpwm_clkdev, 0),
|
||||
LPSC(18, 0, mmcsd1, pll0_sysclk2, mmcsd1_clkdev, 0),
|
||||
LPSC(20, 0, ecap, async3, ecap_clkdev, 0),
|
||||
LPSC(21, 0, tptc2, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int da850_psc1_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return davinci_psc_register_clocks(dev, da850_psc1_info, 32, base);
|
||||
}
|
||||
|
||||
static int of_da850_psc1_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return of_davinci_psc_clk_init(dev, da850_psc1_info, 32, base);
|
||||
}
|
||||
|
||||
static struct clk_bulk_data da850_psc1_parent_clks[] = {
|
||||
{ .id = "pll0_sysclk2" },
|
||||
{ .id = "pll0_sysclk4" },
|
||||
{ .id = "async3" },
|
||||
};
|
||||
|
||||
const struct davinci_psc_init_data da850_psc1_init_data = {
|
||||
.parent_clks = da850_psc1_parent_clks,
|
||||
.num_parent_clks = ARRAY_SIZE(da850_psc1_parent_clks),
|
||||
.psc_init = &da850_psc1_init,
|
||||
};
|
||||
|
||||
const struct davinci_psc_init_data of_da850_psc1_init_data = {
|
||||
.parent_clks = da850_psc1_parent_clks,
|
||||
.num_parent_clks = ARRAY_SIZE(da850_psc1_parent_clks),
|
||||
.psc_init = &of_da850_psc1_init,
|
||||
};
|
|
@ -0,0 +1,88 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PSC clock descriptions for TI DaVinci DM355
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "psc.h"
|
||||
|
||||
LPSC_CLKDEV1(vpss_master_clkdev, "master", "vpss");
|
||||
LPSC_CLKDEV1(vpss_slave_clkdev, "slave", "vpss");
|
||||
LPSC_CLKDEV1(spi1_clkdev, NULL, "spi_davinci.1");
|
||||
LPSC_CLKDEV1(mmcsd1_clkdev, NULL, "dm6441-mmc.1");
|
||||
LPSC_CLKDEV1(mcbsp1_clkdev, NULL, "davinci-mcbsp.1");
|
||||
LPSC_CLKDEV1(usb_clkdev, "usb", NULL);
|
||||
LPSC_CLKDEV1(spi2_clkdev, NULL, "spi_davinci.2");
|
||||
LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL);
|
||||
LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "dm6441-mmc.0");
|
||||
LPSC_CLKDEV1(mcbsp0_clkdev, NULL, "davinci-mcbsp.0");
|
||||
LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1");
|
||||
LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0");
|
||||
LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1");
|
||||
LPSC_CLKDEV1(uart2_clkdev, NULL, "serial8250.2");
|
||||
LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0");
|
||||
/* REVISIT: gpio-davinci.c should be modified to drop con_id */
|
||||
LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL);
|
||||
LPSC_CLKDEV1(timer0_clkdev, "timer0", NULL);
|
||||
LPSC_CLKDEV1(timer2_clkdev, NULL, "davinci-wdt");
|
||||
LPSC_CLKDEV1(vpss_dac_clkdev, "vpss_dac", NULL);
|
||||
|
||||
static const struct davinci_lpsc_clk_info dm355_psc_info[] = {
|
||||
LPSC(0, 0, vpss_master, pll1_sysclk4, vpss_master_clkdev, 0),
|
||||
LPSC(1, 0, vpss_slave, pll1_sysclk4, vpss_slave_clkdev, 0),
|
||||
LPSC(5, 0, timer3, pll1_auxclk, NULL, 0),
|
||||
LPSC(6, 0, spi1, pll1_sysclk2, spi1_clkdev, 0),
|
||||
LPSC(7, 0, mmcsd1, pll1_sysclk2, mmcsd1_clkdev, 0),
|
||||
LPSC(8, 0, asp1, pll1_sysclk2, NULL, 0),
|
||||
LPSC(9, 0, usb, pll1_sysclk2, usb_clkdev, 0),
|
||||
LPSC(10, 0, pwm3, pll1_auxclk, NULL, 0),
|
||||
LPSC(11, 0, spi2, pll1_sysclk2, spi2_clkdev, 0),
|
||||
LPSC(12, 0, rto, pll1_auxclk, NULL, 0),
|
||||
LPSC(14, 0, aemif, pll1_sysclk2, aemif_clkdev, 0),
|
||||
LPSC(15, 0, mmcsd0, pll1_sysclk2, mmcsd0_clkdev, 0),
|
||||
LPSC(17, 0, asp0, pll1_sysclk2, NULL, 0),
|
||||
LPSC(18, 0, i2c, pll1_auxclk, i2c_clkdev, 0),
|
||||
LPSC(19, 0, uart0, pll1_auxclk, uart0_clkdev, 0),
|
||||
LPSC(20, 0, uart1, pll1_auxclk, uart1_clkdev, 0),
|
||||
LPSC(21, 0, uart2, pll1_sysclk2, uart2_clkdev, 0),
|
||||
LPSC(22, 0, spi0, pll1_sysclk2, spi0_clkdev, 0),
|
||||
LPSC(23, 0, pwm0, pll1_auxclk, NULL, 0),
|
||||
LPSC(24, 0, pwm1, pll1_auxclk, NULL, 0),
|
||||
LPSC(25, 0, pwm2, pll1_auxclk, NULL, 0),
|
||||
LPSC(26, 0, gpio, pll1_sysclk2, gpio_clkdev, 0),
|
||||
LPSC(27, 0, timer0, pll1_auxclk, timer0_clkdev, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(28, 0, timer1, pll1_auxclk, NULL, 0),
|
||||
/* REVISIT: why can't this be disabled? */
|
||||
LPSC(29, 0, timer2, pll1_auxclk, timer2_clkdev, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(31, 0, arm, pll1_sysclk1, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(40, 0, mjcp, pll1_sysclk1, NULL, 0),
|
||||
LPSC(41, 0, vpss_dac, pll1_sysclk3, vpss_dac_clkdev, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int dm355_psc_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return davinci_psc_register_clocks(dev, dm355_psc_info, 42, base);
|
||||
}
|
||||
|
||||
static struct clk_bulk_data dm355_psc_parent_clks[] = {
|
||||
{ .id = "pll1_sysclk1" },
|
||||
{ .id = "pll1_sysclk2" },
|
||||
{ .id = "pll1_sysclk3" },
|
||||
{ .id = "pll1_sysclk4" },
|
||||
{ .id = "pll1_auxclk" },
|
||||
};
|
||||
|
||||
const struct davinci_psc_init_data dm355_psc_init_data = {
|
||||
.parent_clks = dm355_psc_parent_clks,
|
||||
.num_parent_clks = ARRAY_SIZE(dm355_psc_parent_clks),
|
||||
.psc_init = &dm355_psc_init,
|
||||
};
|
|
@ -0,0 +1,96 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PSC clock descriptions for TI DaVinci DM365
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "psc.h"
|
||||
|
||||
LPSC_CLKDEV1(vpss_slave_clkdev, "slave", "vpss");
|
||||
LPSC_CLKDEV1(spi1_clkdev, NULL, "spi_davinci.1");
|
||||
LPSC_CLKDEV1(mmcsd1_clkdev, NULL, "da830-mmc.1");
|
||||
LPSC_CLKDEV1(asp0_clkdev, NULL, "davinci-mcbsp");
|
||||
LPSC_CLKDEV1(usb_clkdev, "usb", NULL);
|
||||
LPSC_CLKDEV1(spi2_clkdev, NULL, "spi_davinci.2");
|
||||
LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL);
|
||||
LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "da830-mmc.0");
|
||||
LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1");
|
||||
LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0");
|
||||
LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1");
|
||||
LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0");
|
||||
/* REVISIT: gpio-davinci.c should be modified to drop con_id */
|
||||
LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL);
|
||||
LPSC_CLKDEV1(timer0_clkdev, "timer0", NULL);
|
||||
LPSC_CLKDEV1(timer2_clkdev, NULL, "davinci-wdt");
|
||||
LPSC_CLKDEV1(spi3_clkdev, NULL, "spi_davinci.3");
|
||||
LPSC_CLKDEV1(spi4_clkdev, NULL, "spi_davinci.4");
|
||||
LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1",
|
||||
"fck", "davinci_mdio.0");
|
||||
LPSC_CLKDEV1(voice_codec_clkdev, NULL, "davinci_voicecodec");
|
||||
LPSC_CLKDEV1(vpss_dac_clkdev, "vpss_dac", NULL);
|
||||
LPSC_CLKDEV1(vpss_master_clkdev, "master", "vpss");
|
||||
|
||||
static const struct davinci_lpsc_clk_info dm365_psc_info[] = {
|
||||
LPSC(1, 0, vpss_slave, pll1_sysclk5, vpss_slave_clkdev, 0),
|
||||
LPSC(5, 0, timer3, pll1_auxclk, NULL, 0),
|
||||
LPSC(6, 0, spi1, pll1_sysclk4, spi1_clkdev, 0),
|
||||
LPSC(7, 0, mmcsd1, pll1_sysclk4, mmcsd1_clkdev, 0),
|
||||
LPSC(8, 0, asp0, pll1_sysclk4, asp0_clkdev, 0),
|
||||
LPSC(9, 0, usb, pll1_auxclk, usb_clkdev, 0),
|
||||
LPSC(10, 0, pwm3, pll1_auxclk, NULL, 0),
|
||||
LPSC(11, 0, spi2, pll1_sysclk4, spi2_clkdev, 0),
|
||||
LPSC(12, 0, rto, pll1_sysclk4, NULL, 0),
|
||||
LPSC(14, 0, aemif, pll1_sysclk4, aemif_clkdev, 0),
|
||||
LPSC(15, 0, mmcsd0, pll1_sysclk8, mmcsd0_clkdev, 0),
|
||||
LPSC(18, 0, i2c, pll1_auxclk, i2c_clkdev, 0),
|
||||
LPSC(19, 0, uart0, pll1_auxclk, uart0_clkdev, 0),
|
||||
LPSC(20, 0, uart1, pll1_sysclk4, uart1_clkdev, 0),
|
||||
LPSC(22, 0, spi0, pll1_sysclk4, spi0_clkdev, 0),
|
||||
LPSC(23, 0, pwm0, pll1_auxclk, NULL, 0),
|
||||
LPSC(24, 0, pwm1, pll1_auxclk, NULL, 0),
|
||||
LPSC(25, 0, pwm2, pll1_auxclk, NULL, 0),
|
||||
LPSC(26, 0, gpio, pll1_sysclk4, gpio_clkdev, 0),
|
||||
LPSC(27, 0, timer0, pll1_auxclk, timer0_clkdev, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(28, 0, timer1, pll1_auxclk, NULL, 0),
|
||||
/* REVISIT: why can't this be disabled? */
|
||||
LPSC(29, 0, timer2, pll1_auxclk, timer2_clkdev, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(31, 0, arm, pll2_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(38, 0, spi3, pll1_sysclk4, spi3_clkdev, 0),
|
||||
LPSC(39, 0, spi4, pll1_auxclk, spi4_clkdev, 0),
|
||||
LPSC(40, 0, emac, pll2_sysclk4, emac_clkdev, 0),
|
||||
LPSC(44, 1, voice_codec, pll1_sysclk3, voice_codec_clkdev, 0),
|
||||
LPSC(46, 1, vpss_dac, pll1_sysclk3, vpss_dac_clkdev, 0),
|
||||
LPSC(47, 0, vpss_master, pll1_sysclk5, vpss_master_clkdev, 0),
|
||||
LPSC(50, 0, mjcp, pll1_sysclk3, NULL, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int dm365_psc_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return davinci_psc_register_clocks(dev, dm365_psc_info, 52, base);
|
||||
}
|
||||
|
||||
static struct clk_bulk_data dm365_psc_parent_clks[] = {
|
||||
{ .id = "pll1_sysclk1" },
|
||||
{ .id = "pll1_sysclk3" },
|
||||
{ .id = "pll1_sysclk4" },
|
||||
{ .id = "pll1_sysclk5" },
|
||||
{ .id = "pll1_sysclk8" },
|
||||
{ .id = "pll2_sysclk2" },
|
||||
{ .id = "pll2_sysclk4" },
|
||||
{ .id = "pll1_auxclk" },
|
||||
};
|
||||
|
||||
const struct davinci_psc_init_data dm365_psc_init_data = {
|
||||
.parent_clks = dm365_psc_parent_clks,
|
||||
.num_parent_clks = ARRAY_SIZE(dm365_psc_parent_clks),
|
||||
.psc_init = &dm365_psc_init,
|
||||
};
|
|
@ -0,0 +1,83 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PSC clock descriptions for TI DaVinci DM644x
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "psc.h"
|
||||
|
||||
LPSC_CLKDEV1(vpss_master_clkdev, "master", "vpss");
|
||||
LPSC_CLKDEV1(vpss_slave_clkdev, "slave", "vpss");
|
||||
LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1",
|
||||
"fck", "davinci_mdio.0");
|
||||
LPSC_CLKDEV1(usb_clkdev, "usb", NULL);
|
||||
LPSC_CLKDEV1(ide_clkdev, NULL, "palm_bk3710");
|
||||
LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL);
|
||||
LPSC_CLKDEV1(mmcsd_clkdev, NULL, "dm6441-mmc.0");
|
||||
LPSC_CLKDEV1(asp0_clkdev, NULL, "davinci-mcbsp");
|
||||
LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1");
|
||||
LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0");
|
||||
LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1");
|
||||
LPSC_CLKDEV1(uart2_clkdev, NULL, "serial8250.2");
|
||||
/* REVISIT: gpio-davinci.c should be modified to drop con_id */
|
||||
LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL);
|
||||
LPSC_CLKDEV1(timer0_clkdev, "timer0", NULL);
|
||||
LPSC_CLKDEV1(timer2_clkdev, NULL, "davinci-wdt");
|
||||
|
||||
static const struct davinci_lpsc_clk_info dm644x_psc_info[] = {
|
||||
LPSC(0, 0, vpss_master, pll1_sysclk3, vpss_master_clkdev, 0),
|
||||
LPSC(1, 0, vpss_slave, pll1_sysclk3, vpss_slave_clkdev, 0),
|
||||
LPSC(6, 0, emac, pll1_sysclk5, emac_clkdev, 0),
|
||||
LPSC(9, 0, usb, pll1_sysclk5, usb_clkdev, 0),
|
||||
LPSC(10, 0, ide, pll1_sysclk5, ide_clkdev, 0),
|
||||
LPSC(11, 0, vlynq, pll1_sysclk5, NULL, 0),
|
||||
LPSC(14, 0, aemif, pll1_sysclk5, aemif_clkdev, 0),
|
||||
LPSC(15, 0, mmcsd, pll1_sysclk5, mmcsd_clkdev, 0),
|
||||
LPSC(17, 0, asp0, pll1_sysclk5, asp0_clkdev, 0),
|
||||
LPSC(18, 0, i2c, pll1_auxclk, i2c_clkdev, 0),
|
||||
LPSC(19, 0, uart0, pll1_auxclk, uart0_clkdev, 0),
|
||||
LPSC(20, 0, uart1, pll1_auxclk, uart1_clkdev, 0),
|
||||
LPSC(21, 0, uart2, pll1_auxclk, uart2_clkdev, 0),
|
||||
LPSC(22, 0, spi, pll1_sysclk5, NULL, 0),
|
||||
LPSC(23, 0, pwm0, pll1_auxclk, NULL, 0),
|
||||
LPSC(24, 0, pwm1, pll1_auxclk, NULL, 0),
|
||||
LPSC(25, 0, pwm2, pll1_auxclk, NULL, 0),
|
||||
LPSC(26, 0, gpio, pll1_sysclk5, gpio_clkdev, 0),
|
||||
LPSC(27, 0, timer0, pll1_auxclk, timer0_clkdev, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(28, 0, timer1, pll1_auxclk, NULL, 0),
|
||||
/* REVISIT: why can't this be disabled? */
|
||||
LPSC(29, 0, timer2, pll1_auxclk, timer2_clkdev, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(31, 0, arm, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
/* REVISIT how to disable? */
|
||||
LPSC(39, 1, dsp, pll1_sysclk1, NULL, LPSC_ALWAYS_ENABLED),
|
||||
/* REVISIT how to disable? */
|
||||
LPSC(40, 1, vicp, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int dm644x_psc_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return davinci_psc_register_clocks(dev, dm644x_psc_info, 41, base);
|
||||
}
|
||||
|
||||
static struct clk_bulk_data dm644x_psc_parent_clks[] = {
|
||||
{ .id = "pll1_sysclk1" },
|
||||
{ .id = "pll1_sysclk2" },
|
||||
{ .id = "pll1_sysclk3" },
|
||||
{ .id = "pll1_sysclk5" },
|
||||
{ .id = "pll1_auxclk" },
|
||||
};
|
||||
|
||||
const struct davinci_psc_init_data dm644x_psc_init_data = {
|
||||
.parent_clks = dm644x_psc_parent_clks,
|
||||
.num_parent_clks = ARRAY_SIZE(dm644x_psc_parent_clks),
|
||||
.psc_init = &dm644x_psc_init,
|
||||
};
|
|
@ -0,0 +1,80 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PSC clock descriptions for TI DaVinci DM646x
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "psc.h"
|
||||
|
||||
LPSC_CLKDEV1(ide_clkdev, NULL, "palm_bk3710");
|
||||
LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1",
|
||||
"fck", "davinci_mdio.0");
|
||||
LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL);
|
||||
LPSC_CLKDEV1(mcasp0_clkdev, NULL, "davinci-mcasp.0");
|
||||
LPSC_CLKDEV1(mcasp1_clkdev, NULL, "davinci-mcasp.1");
|
||||
LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0");
|
||||
LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1");
|
||||
LPSC_CLKDEV1(uart2_clkdev, NULL, "serial8250.2");
|
||||
LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1");
|
||||
/* REVISIT: gpio-davinci.c should be modified to drop con_id */
|
||||
LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL);
|
||||
LPSC_CLKDEV1(timer0_clkdev, "timer0", NULL);
|
||||
|
||||
static const struct davinci_lpsc_clk_info dm646x_psc_info[] = {
|
||||
LPSC(0, 0, arm, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
/* REVISIT how to disable? */
|
||||
LPSC(1, 0, dsp, pll1_sysclk1, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(4, 0, edma_cc, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(5, 0, edma_tc0, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(6, 0, edma_tc1, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(7, 0, edma_tc2, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(8, 0, edma_tc3, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(10, 0, ide, pll1_sysclk4, ide_clkdev, 0),
|
||||
LPSC(14, 0, emac, pll1_sysclk3, emac_clkdev, 0),
|
||||
LPSC(16, 0, vpif0, ref_clk, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(17, 0, vpif1, ref_clk, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(21, 0, aemif, pll1_sysclk3, aemif_clkdev, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(22, 0, mcasp0, pll1_sysclk3, mcasp0_clkdev, 0),
|
||||
LPSC(23, 0, mcasp1, pll1_sysclk3, mcasp1_clkdev, 0),
|
||||
LPSC(26, 0, uart0, aux_clkin, uart0_clkdev, 0),
|
||||
LPSC(27, 0, uart1, aux_clkin, uart1_clkdev, 0),
|
||||
LPSC(28, 0, uart2, aux_clkin, uart2_clkdev, 0),
|
||||
/* REVIST: disabling hangs system */
|
||||
LPSC(29, 0, pwm0, pll1_sysclk3, NULL, LPSC_ALWAYS_ENABLED),
|
||||
/* REVIST: disabling hangs system */
|
||||
LPSC(30, 0, pwm1, pll1_sysclk3, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(31, 0, i2c, pll1_sysclk3, i2c_clkdev, 0),
|
||||
LPSC(33, 0, gpio, pll1_sysclk3, gpio_clkdev, 0),
|
||||
LPSC(34, 0, timer0, pll1_sysclk3, timer0_clkdev, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(35, 0, timer1, pll1_sysclk3, NULL, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int dm646x_psc_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return davinci_psc_register_clocks(dev, dm646x_psc_info, 46, base);
|
||||
}
|
||||
|
||||
static struct clk_bulk_data dm646x_psc_parent_clks[] = {
|
||||
{ .id = "ref_clk" },
|
||||
{ .id = "aux_clkin" },
|
||||
{ .id = "pll1_sysclk1" },
|
||||
{ .id = "pll1_sysclk2" },
|
||||
{ .id = "pll1_sysclk3" },
|
||||
{ .id = "pll1_sysclk4" },
|
||||
{ .id = "pll1_sysclk5" },
|
||||
};
|
||||
|
||||
const struct davinci_psc_init_data dm646x_psc_init_data = {
|
||||
.parent_clks = dm646x_psc_parent_clks,
|
||||
.num_parent_clks = ARRAY_SIZE(dm646x_psc_parent_clks),
|
||||
.psc_init = &dm646x_psc_init,
|
||||
};
|
|
@ -0,0 +1,550 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Clock driver for TI Davinci PSC controllers
|
||||
*
|
||||
* Copyright (C) 2017 David Lechner <david@lechnology.com>
|
||||
*
|
||||
* Based on: drivers/clk/keystone/gate.c
|
||||
* Copyright (C) 2013 Texas Instruments.
|
||||
* Murali Karicheri <m-karicheri2@ti.com>
|
||||
* Santosh Shilimkar <santosh.shilimkar@ti.com>
|
||||
*
|
||||
* And: arch/arm/mach-davinci/psc.c
|
||||
* Copyright (C) 2006 Texas Instruments.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_clock.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "psc.h"
|
||||
|
||||
/* PSC register offsets */
|
||||
#define EPCPR 0x070
|
||||
#define PTCMD 0x120
|
||||
#define PTSTAT 0x128
|
||||
#define PDSTAT(n) (0x200 + 4 * (n))
|
||||
#define PDCTL(n) (0x300 + 4 * (n))
|
||||
#define MDSTAT(n) (0x800 + 4 * (n))
|
||||
#define MDCTL(n) (0xa00 + 4 * (n))
|
||||
|
||||
/* PSC module states */
|
||||
enum davinci_lpsc_state {
|
||||
LPSC_STATE_SWRSTDISABLE = 0,
|
||||
LPSC_STATE_SYNCRST = 1,
|
||||
LPSC_STATE_DISABLE = 2,
|
||||
LPSC_STATE_ENABLE = 3,
|
||||
};
|
||||
|
||||
#define MDSTAT_STATE_MASK GENMASK(5, 0)
|
||||
#define MDSTAT_MCKOUT BIT(12)
|
||||
#define PDSTAT_STATE_MASK GENMASK(4, 0)
|
||||
#define MDCTL_FORCE BIT(31)
|
||||
#define MDCTL_LRESET BIT(8)
|
||||
#define PDCTL_EPCGOOD BIT(8)
|
||||
#define PDCTL_NEXT BIT(0)
|
||||
|
||||
struct davinci_psc_data {
|
||||
struct clk_onecell_data clk_data;
|
||||
struct genpd_onecell_data pm_data;
|
||||
struct reset_controller_dev rcdev;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct davinci_lpsc_clk - LPSC clock structure
|
||||
* @dev: the device that provides this LPSC
|
||||
* @hw: clk_hw for the LPSC
|
||||
* @pm_domain: power domain for the LPSC
|
||||
* @genpd_clk: clock reference owned by @pm_domain
|
||||
* @regmap: PSC MMIO region
|
||||
* @md: Module domain (LPSC module id)
|
||||
* @pd: Power domain
|
||||
* @flags: LPSC_* quirk flags
|
||||
*/
|
||||
struct davinci_lpsc_clk {
|
||||
struct device *dev;
|
||||
struct clk_hw hw;
|
||||
struct generic_pm_domain pm_domain;
|
||||
struct clk *genpd_clk;
|
||||
struct regmap *regmap;
|
||||
u32 md;
|
||||
u32 pd;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
#define to_davinci_psc_data(x) container_of(x, struct davinci_psc_data, x)
|
||||
#define to_davinci_lpsc_clk(x) container_of(x, struct davinci_lpsc_clk, x)
|
||||
|
||||
/**
|
||||
* best_dev_name - get the "best" device name.
|
||||
* @dev: the device
|
||||
*
|
||||
* Returns the device tree compatible name if the device has a DT node,
|
||||
* otherwise return the device name. This is mainly needed because clkdev
|
||||
* lookups are limited to 20 chars for dev_id and when using device tree,
|
||||
* dev_name(dev) is much longer than that.
|
||||
*/
|
||||
static inline const char *best_dev_name(struct device *dev)
|
||||
{
|
||||
const char *compatible;
|
||||
|
||||
if (!of_property_read_string(dev->of_node, "compatible", &compatible))
|
||||
return compatible;
|
||||
|
||||
return dev_name(dev);
|
||||
}
|
||||
|
||||
static void davinci_lpsc_config(struct davinci_lpsc_clk *lpsc,
|
||||
enum davinci_lpsc_state next_state)
|
||||
{
|
||||
u32 epcpr, pdstat, mdstat, ptstat;
|
||||
|
||||
regmap_write_bits(lpsc->regmap, MDCTL(lpsc->md), MDSTAT_STATE_MASK,
|
||||
next_state);
|
||||
|
||||
if (lpsc->flags & LPSC_FORCE)
|
||||
regmap_write_bits(lpsc->regmap, MDCTL(lpsc->md), MDCTL_FORCE,
|
||||
MDCTL_FORCE);
|
||||
|
||||
regmap_read(lpsc->regmap, PDSTAT(lpsc->pd), &pdstat);
|
||||
if ((pdstat & PDSTAT_STATE_MASK) == 0) {
|
||||
regmap_write_bits(lpsc->regmap, PDCTL(lpsc->pd), PDCTL_NEXT,
|
||||
PDCTL_NEXT);
|
||||
|
||||
regmap_write(lpsc->regmap, PTCMD, BIT(lpsc->pd));
|
||||
|
||||
regmap_read_poll_timeout(lpsc->regmap, EPCPR, epcpr,
|
||||
epcpr & BIT(lpsc->pd), 0, 0);
|
||||
|
||||
regmap_write_bits(lpsc->regmap, PDCTL(lpsc->pd), PDCTL_EPCGOOD,
|
||||
PDCTL_EPCGOOD);
|
||||
} else {
|
||||
regmap_write(lpsc->regmap, PTCMD, BIT(lpsc->pd));
|
||||
}
|
||||
|
||||
regmap_read_poll_timeout(lpsc->regmap, PTSTAT, ptstat,
|
||||
!(ptstat & BIT(lpsc->pd)), 0, 0);
|
||||
|
||||
regmap_read_poll_timeout(lpsc->regmap, MDSTAT(lpsc->md), mdstat,
|
||||
(mdstat & MDSTAT_STATE_MASK) == next_state,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
static int davinci_lpsc_clk_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(hw);
|
||||
|
||||
davinci_lpsc_config(lpsc, LPSC_STATE_ENABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void davinci_lpsc_clk_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(hw);
|
||||
|
||||
davinci_lpsc_config(lpsc, LPSC_STATE_DISABLE);
|
||||
}
|
||||
|
||||
static int davinci_lpsc_clk_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(hw);
|
||||
u32 mdstat;
|
||||
|
||||
regmap_read(lpsc->regmap, MDSTAT(lpsc->md), &mdstat);
|
||||
|
||||
return (mdstat & MDSTAT_MCKOUT) ? 1 : 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops davinci_lpsc_clk_ops = {
|
||||
.enable = davinci_lpsc_clk_enable,
|
||||
.disable = davinci_lpsc_clk_disable,
|
||||
.is_enabled = davinci_lpsc_clk_is_enabled,
|
||||
};
|
||||
|
||||
static int davinci_psc_genpd_attach_dev(struct generic_pm_domain *pm_domain,
|
||||
struct device *dev)
|
||||
{
|
||||
struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(pm_domain);
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* pm_clk_remove_clk() will call clk_put(), so we have to use clk_get()
|
||||
* to get the clock instead of using lpsc->hw.clk directly.
|
||||
*/
|
||||
clk = clk_get_sys(best_dev_name(lpsc->dev), clk_hw_get_name(&lpsc->hw));
|
||||
if (IS_ERR(clk))
|
||||
return (PTR_ERR(clk));
|
||||
|
||||
ret = pm_clk_create(dev);
|
||||
if (ret < 0)
|
||||
goto fail_clk_put;
|
||||
|
||||
ret = pm_clk_add_clk(dev, clk);
|
||||
if (ret < 0)
|
||||
goto fail_pm_clk_destroy;
|
||||
|
||||
lpsc->genpd_clk = clk;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_pm_clk_destroy:
|
||||
pm_clk_destroy(dev);
|
||||
fail_clk_put:
|
||||
clk_put(clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void davinci_psc_genpd_detach_dev(struct generic_pm_domain *pm_domain,
|
||||
struct device *dev)
|
||||
{
|
||||
struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(pm_domain);
|
||||
|
||||
pm_clk_remove_clk(dev, lpsc->genpd_clk);
|
||||
pm_clk_destroy(dev);
|
||||
|
||||
lpsc->genpd_clk = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* davinci_lpsc_clk_register - register LPSC clock
|
||||
* @name: name of this clock
|
||||
* @parent_name: name of clock's parent
|
||||
* @regmap: PSC MMIO region
|
||||
* @md: local PSC number
|
||||
* @pd: power domain
|
||||
* @flags: LPSC_* flags
|
||||
*/
|
||||
static struct davinci_lpsc_clk *
|
||||
davinci_lpsc_clk_register(struct device *dev, const char *name,
|
||||
const char *parent_name, struct regmap *regmap,
|
||||
u32 md, u32 pd, u32 flags)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
struct davinci_lpsc_clk *lpsc;
|
||||
int ret;
|
||||
bool is_on;
|
||||
|
||||
lpsc = devm_kzalloc(dev, sizeof(*lpsc), GFP_KERNEL);
|
||||
if (!lpsc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &davinci_lpsc_clk_ops;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
init.flags = 0;
|
||||
|
||||
if (flags & LPSC_ALWAYS_ENABLED)
|
||||
init.flags |= CLK_IS_CRITICAL;
|
||||
|
||||
if (flags & LPSC_SET_RATE_PARENT)
|
||||
init.flags |= CLK_SET_RATE_PARENT;
|
||||
|
||||
lpsc->dev = dev;
|
||||
lpsc->regmap = regmap;
|
||||
lpsc->hw.init = &init;
|
||||
lpsc->md = md;
|
||||
lpsc->pd = pd;
|
||||
lpsc->flags = flags;
|
||||
|
||||
ret = devm_clk_hw_register(dev, &lpsc->hw);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/* genpd attach needs a way to look up this clock */
|
||||
ret = clk_hw_register_clkdev(&lpsc->hw, name, best_dev_name(dev));
|
||||
|
||||
lpsc->pm_domain.name = devm_kasprintf(dev, GFP_KERNEL, "%s: %s",
|
||||
best_dev_name(dev), name);
|
||||
lpsc->pm_domain.attach_dev = davinci_psc_genpd_attach_dev;
|
||||
lpsc->pm_domain.detach_dev = davinci_psc_genpd_detach_dev;
|
||||
lpsc->pm_domain.flags = GENPD_FLAG_PM_CLK;
|
||||
|
||||
is_on = davinci_lpsc_clk_is_enabled(&lpsc->hw);
|
||||
pm_genpd_init(&lpsc->pm_domain, NULL, is_on);
|
||||
|
||||
return lpsc;
|
||||
}
|
||||
|
||||
static int davinci_lpsc_clk_reset(struct clk *clk, bool reset)
|
||||
{
|
||||
struct clk_hw *hw = __clk_get_hw(clk);
|
||||
struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(hw);
|
||||
u32 mdctl;
|
||||
|
||||
if (IS_ERR_OR_NULL(lpsc))
|
||||
return -EINVAL;
|
||||
|
||||
mdctl = reset ? 0 : MDCTL_LRESET;
|
||||
regmap_write_bits(lpsc->regmap, MDCTL(lpsc->md), MDCTL_LRESET, mdctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* REVISIT: These exported functions can be removed after a non-DT lookup is
|
||||
* added to the reset controller framework and the davinci-rproc driver is
|
||||
* updated to use the generic reset controller framework.
|
||||
*/
|
||||
|
||||
int davinci_clk_reset_assert(struct clk *clk)
|
||||
{
|
||||
return davinci_lpsc_clk_reset(clk, true);
|
||||
}
|
||||
EXPORT_SYMBOL(davinci_clk_reset_assert);
|
||||
|
||||
int davinci_clk_reset_deassert(struct clk *clk)
|
||||
{
|
||||
return davinci_lpsc_clk_reset(clk, false);
|
||||
}
|
||||
EXPORT_SYMBOL(davinci_clk_reset_deassert);
|
||||
|
||||
static int davinci_psc_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct davinci_psc_data *psc = to_davinci_psc_data(rcdev);
|
||||
struct clk *clk = psc->clk_data.clks[id];
|
||||
|
||||
return davinci_lpsc_clk_reset(clk, true);
|
||||
}
|
||||
|
||||
static int davinci_psc_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct davinci_psc_data *psc = to_davinci_psc_data(rcdev);
|
||||
struct clk *clk = psc->clk_data.clks[id];
|
||||
|
||||
return davinci_lpsc_clk_reset(clk, false);
|
||||
}
|
||||
|
||||
static const struct reset_control_ops davinci_psc_reset_ops = {
|
||||
.assert = davinci_psc_reset_assert,
|
||||
.deassert = davinci_psc_reset_deassert,
|
||||
};
|
||||
|
||||
static int davinci_psc_reset_of_xlate(struct reset_controller_dev *rcdev,
|
||||
const struct of_phandle_args *reset_spec)
|
||||
{
|
||||
struct of_phandle_args clkspec = *reset_spec; /* discard const qualifier */
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
struct davinci_lpsc_clk *lpsc;
|
||||
|
||||
/* the clock node is the same as the reset node */
|
||||
clk = of_clk_get_from_provider(&clkspec);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
hw = __clk_get_hw(clk);
|
||||
lpsc = to_davinci_lpsc_clk(hw);
|
||||
clk_put(clk);
|
||||
|
||||
/* not all modules support local reset */
|
||||
if (!(lpsc->flags & LPSC_LOCAL_RESET))
|
||||
return -EINVAL;
|
||||
|
||||
return lpsc->md;
|
||||
}
|
||||
|
||||
static const struct regmap_config davinci_psc_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
};
|
||||
|
||||
static struct davinci_psc_data *
|
||||
__davinci_psc_register_clocks(struct device *dev,
|
||||
const struct davinci_lpsc_clk_info *info,
|
||||
int num_clks,
|
||||
void __iomem *base)
|
||||
{
|
||||
struct davinci_psc_data *psc;
|
||||
struct clk **clks;
|
||||
struct generic_pm_domain **pm_domains;
|
||||
struct regmap *regmap;
|
||||
int i, ret;
|
||||
|
||||
psc = devm_kzalloc(dev, sizeof(*psc), GFP_KERNEL);
|
||||
if (!psc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
clks = devm_kmalloc_array(dev, num_clks, sizeof(*clks), GFP_KERNEL);
|
||||
if (!clks)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
psc->clk_data.clks = clks;
|
||||
psc->clk_data.clk_num = num_clks;
|
||||
|
||||
/*
|
||||
* init array with error so that of_clk_src_onecell_get() doesn't
|
||||
* return NULL for gaps in the sparse array
|
||||
*/
|
||||
for (i = 0; i < num_clks; i++)
|
||||
clks[i] = ERR_PTR(-ENOENT);
|
||||
|
||||
pm_domains = devm_kcalloc(dev, num_clks, sizeof(*pm_domains), GFP_KERNEL);
|
||||
if (!pm_domains)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
psc->pm_data.domains = pm_domains;
|
||||
psc->pm_data.num_domains = num_clks;
|
||||
|
||||
regmap = devm_regmap_init_mmio(dev, base, &davinci_psc_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return ERR_CAST(regmap);
|
||||
|
||||
for (; info->name; info++) {
|
||||
struct davinci_lpsc_clk *lpsc;
|
||||
|
||||
lpsc = davinci_lpsc_clk_register(dev, info->name, info->parent,
|
||||
regmap, info->md, info->pd,
|
||||
info->flags);
|
||||
if (IS_ERR(lpsc)) {
|
||||
dev_warn(dev, "Failed to register %s (%ld)\n",
|
||||
info->name, PTR_ERR(lpsc));
|
||||
continue;
|
||||
}
|
||||
|
||||
clks[info->md] = lpsc->hw.clk;
|
||||
pm_domains[info->md] = &lpsc->pm_domain;
|
||||
}
|
||||
|
||||
psc->rcdev.ops = &davinci_psc_reset_ops;
|
||||
psc->rcdev.owner = THIS_MODULE;
|
||||
psc->rcdev.of_node = dev->of_node;
|
||||
psc->rcdev.of_reset_n_cells = 1;
|
||||
psc->rcdev.of_xlate = davinci_psc_reset_of_xlate;
|
||||
psc->rcdev.nr_resets = num_clks;
|
||||
|
||||
ret = devm_reset_controller_register(dev, &psc->rcdev);
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "Failed to register reset controller (%d)\n", ret);
|
||||
|
||||
return psc;
|
||||
}
|
||||
|
||||
int davinci_psc_register_clocks(struct device *dev,
|
||||
const struct davinci_lpsc_clk_info *info,
|
||||
u8 num_clks,
|
||||
void __iomem *base)
|
||||
{
|
||||
struct davinci_psc_data *psc;
|
||||
|
||||
psc = __davinci_psc_register_clocks(dev, info, num_clks, base);
|
||||
if (IS_ERR(psc))
|
||||
return PTR_ERR(psc);
|
||||
|
||||
for (; info->name; info++) {
|
||||
const struct davinci_lpsc_clkdev_info *cdevs = info->cdevs;
|
||||
struct clk *clk = psc->clk_data.clks[info->md];
|
||||
|
||||
if (!cdevs || IS_ERR_OR_NULL(clk))
|
||||
continue;
|
||||
|
||||
for (; cdevs->con_id || cdevs->dev_id; cdevs++)
|
||||
clk_register_clkdev(clk, cdevs->con_id, cdevs->dev_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int of_davinci_psc_clk_init(struct device *dev,
|
||||
const struct davinci_lpsc_clk_info *info,
|
||||
u8 num_clks,
|
||||
void __iomem *base)
|
||||
{
|
||||
struct device_node *node = dev->of_node;
|
||||
struct davinci_psc_data *psc;
|
||||
|
||||
psc = __davinci_psc_register_clocks(dev, info, num_clks, base);
|
||||
if (IS_ERR(psc))
|
||||
return PTR_ERR(psc);
|
||||
|
||||
of_genpd_add_provider_onecell(node, &psc->pm_data);
|
||||
|
||||
of_clk_add_provider(node, of_clk_src_onecell_get, &psc->clk_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id davinci_psc_of_match[] = {
|
||||
{ .compatible = "ti,da850-psc0", .data = &of_da850_psc0_init_data },
|
||||
{ .compatible = "ti,da850-psc1", .data = &of_da850_psc1_init_data },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct platform_device_id davinci_psc_id_table[] = {
|
||||
{ .name = "da830-psc0", .driver_data = (kernel_ulong_t)&da830_psc0_init_data },
|
||||
{ .name = "da830-psc1", .driver_data = (kernel_ulong_t)&da830_psc1_init_data },
|
||||
{ .name = "da850-psc0", .driver_data = (kernel_ulong_t)&da850_psc0_init_data },
|
||||
{ .name = "da850-psc1", .driver_data = (kernel_ulong_t)&da850_psc1_init_data },
|
||||
{ .name = "dm355-psc", .driver_data = (kernel_ulong_t)&dm355_psc_init_data },
|
||||
{ .name = "dm365-psc", .driver_data = (kernel_ulong_t)&dm365_psc_init_data },
|
||||
{ .name = "dm644x-psc", .driver_data = (kernel_ulong_t)&dm644x_psc_init_data },
|
||||
{ .name = "dm646x-psc", .driver_data = (kernel_ulong_t)&dm646x_psc_init_data },
|
||||
{ }
|
||||
};
|
||||
|
||||
static int davinci_psc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct of_device_id *of_id;
|
||||
const struct davinci_psc_init_data *init_data = NULL;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
of_id = of_match_device(davinci_psc_of_match, dev);
|
||||
if (of_id)
|
||||
init_data = of_id->data;
|
||||
else if (pdev->id_entry)
|
||||
init_data = (void *)pdev->id_entry->driver_data;
|
||||
|
||||
if (!init_data) {
|
||||
dev_err(dev, "unable to find driver init data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
ret = devm_clk_bulk_get(dev, init_data->num_parent_clks,
|
||||
init_data->parent_clks);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return init_data->psc_init(dev, base);
|
||||
}
|
||||
|
||||
static struct platform_driver davinci_psc_driver = {
|
||||
.probe = davinci_psc_probe,
|
||||
.driver = {
|
||||
.name = "davinci-psc-clk",
|
||||
.of_match_table = davinci_psc_of_match,
|
||||
},
|
||||
.id_table = davinci_psc_id_table,
|
||||
};
|
||||
|
||||
static int __init davinci_psc_driver_init(void)
|
||||
{
|
||||
return platform_driver_register(&davinci_psc_driver);
|
||||
}
|
||||
|
||||
/* has to be postcore_initcall because davinci_gpio depend on PSC clocks */
|
||||
postcore_initcall(davinci_psc_driver_init);
|
|
@ -0,0 +1,108 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Clock driver for TI Davinci PSC controllers
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#ifndef __CLK_DAVINCI_PSC_H__
|
||||
#define __CLK_DAVINCI_PSC_H__
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* PSC quirk flags */
|
||||
#define LPSC_ALWAYS_ENABLED BIT(0) /* never disable this clock */
|
||||
#define LPSC_SET_RATE_PARENT BIT(1) /* propagate set_rate to parent clock */
|
||||
#define LPSC_FORCE BIT(2) /* requires MDCTL FORCE bit */
|
||||
#define LPSC_LOCAL_RESET BIT(3) /* acts as reset provider */
|
||||
|
||||
struct davinci_lpsc_clkdev_info {
|
||||
const char *con_id;
|
||||
const char *dev_id;
|
||||
};
|
||||
|
||||
#define LPSC_CLKDEV(c, d) { \
|
||||
.con_id = (c), \
|
||||
.dev_id = (d) \
|
||||
}
|
||||
|
||||
#define LPSC_CLKDEV1(n, c, d) \
|
||||
static const struct davinci_lpsc_clkdev_info n[] __initconst = { \
|
||||
LPSC_CLKDEV((c), (d)), \
|
||||
{ } \
|
||||
}
|
||||
|
||||
#define LPSC_CLKDEV2(n, c1, d1, c2, d2) \
|
||||
static const struct davinci_lpsc_clkdev_info n[] __initconst = { \
|
||||
LPSC_CLKDEV((c1), (d1)), \
|
||||
LPSC_CLKDEV((c2), (d2)), \
|
||||
{ } \
|
||||
}
|
||||
|
||||
#define LPSC_CLKDEV3(n, c1, d1, c2, d2, c3, d3) \
|
||||
static const struct davinci_lpsc_clkdev_info n[] __initconst = { \
|
||||
LPSC_CLKDEV((c1), (d1)), \
|
||||
LPSC_CLKDEV((c2), (d2)), \
|
||||
LPSC_CLKDEV((c3), (d3)), \
|
||||
{ } \
|
||||
}
|
||||
|
||||
/**
|
||||
* davinci_lpsc_clk_info - LPSC module-specific clock information
|
||||
* @name: the clock name
|
||||
* @parent: the parent clock name
|
||||
* @cdevs: optional array of clkdev lookup table info
|
||||
* @md: the local module domain (LPSC id)
|
||||
* @pd: the power domain id
|
||||
* @flags: bitmask of LPSC_* flags
|
||||
*/
|
||||
struct davinci_lpsc_clk_info {
|
||||
const char *name;
|
||||
const char *parent;
|
||||
const struct davinci_lpsc_clkdev_info *cdevs;
|
||||
u32 md;
|
||||
u32 pd;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
#define LPSC(m, d, n, p, c, f) \
|
||||
{ \
|
||||
.name = #n, \
|
||||
.parent = #p, \
|
||||
.cdevs = (c), \
|
||||
.md = (m), \
|
||||
.pd = (d), \
|
||||
.flags = (f), \
|
||||
}
|
||||
|
||||
int davinci_psc_register_clocks(struct device *dev,
|
||||
const struct davinci_lpsc_clk_info *info,
|
||||
u8 num_clks,
|
||||
void __iomem *base);
|
||||
|
||||
int of_davinci_psc_clk_init(struct device *dev,
|
||||
const struct davinci_lpsc_clk_info *info,
|
||||
u8 num_clks,
|
||||
void __iomem *base);
|
||||
|
||||
/* Device-specific data */
|
||||
|
||||
struct davinci_psc_init_data {
|
||||
struct clk_bulk_data *parent_clks;
|
||||
int num_parent_clks;
|
||||
int (*psc_init)(struct device *dev, void __iomem *base);
|
||||
};
|
||||
|
||||
extern const struct davinci_psc_init_data da830_psc0_init_data;
|
||||
extern const struct davinci_psc_init_data da830_psc1_init_data;
|
||||
extern const struct davinci_psc_init_data da850_psc0_init_data;
|
||||
extern const struct davinci_psc_init_data da850_psc1_init_data;
|
||||
extern const struct davinci_psc_init_data of_da850_psc0_init_data;
|
||||
extern const struct davinci_psc_init_data of_da850_psc1_init_data;
|
||||
extern const struct davinci_psc_init_data dm355_psc_init_data;
|
||||
extern const struct davinci_psc_init_data dm365_psc_init_data;
|
||||
extern const struct davinci_psc_init_data dm644x_psc_init_data;
|
||||
extern const struct davinci_psc_init_data dm646x_psc_init_data;
|
||||
|
||||
#endif /* __CLK_DAVINCI_PSC_H__ */
|
|
@ -25,6 +25,8 @@ struct rockchip_mmc_clock {
|
|||
void __iomem *reg;
|
||||
int id;
|
||||
int shift;
|
||||
int cached_phase;
|
||||
struct notifier_block clk_rate_change_nb;
|
||||
};
|
||||
|
||||
#define to_mmc_clock(_hw) container_of(_hw, struct rockchip_mmc_clock, hw)
|
||||
|
@ -58,6 +60,12 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw)
|
|||
u16 degrees;
|
||||
u32 delay_num = 0;
|
||||
|
||||
/* See the comment for rockchip_mmc_set_phase below */
|
||||
if (!rate) {
|
||||
pr_err("%s: invalid clk rate\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift);
|
||||
|
||||
degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
|
||||
|
@ -84,6 +92,23 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees)
|
|||
u32 raw_value;
|
||||
u32 delay;
|
||||
|
||||
/*
|
||||
* The below calculation is based on the output clock from
|
||||
* MMC host to the card, which expects the phase clock inherits
|
||||
* the clock rate from its parent, namely the output clock
|
||||
* provider of MMC host. However, things may go wrong if
|
||||
* (1) It is orphan.
|
||||
* (2) It is assigned to the wrong parent.
|
||||
*
|
||||
* This check help debug the case (1), which seems to be the
|
||||
* most likely problem we often face and which makes it difficult
|
||||
* for people to debug unstable mmc tuning results.
|
||||
*/
|
||||
if (!rate) {
|
||||
pr_err("%s: invalid clk rate\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nineties = degrees / 90;
|
||||
remainder = (degrees % 90);
|
||||
|
||||
|
@ -139,6 +164,41 @@ static const struct clk_ops rockchip_mmc_clk_ops = {
|
|||
.set_phase = rockchip_mmc_set_phase,
|
||||
};
|
||||
|
||||
#define to_rockchip_mmc_clock(x) \
|
||||
container_of(x, struct rockchip_mmc_clock, clk_rate_change_nb)
|
||||
static int rockchip_mmc_clk_rate_notify(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct rockchip_mmc_clock *mmc_clock = to_rockchip_mmc_clock(nb);
|
||||
struct clk_notifier_data *ndata = data;
|
||||
|
||||
/*
|
||||
* rockchip_mmc_clk is mostly used by mmc controllers to sample
|
||||
* the intput data, which expects the fixed phase after the tuning
|
||||
* process. However if the clock rate is changed, the phase is stale
|
||||
* and may break the data sampling. So here we try to restore the phase
|
||||
* for that case, except that
|
||||
* (1) cached_phase is invaild since we inevitably cached it when the
|
||||
* clock provider be reparented from orphan to its real parent in the
|
||||
* first place. Otherwise we may mess up the initialization of MMC cards
|
||||
* since we only set the default sample phase and drive phase later on.
|
||||
* (2) the new coming rate is higher than the older one since mmc driver
|
||||
* set the max-frequency to match the boards' ability but we can't go
|
||||
* over the heads of that, otherwise the tests smoke out the issue.
|
||||
*/
|
||||
if (ndata->old_rate <= ndata->new_rate)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (event == PRE_RATE_CHANGE)
|
||||
mmc_clock->cached_phase =
|
||||
rockchip_mmc_get_phase(&mmc_clock->hw);
|
||||
else if (mmc_clock->cached_phase != -EINVAL &&
|
||||
event == POST_RATE_CHANGE)
|
||||
rockchip_mmc_set_phase(&mmc_clock->hw, mmc_clock->cached_phase);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
struct clk *rockchip_clk_register_mmc(const char *name,
|
||||
const char *const *parent_names, u8 num_parents,
|
||||
void __iomem *reg, int shift)
|
||||
|
@ -146,6 +206,7 @@ struct clk *rockchip_clk_register_mmc(const char *name,
|
|||
struct clk_init_data init;
|
||||
struct rockchip_mmc_clock *mmc_clock;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
mmc_clock = kmalloc(sizeof(*mmc_clock), GFP_KERNEL);
|
||||
if (!mmc_clock)
|
||||
|
@ -162,8 +223,21 @@ struct clk *rockchip_clk_register_mmc(const char *name,
|
|||
mmc_clock->shift = shift;
|
||||
|
||||
clk = clk_register(NULL, &mmc_clock->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(mmc_clock);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_register;
|
||||
}
|
||||
|
||||
mmc_clock->clk_rate_change_nb.notifier_call =
|
||||
&rockchip_mmc_clk_rate_notify;
|
||||
ret = clk_notifier_register(clk, &mmc_clock->clk_rate_change_nb);
|
||||
if (ret)
|
||||
goto err_notifier;
|
||||
|
||||
return clk;
|
||||
err_notifier:
|
||||
clk_unregister(clk);
|
||||
err_register:
|
||||
kfree(mmc_clock);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
|
|
@ -387,7 +387,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
|
|||
RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 6, DFLAGS,
|
||||
RK2928_CLKGATE_CON(2), 15, GFLAGS),
|
||||
|
||||
COMPOSITE(SCLK_SDMMC, "sclk_sdmmc0", mux_mmc_src_p, 0,
|
||||
COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0,
|
||||
RK2928_CLKSEL_CON(11), 8, 2, MFLAGS, 0, 8, DFLAGS,
|
||||
RK2928_CLKGATE_CON(2), 11, GFLAGS),
|
||||
|
||||
|
|
|
@ -304,7 +304,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
COMPOSITE_NOMUX(0, "aclk_core", "armclk", CLK_IGNORE_UNUSED,
|
||||
RK3328_CLKSEL_CON(1), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
|
||||
RK3328_CLKGATE_CON(7), 1, GFLAGS),
|
||||
GATE(0, "aclk_core_niu", "aclk_core", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "aclk_core_niu", "aclk_core", 0,
|
||||
RK3328_CLKGATE_CON(13), 0, GFLAGS),
|
||||
GATE(0, "aclk_gic400", "aclk_core", CLK_IGNORE_UNUSED,
|
||||
RK3328_CLKGATE_CON(13), 1, GFLAGS),
|
||||
|
@ -318,7 +318,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
RK3328_CLKGATE_CON(6), 6, GFLAGS),
|
||||
GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", CLK_SET_RATE_PARENT,
|
||||
RK3328_CLKGATE_CON(14), 0, GFLAGS),
|
||||
GATE(0, "aclk_gpu_niu", "aclk_gpu_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "aclk_gpu_niu", "aclk_gpu_pre", 0,
|
||||
RK3328_CLKGATE_CON(14), 1, GFLAGS),
|
||||
|
||||
/* PD_DDR */
|
||||
|
@ -513,9 +513,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
RK3328_CLKGATE_CON(24), 0, GFLAGS),
|
||||
GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", CLK_SET_RATE_PARENT,
|
||||
RK3328_CLKGATE_CON(24), 1, GFLAGS),
|
||||
GATE(0, "aclk_rkvdec_niu", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "aclk_rkvdec_niu", "aclk_rkvdec_pre", 0,
|
||||
RK3328_CLKGATE_CON(24), 2, GFLAGS),
|
||||
GATE(0, "hclk_rkvdec_niu", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "hclk_rkvdec_niu", "hclk_rkvdec_pre", 0,
|
||||
RK3328_CLKGATE_CON(24), 3, GFLAGS),
|
||||
|
||||
COMPOSITE(SCLK_VDEC_CABAC, "sclk_vdec_cabac", mux_4plls_p, 0,
|
||||
|
@ -535,9 +535,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
RK3328_CLKGATE_CON(23), 0, GFLAGS),
|
||||
GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", CLK_SET_RATE_PARENT,
|
||||
RK3328_CLKGATE_CON(23), 1, GFLAGS),
|
||||
GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", 0,
|
||||
RK3328_CLKGATE_CON(23), 2, GFLAGS),
|
||||
GATE(0, "hclk_vpu_niu", "hclk_vpu_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "hclk_vpu_niu", "hclk_vpu_pre", 0,
|
||||
RK3328_CLKGATE_CON(23), 3, GFLAGS),
|
||||
|
||||
COMPOSITE(ACLK_RKVENC, "aclk_rkvenc", mux_4plls_p, 0,
|
||||
|
@ -545,9 +545,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
RK3328_CLKGATE_CON(6), 3, GFLAGS),
|
||||
FACTOR_GATE(HCLK_RKVENC, "hclk_rkvenc", "aclk_rkvenc", 0, 1, 4,
|
||||
RK3328_CLKGATE_CON(11), 4, GFLAGS),
|
||||
GATE(0, "aclk_rkvenc_niu", "aclk_rkvenc", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "aclk_rkvenc_niu", "aclk_rkvenc", 0,
|
||||
RK3328_CLKGATE_CON(25), 0, GFLAGS),
|
||||
GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc", 0,
|
||||
RK3328_CLKGATE_CON(25), 1, GFLAGS),
|
||||
GATE(ACLK_H265, "aclk_h265", "aclk_rkvenc", 0,
|
||||
RK3328_CLKGATE_CON(25), 0, GFLAGS),
|
||||
|
@ -588,7 +588,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
COMPOSITE(ACLK_VOP_PRE, "aclk_vop_pre", mux_4plls_p, 0,
|
||||
RK3328_CLKSEL_CON(39), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
||||
RK3328_CLKGATE_CON(5), 5, GFLAGS),
|
||||
GATE(0, "clk_hdmi_sfc", "xin24m", 0,
|
||||
GATE(SCLK_HDMI_SFC, "sclk_hdmi_sfc", "xin24m", 0,
|
||||
RK3328_CLKGATE_CON(5), 4, GFLAGS),
|
||||
|
||||
COMPOSITE_NODIV(0, "clk_cif_src", mux_2plls_p, 0,
|
||||
|
@ -602,7 +602,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
RK3328_CLKGATE_CON(5), 6, GFLAGS),
|
||||
DIV(DCLK_HDMIPHY, "dclk_hdmiphy", "dclk_lcdc_src", 0,
|
||||
RK3328_CLKSEL_CON(40), 3, 3, DFLAGS),
|
||||
MUX(DCLK_LCDC, "dclk_lcdc", mux_dclk_lcdc_p, 0,
|
||||
MUX(DCLK_LCDC, "dclk_lcdc", mux_dclk_lcdc_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
|
||||
RK3328_CLKSEL_CON(40), 1, 1, MFLAGS),
|
||||
|
||||
/*
|
||||
|
@ -709,14 +709,14 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
|
||||
/* PD_VOP */
|
||||
GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3328_CLKGATE_CON(21), 10, GFLAGS),
|
||||
GATE(0, "aclk_rga_niu", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(22), 3, GFLAGS),
|
||||
GATE(0, "aclk_rga_niu", "aclk_rga_pre", 0, RK3328_CLKGATE_CON(22), 3, GFLAGS),
|
||||
GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0, RK3328_CLKGATE_CON(21), 2, GFLAGS),
|
||||
GATE(0, "aclk_vop_niu", "aclk_vop_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 4, GFLAGS),
|
||||
GATE(0, "aclk_vop_niu", "aclk_vop_pre", 0, RK3328_CLKGATE_CON(21), 4, GFLAGS),
|
||||
|
||||
GATE(ACLK_IEP, "aclk_iep", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 6, GFLAGS),
|
||||
GATE(ACLK_CIF, "aclk_cif", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 8, GFLAGS),
|
||||
GATE(ACLK_HDCP, "aclk_hdcp", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 15, GFLAGS),
|
||||
GATE(0, "aclk_vio_niu", "aclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(22), 2, GFLAGS),
|
||||
GATE(0, "aclk_vio_niu", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 2, GFLAGS),
|
||||
|
||||
GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 3, GFLAGS),
|
||||
GATE(0, "hclk_vop_niu", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 5, GFLAGS),
|
||||
|
@ -724,10 +724,10 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
GATE(HCLK_CIF, "hclk_cif", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 9, GFLAGS),
|
||||
GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 11, GFLAGS),
|
||||
GATE(0, "hclk_ahb1tom", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 12, GFLAGS),
|
||||
GATE(0, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 13, GFLAGS),
|
||||
GATE(0, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 14, GFLAGS),
|
||||
GATE(0, "pclk_vio_h2p", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 13, GFLAGS),
|
||||
GATE(0, "hclk_vio_h2p", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 14, GFLAGS),
|
||||
GATE(HCLK_HDCP, "hclk_hdcp", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 0, GFLAGS),
|
||||
GATE(HCLK_VIO, "hclk_vio", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 1, GFLAGS),
|
||||
GATE(0, "hclk_vio_niu", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 1, GFLAGS),
|
||||
GATE(PCLK_HDMI, "pclk_hdmi", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 4, GFLAGS),
|
||||
GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 5, GFLAGS),
|
||||
|
||||
|
@ -743,19 +743,19 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 7, GFLAGS),
|
||||
GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 8, GFLAGS),
|
||||
GATE(HCLK_OTG_PMU, "hclk_otg_pmu", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 9, GFLAGS),
|
||||
GATE(0, "hclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 12, GFLAGS),
|
||||
GATE(0, "pclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 13, GFLAGS),
|
||||
GATE(0, "hclk_peri_niu", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 12, GFLAGS),
|
||||
GATE(0, "pclk_peri_niu", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 13, GFLAGS),
|
||||
|
||||
/* PD_GMAC */
|
||||
GATE(ACLK_MAC2PHY, "aclk_mac2phy", "aclk_gmac", 0, RK3328_CLKGATE_CON(26), 0, GFLAGS),
|
||||
GATE(ACLK_MAC2IO, "aclk_mac2io", "aclk_gmac", 0, RK3328_CLKGATE_CON(26), 2, GFLAGS),
|
||||
GATE(0, "aclk_gmac_niu", "aclk_gmac", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(26), 4, GFLAGS),
|
||||
GATE(0, "aclk_gmac_niu", "aclk_gmac", 0, RK3328_CLKGATE_CON(26), 4, GFLAGS),
|
||||
GATE(PCLK_MAC2PHY, "pclk_mac2phy", "pclk_gmac", 0, RK3328_CLKGATE_CON(26), 1, GFLAGS),
|
||||
GATE(PCLK_MAC2IO, "pclk_mac2io", "pclk_gmac", 0, RK3328_CLKGATE_CON(26), 3, GFLAGS),
|
||||
GATE(0, "pclk_gmac_niu", "pclk_gmac", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(26), 5, GFLAGS),
|
||||
GATE(0, "pclk_gmac_niu", "pclk_gmac", 0, RK3328_CLKGATE_CON(26), 5, GFLAGS),
|
||||
|
||||
/* PD_BUS */
|
||||
GATE(0, "aclk_bus_niu", "aclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 12, GFLAGS),
|
||||
GATE(0, "aclk_bus_niu", "aclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 12, GFLAGS),
|
||||
GATE(ACLK_DCF, "aclk_dcf", "aclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 11, GFLAGS),
|
||||
GATE(ACLK_TSP, "aclk_tsp", "aclk_bus_pre", 0, RK3328_CLKGATE_CON(17), 12, GFLAGS),
|
||||
GATE(0, "aclk_intmem", "aclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 0, GFLAGS),
|
||||
|
@ -769,10 +769,10 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
GATE(HCLK_TSP, "hclk_tsp", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(17), 11, GFLAGS),
|
||||
GATE(HCLK_CRYPTO_MST, "hclk_crypto_mst", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 7, GFLAGS),
|
||||
GATE(HCLK_CRYPTO_SLV, "hclk_crypto_slv", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 8, GFLAGS),
|
||||
GATE(0, "hclk_bus_niu", "hclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 13, GFLAGS),
|
||||
GATE(0, "hclk_bus_niu", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 13, GFLAGS),
|
||||
GATE(HCLK_PDM, "hclk_pdm", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(28), 0, GFLAGS),
|
||||
|
||||
GATE(0, "pclk_bus_niu", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 14, GFLAGS),
|
||||
GATE(0, "pclk_bus_niu", "pclk_bus", 0, RK3328_CLKGATE_CON(15), 14, GFLAGS),
|
||||
GATE(0, "pclk_efuse", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 9, GFLAGS),
|
||||
GATE(0, "pclk_otp", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(28), 4, GFLAGS),
|
||||
GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0, RK3328_CLKGATE_CON(15), 10, GFLAGS),
|
||||
|
@ -807,37 +807,42 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
GATE(0, "pclk_acodecphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 5, GFLAGS),
|
||||
GATE(PCLK_HDMIPHY, "pclk_hdmiphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 7, GFLAGS),
|
||||
GATE(0, "pclk_vdacphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 8, GFLAGS),
|
||||
GATE(0, "pclk_phy_niu", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 15, GFLAGS),
|
||||
GATE(0, "pclk_phy_niu", "pclk_phy_pre", 0, RK3328_CLKGATE_CON(15), 15, GFLAGS),
|
||||
|
||||
/* PD_MMC */
|
||||
MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc",
|
||||
MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "clk_sdmmc",
|
||||
RK3328_SDMMC_CON0, 1),
|
||||
MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc",
|
||||
MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "clk_sdmmc",
|
||||
RK3328_SDMMC_CON1, 1),
|
||||
|
||||
MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio",
|
||||
MMC(SCLK_SDIO_DRV, "sdio_drv", "clk_sdio",
|
||||
RK3328_SDIO_CON0, 1),
|
||||
MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio",
|
||||
MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio",
|
||||
RK3328_SDIO_CON1, 1),
|
||||
|
||||
MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc",
|
||||
MMC(SCLK_EMMC_DRV, "emmc_drv", "clk_emmc",
|
||||
RK3328_EMMC_CON0, 1),
|
||||
MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc",
|
||||
MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "clk_emmc",
|
||||
RK3328_EMMC_CON1, 1),
|
||||
|
||||
MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "sclk_sdmmc_ext",
|
||||
MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "clk_sdmmc_ext",
|
||||
RK3328_SDMMC_EXT_CON0, 1),
|
||||
MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "sclk_sdmmc_ext",
|
||||
MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "clk_sdmmc_ext",
|
||||
RK3328_SDMMC_EXT_CON1, 1),
|
||||
};
|
||||
|
||||
static const char *const rk3328_critical_clocks[] __initconst = {
|
||||
"aclk_bus",
|
||||
"aclk_bus_niu",
|
||||
"pclk_bus",
|
||||
"pclk_bus_niu",
|
||||
"hclk_bus",
|
||||
"hclk_bus_niu",
|
||||
"aclk_peri",
|
||||
"hclk_peri",
|
||||
"hclk_peri_niu",
|
||||
"pclk_peri",
|
||||
"pclk_peri_niu",
|
||||
"pclk_dbg",
|
||||
"aclk_core_niu",
|
||||
"aclk_gic400",
|
||||
|
@ -861,6 +866,20 @@ static const char *const rk3328_critical_clocks[] __initconst = {
|
|||
"aclk_rga_niu",
|
||||
"pclk_vio_h2p",
|
||||
"hclk_vio_h2p",
|
||||
"aclk_vio_niu",
|
||||
"hclk_vio_niu",
|
||||
"aclk_vop_niu",
|
||||
"hclk_vop_niu",
|
||||
"aclk_gpu_niu",
|
||||
"aclk_rkvdec_niu",
|
||||
"hclk_rkvdec_niu",
|
||||
"aclk_vpu_niu",
|
||||
"hclk_vpu_niu",
|
||||
"aclk_rkvenc_niu",
|
||||
"hclk_rkvenc_niu",
|
||||
"aclk_gmac_niu",
|
||||
"pclk_gmac_niu",
|
||||
"pclk_phy_niu",
|
||||
};
|
||||
|
||||
static void __init rk3328_clk_init(struct device_node *np)
|
||||
|
|
|
@ -57,6 +57,7 @@ static struct rockchip_pll_rate_table rk3399_pll_rates[] = {
|
|||
RK3036_PLL_RATE(1656000000, 1, 69, 1, 1, 1, 0),
|
||||
RK3036_PLL_RATE(1632000000, 1, 68, 1, 1, 1, 0),
|
||||
RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
|
||||
RK3036_PLL_RATE(1600000000, 3, 200, 1, 1, 1, 0),
|
||||
RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
|
||||
RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
|
||||
RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
|
||||
|
@ -670,7 +671,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|||
RK3399_CLKGATE_CON(9), 7, GFLAGS,
|
||||
&rk3399_uart3_fracmux),
|
||||
|
||||
COMPOSITE(0, "pclk_ddr", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED,
|
||||
COMPOSITE(PCLK_DDR, "pclk_ddr", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED,
|
||||
RK3399_CLKSEL_CON(6), 15, 1, MFLAGS, 8, 5, DFLAGS,
|
||||
RK3399_CLKGATE_CON(3), 4, GFLAGS),
|
||||
|
||||
|
@ -886,7 +887,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|||
RK3399_CLKGATE_CON(31), 8, GFLAGS),
|
||||
|
||||
/* sdio & sdmmc */
|
||||
COMPOSITE(0, "hclk_sd", mux_pll_src_cpll_gpll_p, 0,
|
||||
COMPOSITE(HCLK_SD, "hclk_sd", mux_pll_src_cpll_gpll_p, 0,
|
||||
RK3399_CLKSEL_CON(13), 15, 1, MFLAGS, 8, 5, DFLAGS,
|
||||
RK3399_CLKGATE_CON(12), 13, GFLAGS),
|
||||
GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_sd", 0,
|
||||
|
|
|
@ -57,6 +57,7 @@ static struct clk *rockchip_clk_register_branch(const char *name,
|
|||
struct clk_divider *div = NULL;
|
||||
const struct clk_ops *mux_ops = NULL, *div_ops = NULL,
|
||||
*gate_ops = NULL;
|
||||
int ret;
|
||||
|
||||
if (num_parents > 1) {
|
||||
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
|
||||
|
@ -74,8 +75,10 @@ static struct clk *rockchip_clk_register_branch(const char *name,
|
|||
|
||||
if (gate_offset >= 0) {
|
||||
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate)
|
||||
if (!gate) {
|
||||
ret = -ENOMEM;
|
||||
goto err_gate;
|
||||
}
|
||||
|
||||
gate->flags = gate_flags;
|
||||
gate->reg = base + gate_offset;
|
||||
|
@ -86,8 +89,10 @@ static struct clk *rockchip_clk_register_branch(const char *name,
|
|||
|
||||
if (div_width > 0) {
|
||||
div = kzalloc(sizeof(*div), GFP_KERNEL);
|
||||
if (!div)
|
||||
if (!div) {
|
||||
ret = -ENOMEM;
|
||||
goto err_div;
|
||||
}
|
||||
|
||||
div->flags = div_flags;
|
||||
div->reg = base + muxdiv_offset;
|
||||
|
@ -106,12 +111,19 @@ static struct clk *rockchip_clk_register_branch(const char *name,
|
|||
gate ? &gate->hw : NULL, gate_ops,
|
||||
flags);
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_composite;
|
||||
}
|
||||
|
||||
return clk;
|
||||
err_composite:
|
||||
kfree(div);
|
||||
err_div:
|
||||
kfree(gate);
|
||||
err_gate:
|
||||
kfree(mux);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
struct rockchip_clk_frac {
|
||||
|
@ -291,8 +303,10 @@ static struct clk *rockchip_clk_register_frac_branch(
|
|||
init.num_parents = child->num_parents;
|
||||
|
||||
mux_clk = clk_register(NULL, &frac_mux->hw);
|
||||
if (IS_ERR(mux_clk))
|
||||
if (IS_ERR(mux_clk)) {
|
||||
kfree(frac);
|
||||
return clk;
|
||||
}
|
||||
|
||||
rockchip_clk_add_lookup(ctx, mux_clk, child->id);
|
||||
|
||||
|
|
|
@ -537,6 +537,8 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node)
|
|||
init.parent_names = ®_data->parent;
|
||||
init.num_parents = 1;
|
||||
init.flags = 0;
|
||||
if (reg_data->flags & CLKF_SET_RATE_PARENT)
|
||||
init.flags |= CLK_SET_RATE_PARENT;
|
||||
init.name = kasprintf(GFP_KERNEL, "%s:%s:%04x:%d",
|
||||
node->parent->name, node->name,
|
||||
reg_data->offset, 0);
|
||||
|
|
|
@ -76,6 +76,11 @@ enum {
|
|||
#define CLKF_CORE (1 << 9)
|
||||
#define CLKF_J_TYPE (1 << 10)
|
||||
|
||||
/* CLKCTRL flags */
|
||||
#define CLKF_SW_SUP BIT(5)
|
||||
#define CLKF_HW_SUP BIT(6)
|
||||
#define CLKF_NO_IDLEST BIT(7)
|
||||
|
||||
#define CLK(dev, con, ck) \
|
||||
{ \
|
||||
.lk = { \
|
||||
|
@ -185,10 +190,6 @@ extern const struct omap_clkctrl_data am438x_clkctrl_data[];
|
|||
extern const struct omap_clkctrl_data dm814_clkctrl_data[];
|
||||
extern const struct omap_clkctrl_data dm816_clkctrl_data[];
|
||||
|
||||
#define CLKF_SW_SUP BIT(0)
|
||||
#define CLKF_HW_SUP BIT(1)
|
||||
#define CLKF_NO_IDLEST BIT(2)
|
||||
|
||||
typedef void (*ti_of_clk_init_cb_t)(void *, struct device_node *);
|
||||
|
||||
struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw,
|
||||
|
|
|
@ -57,6 +57,14 @@
|
|||
#define UNIPHIER_PRO4_SYS_CLK_USB3(idx, ch) \
|
||||
UNIPHIER_CLK_GATE("usb3" #ch, (idx), NULL, 0x2104, 16 + (ch))
|
||||
|
||||
#define UNIPHIER_PRO4_SYS_CLK_AIO(idx) \
|
||||
UNIPHIER_CLK_FACTOR("aio-io200m", -1, "spll", 1, 8), \
|
||||
UNIPHIER_CLK_GATE("aio", (idx), "aio-io200m", 0x2104, 13)
|
||||
|
||||
#define UNIPHIER_PRO5_SYS_CLK_AIO(idx) \
|
||||
UNIPHIER_CLK_FACTOR("aio-io200m", -1, "spll", 1, 12), \
|
||||
UNIPHIER_CLK_GATE("aio", (idx), "aio-io200m", 0x2104, 13)
|
||||
|
||||
#define UNIPHIER_LD11_SYS_CLK_AIO(idx) \
|
||||
UNIPHIER_CLK_FACTOR("aio-io200m", -1, "spll", 1, 10), \
|
||||
UNIPHIER_CLK_GATE("aio", (idx), "aio-io200m", 0x2108, 0)
|
||||
|
@ -94,16 +102,22 @@ const struct uniphier_clk_data uniphier_pro4_sys_clk_data[] = {
|
|||
UNIPHIER_CLK_FACTOR("upll", -1, "ref", 288, 25), /* 288 MHz */
|
||||
UNIPHIER_CLK_FACTOR("a2pll", -1, "upll", 256, 125), /* 589.824 MHz */
|
||||
UNIPHIER_CLK_FACTOR("vpll27a", -1, "ref", 270, 25), /* 270 MHz */
|
||||
UNIPHIER_CLK_FACTOR("gpll", -1, "ref", 10, 1), /* 250 MHz */
|
||||
UNIPHIER_CLK_FACTOR("uart", 0, "a2pll", 1, 8),
|
||||
UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 32),
|
||||
UNIPHIER_LD4_SYS_CLK_NAND(2),
|
||||
UNIPHIER_LD4_SYS_CLK_SD,
|
||||
UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12),
|
||||
UNIPHIER_PRO4_SYS_CLK_ETHER(6),
|
||||
UNIPHIER_CLK_GATE("ether-gb", 7, "gpll", 0x2104, 5),
|
||||
UNIPHIER_LD4_SYS_CLK_STDMAC(8), /* HSC, MIO, RLE */
|
||||
UNIPHIER_CLK_GATE("ether-phy", 10, "ref", 0x2260, 0),
|
||||
UNIPHIER_PRO4_SYS_CLK_GIO(12), /* Ether, SATA, USB3 */
|
||||
UNIPHIER_PRO4_SYS_CLK_USB3(14, 0),
|
||||
UNIPHIER_PRO4_SYS_CLK_USB3(15, 1),
|
||||
UNIPHIER_CLK_GATE("sata0", 28, NULL, 0x2104, 18),
|
||||
UNIPHIER_CLK_GATE("sata1", 29, NULL, 0x2104, 19),
|
||||
UNIPHIER_PRO4_SYS_CLK_AIO(40),
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
|
@ -132,6 +146,8 @@ const struct uniphier_clk_data uniphier_pro5_sys_clk_data[] = {
|
|||
UNIPHIER_PRO4_SYS_CLK_GIO(12), /* PCIe, USB3 */
|
||||
UNIPHIER_PRO4_SYS_CLK_USB3(14, 0),
|
||||
UNIPHIER_PRO4_SYS_CLK_USB3(15, 1),
|
||||
UNIPHIER_CLK_GATE("pcie", 24, NULL, 0x2108, 2),
|
||||
UNIPHIER_PRO5_SYS_CLK_AIO(40),
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
|
@ -149,6 +165,8 @@ const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = {
|
|||
/* The document mentions 0x2104 bit 18, but not functional */
|
||||
UNIPHIER_CLK_GATE("usb30-phy", 16, NULL, 0x2104, 19),
|
||||
UNIPHIER_CLK_GATE("usb31-phy", 20, NULL, 0x2104, 20),
|
||||
UNIPHIER_CLK_GATE("sata0", 28, NULL, 0x2104, 22),
|
||||
UNIPHIER_PRO5_SYS_CLK_AIO(40),
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
|
@ -205,6 +223,7 @@ const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = {
|
|||
UNIPHIER_CLK_GATE("usb30", 14, NULL, 0x210c, 14),
|
||||
UNIPHIER_CLK_GATE("usb30-phy0", 16, NULL, 0x210c, 12),
|
||||
UNIPHIER_CLK_GATE("usb30-phy1", 17, NULL, 0x210c, 13),
|
||||
UNIPHIER_CLK_GATE("pcie", 24, NULL, 0x210c, 4),
|
||||
UNIPHIER_LD11_SYS_CLK_AIO(40),
|
||||
UNIPHIER_LD11_SYS_CLK_EVEA(41),
|
||||
UNIPHIER_LD11_SYS_CLK_EXIV(42),
|
||||
|
@ -233,6 +252,8 @@ const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = {
|
|||
UNIPHIER_LD20_SYS_CLK_SD,
|
||||
UNIPHIER_LD11_SYS_CLK_NAND(2),
|
||||
UNIPHIER_LD11_SYS_CLK_EMMC(4),
|
||||
UNIPHIER_CLK_GATE("ether0", 6, NULL, 0x210c, 9),
|
||||
UNIPHIER_CLK_GATE("ether1", 7, NULL, 0x210c, 10),
|
||||
UNIPHIER_CLK_GATE("usb30", 12, NULL, 0x210c, 4), /* =GIO0 */
|
||||
UNIPHIER_CLK_GATE("usb31-0", 13, NULL, 0x210c, 5), /* =GIO1 */
|
||||
UNIPHIER_CLK_GATE("usb31-1", 14, NULL, 0x210c, 6), /* =GIO1-1 */
|
||||
|
@ -241,6 +262,10 @@ const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = {
|
|||
UNIPHIER_CLK_GATE("usb30-phy2", 18, NULL, 0x210c, 20),
|
||||
UNIPHIER_CLK_GATE("usb31-phy0", 20, NULL, 0x210c, 17),
|
||||
UNIPHIER_CLK_GATE("usb31-phy1", 21, NULL, 0x210c, 19),
|
||||
UNIPHIER_CLK_GATE("pcie", 24, NULL, 0x210c, 3),
|
||||
UNIPHIER_CLK_GATE("sata0", 28, NULL, 0x210c, 7),
|
||||
UNIPHIER_CLK_GATE("sata1", 29, NULL, 0x210c, 8),
|
||||
UNIPHIER_CLK_GATE("sata-phy", 30, NULL, 0x210c, 21),
|
||||
/* CPU gears */
|
||||
UNIPHIER_CLK_DIV4("cpll", 2, 3, 4, 8),
|
||||
UNIPHIER_CLK_DIV4("spll", 2, 3, 4, 8),
|
||||
|
|
|
@ -193,7 +193,6 @@
|
|||
#define HCLK_VPU_PRE 324
|
||||
#define HCLK_VIO_PRE 325
|
||||
#define HCLK_VPU 326
|
||||
#define HCLK_VIO 327
|
||||
#define HCLK_BUS_PRE 328
|
||||
#define HCLK_PERI_PRE 329
|
||||
#define HCLK_H264 330
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* clk-da8xx-cfgchip - TI DaVinci DA8xx CFGCHIP clock driver
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_PLATFORM_DATA_CLK_DA8XX_CFGCHIP_H__
|
||||
#define __LINUX_PLATFORM_DATA_CLK_DA8XX_CFGCHIP_H__
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/**
|
||||
* da8xx_cfgchip_clk_platform_data
|
||||
* @cfgchip: CFGCHIP syscon regmap
|
||||
*/
|
||||
struct da8xx_cfgchip_clk_platform_data {
|
||||
struct regmap *cfgchip;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_PLATFORM_DATA_CLK_DA8XX_CFGCHIP_H__ */
|
|
@ -0,0 +1,21 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PLL clock driver for TI Davinci SoCs
|
||||
*
|
||||
* Copyright (C) 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_PLATFORM_DATA_CLK_DAVINCI_PLL_H__
|
||||
#define __LINUX_PLATFORM_DATA_CLK_DAVINCI_PLL_H__
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/**
|
||||
* davinci_pll_platform_data
|
||||
* @cfgchip: CFGCHIP syscon regmap
|
||||
*/
|
||||
struct davinci_pll_platform_data {
|
||||
struct regmap *cfgchip;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_PLATFORM_DATA_CLK_DAVINCI_PLL_H__ */
|
Loading…
Reference in New Issue