This patch set is to add full platform dt clock support for mx51 babbage, based on Jason's basic-mx51-dt patch. All mx51 non-dt clocks in clock-mx51-mx53.c are translated to dt ones.
Shawn Guo (5): arm/dts: babbage: add all available clock nodes arm/mxc: add clk member 'rate' to ease dt fixed-clock support arm/dt: mx51: dynamically add clocks per dt nodes arm/dt: mx5: change timer init function to dt clock way of/clock: eliminate function __of_clk_get_from_provider
arch/arm/boot/dts/babbage.dts | 495 +++++++++++- arch/arm/mach-mx5/board-dt.c | 9 +- arch/arm/mach-mx5/clock-mx51-mx53.c | 1401 +++++++++++++++++++++++++++++++- arch/arm/plat-mxc/include/mach/clock.h | 4 + drivers/of/clock.c | 23 +- 5 files changed, 1886 insertions(+), 46 deletions(-)
Regards, Shawn
The patch is to add all available dt clock nodes for babbage board. It sticks to the clock name used in clock-mx51-mx53.c, so that everything gets consistent to Reference Manual. For example, the numbering in clock name usually starts from 1, while 'reg' property numbering starts from 0 to easy clock binding.
Besides the generally used clock bindings, the following properties are proposed in this patch.
* clock-source This property is added to reflect the parent clock.
* clock-depend The mxc 'struct clk' has the member 'secondary' to refer to the clock that the 'clk' has dependency on. This 'secondary' clock needs to be turned on whenever the 'clk' is turned on. This clock-depend property is defined to reflect this 'secondary' clock.
Signed-off-by: Shawn Guo shawn.guo@linaro.org --- arch/arm/boot/dts/babbage.dts | 495 ++++++++++++++++++++++++++++++++++++++++- 1 files changed, 485 insertions(+), 10 deletions(-)
diff --git a/arch/arm/boot/dts/babbage.dts b/arch/arm/boot/dts/babbage.dts index ab87a1b..378cd7d 100644 --- a/arch/arm/boot/dts/babbage.dts +++ b/arch/arm/boot/dts/babbage.dts @@ -47,24 +47,499 @@ #address-cells = <1>; #size-cells = <0>;
- uart0_clk: uart0 { - compatible = "clock"; + ckil_clk: clkil { + compatible = "fixed-clock"; + #frequency-cells = <1>; + clock-outputs = "clil"; + clock-frequency = <32768>; + }; + + ckih_clk: ckih { + compatible = "fixed-clock"; + #frequency-cells = <1>; + clock-outputs = "ckih"; + clock-frequency = <22579200>; + }; + + ckih2_clk: ckih2 { + compatible = "fixed-clock"; + #frequency-cells = <1>; + clock-outputs = "ckih2"; + clock-frequency = <0>; + }; + + osc_clk: soc { + compatible = "fixed-clock"; + #frequency-cells = <1>; + clock-outputs = "osc"; + clock-frequency = <24000000>; + }; + + pll1_main_clk: pll1_main { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "pll1_main"; + clock-source = <&osc_clk>; + }; + + pll1_sw_clk: pll_switch@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "pll1_sw"; + clock-source = <&pll1_main_clk>; + }; + + pll2_sw_clk: pll_switch@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "pll2_sw"; + clock-source = <&osc_clk>; + }; + + pll3_sw_clk: pll_switch@2 { + compatible = "fsl,mxc-clock"; + reg = <2>; + clock-outputs = "pll3_sw"; + clock-source = <&osc_clk>; + }; + + lp_apm_clk: lp_apm { + compatible = "fsl,mxc-clock"; + clock-outputs = "lp_apm"; + clock-source = <&osc_clk>; + }; + + ipg_per_clk: ipg_per { + compatible = "fsl,mxc-clock"; + clock-outputs = "ipg_per"; + clock-source = <&lp_apm_clk>; + }; + + periph_apm_clk: periph_apm { + compatible = "fsl,mxc-clock"; + clock-outputs = "periph_apm"; + clock-source = <&pll1_sw_clk>; + }; + + cpu_clk: cpu { + compatible = "fsl,mxc-clock"; + clock-outputs = "cpu"; + clock-source = <&pll1_sw_clk>; + }; + + ddr_hf_clk: ddr_hf { + compatible = "fsl,mxc-clock"; + clock-outputs = "ddr_hf"; + clock-source = <&pll1_sw_clk>; + }; + + ddr_clk: ddr { + compatible = "fsl,mxc-clock"; + clock-outputs = "ddr"; + clock-source = <&ddr_hf_clk>; + }; + + emi_fast_clk: emi_fast { + compatible = "fsl,mxc-clock"; + clock-outputs = "emi_fast"; + clock-source = <&ddr_clk>; + }; + + main_bus_clk: main_bus { + compatible = "fsl,mxc-clock"; + clock-outputs = "main_bus"; + clock-source = <&pll2_sw_clk>; + }; + + emi_slow_clk: emi_slow { + compatible = "fsl,mxc-clock"; + clock-outputs = "emi_slow"; + clock-source = <&pll2_sw_clk>; + }; + + ahb_clk: ahb { + compatible = "fsl,mxc-clock"; + clock-outputs = "ahb"; + clock-source = <&main_bus_clk>; + }; + + ipg_clk: ipg { + compatible = "fsl,mxc-clock"; + clock-outputs = "ipg"; + clock-source = <&ahb_clk>; + }; + + spba_clk: spba { + compatible = "fsl,mxc-clock"; + clock-outputs = "spba"; + clock-source = <&ipg_clk>; + }; + + iim_clk: iim { + compatible = "fsl,mxc-clock"; + clock-outputs = "iim"; + clock-source = <&ipg_clk>; + }; + + ahb_max_clk: ahb_max { + compatible = "fsl,mxc-clock"; + clock-outputs = "ahb_max"; + clock-source = <&ahb_clk>; + }; + + aips_tz1_clk: aips_tz@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "aips_tz1"; + clock-source = <&ahb_clk>; + clock-depend = <&ahb_max_clk>; + }; + + aips_tz2_clk: aips_tz@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "aips_tz2"; + clock-source = <&ahb_clk>; + clock-depend = <&ahb_max_clk>; + }; + + ahbmux1_clk: ahbmux1 { + compatible = "fsl,mxc-clock"; + clock-outputs = "ahbmux1"; + clock-source = <&ahb_clk>; + clock-depend = <&ahb_max_clk>; + }; + + gpt_ipg_clk: gpt_ipg { + compatible = "fsl,mxc-clock"; + clock-outputs = "gpt_ipg"; + clock-source = <&ipg_clk>; + }; + + gpt_clk: gpt { + compatible = "fsl,mxc-clock"; + clock-outputs = "gpt"; + clock-source = <&ipg_clk>; + clock-depend = <&gpt_ipg_clk>; + }; + + gpt_32k_clk: gpt_32k { + compatible = "fsl,mxc-clock"; + clock-outputs = "gpt_32k"; + clock-source = <&ckil_clk>; + }; + + uart1_ipg_clk: uart_ipg@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "uart1_ipg"; + clock-source = <&ipg_clk>; + clock-depend = <&aips_tz1_clk>; + }; + + uart2_ipg_clk: uart_ipg@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "uart2_ipg"; + clock-source = <&ipg_clk>; + clock-depend = <&aips_tz1_clk>; + }; + + uart3_ipg_clk: uart_ipg@2 { + compatible = "fsl,mxc-clock"; + reg = <2>; + clock-outputs = "uart3_ipg"; + clock-source = <&ipg_clk>; + clock-depend = <&spba_clk>; + }; + + uart_root_clk: uart_root { + compatible = "fsl,mxc-clock"; + clock-outputs = "uart_root"; + clock-source = <&pll2_sw_clk>; + }; + + uart1_clk: uart@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; clock-outputs = "imx-uart.0"; + clock-source = <&uart_root_clk>; + clock-depends = <&uart1_ipg_clk>; };
- uart1_clk: uart1 { - compatible = "clock"; + uart2_clk: uart@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; clock-outputs = "imx-uart.1"; + clock-source = <&uart_root_clk>; + clock-depends = <&uart2_ipg_clk>; };
- uart2_clk: uart2 { - compatible = "clock"; + uart3_clk: uart@2 { + compatible = "fsl,mxc-clock"; + reg = <2>; clock-outputs = "imx-uart.2"; + clock-source = <&uart_root_clk>; + clock-depends = <&uart3_ipg_clk>; };
fec_clk: fec { - compatible = "clock"; + compatible = "fsl,mxc-clock"; clock-outputs = "fec.0"; + clock-source = <&ipg_clk>; + }; + + pwm1_clk: pwm@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "mxc-pwm.0"; + clock-source = <&ipg_clk>; + }; + + pwm2_clk: pwm@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "mxc-pwm.1"; + clock-source = <&ipg_clk>; + }; + + i2c1_clk: i2c@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "imx-i2c.0"; + clock-source = <&ipg_clk>; + }; + + i2c2_clk: i2c@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "imx-i2c.1"; + clock-source = <&ipg_clk>; + }; + + hsi2c_clk: i2c@2 { + compatible = "fsl,mxc-clock"; + reg = <2>; + clock-outputs = "imx-i2c.2"; + clock-source = <&ipg_clk>; + }; + + nfc_clk: nfc { + compatible = "fsl,mxc-clock"; + clock-outputs = "mxs_nand"; + clock-source = <&emi_slow_clk>; + }; + + ssi1_ipg_clk: ssi_ipg@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "ssi1_ipg"; + clock-source = <&ipg_clk>; + }; + + ssi2_ipg_clk: ssi_ipg@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "ssi2_ipg"; + clock-source = <&ipg_clk>; + }; + + ssi3_ipg_clk: ssi_ipg@2 { + compatible = "fsl,mxc-clock"; + reg = <2>; + clock-outputs = "ssi3_ipg"; + clock-source = <&ipg_clk>; + }; + + ssi1_clk: ssi@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "imx-ssi.0"; + clock-source = <&pll3_sw_clk>; + clock-dpends = <&ssi1_ipg_clk>; + }; + + ssi2_clk: ssi@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "imx-ssi.1"; + clock-source = <&pll3_sw_clk>; + clock-dpends = <&ssi2_ipg_clk>; + }; + + ssi3_clk: ssi@2 { + compatible = "fsl,mxc-clock"; + reg = <2>; + clock-outputs = "imx-ssi.2"; + clock-source = <&pll3_sw_clk>; + clock-dpends = <&ssi3_ipg_clk>; + }; + + cspi_ipg_clk: cspi_ipg { + compatible = "fsl,mxc-clock"; + clock-outputs = "cspi_ipg"; + clock-source = <&ipg_clk>; + clock-dpends = <&aips_tz2_clk>; + }; + + cspi_clk: cspi { + compatible = "fsl,mxc-clock"; + clock-outputs = "imx51-cspi.0"; + clock-source = <&ipg_clk>; + clock-dpends = <&cspi_ipg_clk>; + }; + + ecspi1_ipg_clk: ecspi_ipg@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "ecspi1_ipg"; + clock-source = <&ipg_clk>; + clock-dpends = <&spba_clk>; + }; + + ecspi2_ipg_clk: ecspi_ipg@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "ecspi2_ipg"; + clock-source = <&ipg_clk>; + clock-dpends = <&aips_tz2_clk>; + }; + + ecspi_main_clk: ecspi_main { + compatible = "fsl,mxc-clock"; + clock-outputs = "ecspi_main"; + clock-source = <&pll3_sw_clk>; + }; + + ecspi1_clk: ecspi@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "imx51-ecspi.0"; + clock-source = <&ecspi_main_clk>; + clock-dpends = <&ecspi1_ipg_clk>; + }; + + ecspi2_clk: ecspi@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "imx51-ecspi.1"; + clock-source = <&ecspi_main_clk>; + clock-dpends = <&ecspi2_ipg_clk>; + }; + + sdma_clk: sdma { + compatible = "fsl,mxc-clock"; + clock-outputs = "imx-sdma"; + clock-source = <&ahb_clk>; + }; + + esdhc1_ipg_clk: esdhc_ipg@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "esdhc1_ipg"; + clock-source = <&ipg_clk>; + }; + + esdhc2_ipg_clk: esdhc_ipg@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "esdhc2_ipg"; + clock-source = <&ipg_clk>; + }; + + esdhc1_clk: esdhc@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "sdhci-esdhc-imx.0"; + clock-source = <&pll2_sw_clk>; + clock-dpends = <&esdhc1_ipg_clk>; + }; + + esdhc2_clk: esdhc@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "sdhci-esdhc-imx.1"; + clock-source = <&pll2_sw_clk>; + clock-dpends = <&esdhc2_ipg_clk>; + }; + + mipi_esc_clk: mipi_esc { + compatible = "fsl,mxc-clock"; + clock-outputs = "mipi_esc"; + clock-dpends = <&pll2_sw_clk>; + }; + + mipi_hsc1_clk: mipi_hsc@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "mipi_hsc1"; + clock-source = <&mipi_hsc2_clk>; + clock-dpends = <&pll2_sw_clk>; + }; + + mipi_hsc2_clk: mipi_hsc@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "mipi_hsc2"; + clock-source = <&mipi_esc_clk>; + clock-dpends = <&pll2_sw_clk>; + }; + + ipu_sec_clk: ipu_sec { + compatible = "fsl,mxc-clock"; + clock-outputs = "ipu_sec"; + clock-source = <&emi_fast_clk>; + clock-dpends = <&ahbmux1_clk>; + }; + + ipu_clk: ipu { + compatible = "fsl,mxc-clock"; + clock-outputs = "imx-ipuv3"; + clock-source = <&ahb_clk>; + clock-dpends = <&ipu_sec_clk>; + }; + + ipu_di0_clk: ipu_di@0 { + compatible = "fsl,mxc-clock"; + reg = <0>; + clock-outputs = "imx-ipuv3-di0"; + clock-source = <&pll3_sw_clk>; + }; + + ipu_di1_clk: ipu_di@1 { + compatible = "fsl,mxc-clock"; + reg = <1>; + clock-outputs = "imx-ipuv3-di1"; + clock-source = <&pll3_sw_clk>; + }; + + mipi_hsp_clk: mipi_hsp { + compatible = "fsl,mxc-clock"; + clock-outputs = "mipi_hsp"; + clock-source = <&ipu_clk>; + clock-dpends = <&mipi_hsc1_clk>; + }; + + usboh3_clk: usboh3 { + compatible = "fsl,mxc-clock"; + clock-outputs = "mxc-ehci"; + clock-source = <&pll2_sw_clk>; + }; + + usb_ahb_clk: usb_ahb { + compatible = "fsl,mxc-clock"; + clock-outputs = "mxc-ehci-ahb"; + clock-source = <&ipg_clk>; + }; + + usb_phy1_clk: usb_phy1 { + compatible = "fsl,mxc-clock"; + clock-outputs = "usb_phy1"; + clock-source = <&pll3_sw_clk>; + }; + + dummy_clk: dummy { + compatible = "fsl,mxc-clock"; }; };
@@ -79,7 +554,7 @@ reg = <0xbc000 0x1000>; interrupts = <0x1f>; fsl,has-rts-cts; - uart-clock = <&uart0_clk>, "uart"; + uart-clock = <&uart1_clk>, "uart"; };
imx-uart@c0000 { @@ -87,7 +562,7 @@ reg = <0xc0000 0x1000>; interrupts = <0x20>; fsl,has-rts-cts; - uart-clock = <&uart1_clk>, "uart"; + uart-clock = <&uart2_clk>, "uart"; }; };
@@ -102,7 +577,7 @@ reg = <0xc000 0x1000>; interrupts = <0x21>; fsl,has-rts-cts; - uart-clock = <&uart2_clk>, "uart"; + uart-clock = <&uart3_clk>, "uart"; }; };
This new member is not necessary to support dt clock, but it can simplified the code a lot in terms of those fixed rate clocks.
Signed-off-by: Shawn Guo shawn.guo@linaro.org --- arch/arm/plat-mxc/include/mach/clock.h | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/arch/arm/plat-mxc/include/mach/clock.h b/arch/arm/plat-mxc/include/mach/clock.h index 753a598..e688b49 100644 --- a/arch/arm/plat-mxc/include/mach/clock.h +++ b/arch/arm/plat-mxc/include/mach/clock.h @@ -38,6 +38,10 @@ struct clk { /* Register address for clock's enable/disable control. */ void __iomem *enable_reg; u32 flags; +#ifdef CONFIG_OF + /* clock rate used by fixed-clock */ + unsigned long rate; +#endif /* get the current clock rate (always a fresh value) */ unsigned long (*get_rate) (struct clk *); /* Function ptr to set the clock to a new rate. The rate must match a
This patch is to change the static clock creating and registering to the dynamic way, which scans dt clock nodes, associate clk with device_node, and then add them to clkdev accordingly.
It's a pretty straight translation from non-dt clock code to dt one, and it does not really change any actual clock code.
Signed-off-by: Shawn Guo shawn.guo@linaro.org --- arch/arm/mach-mx5/clock-mx51-mx53.c | 1401 ++++++++++++++++++++++++++++++++++- 1 files changed, 1387 insertions(+), 14 deletions(-)
diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c index dedb7f9..c3ec7f6 100644 --- a/arch/arm/mach-mx5/clock-mx51-mx53.c +++ b/arch/arm/mach-mx5/clock-mx51-mx53.c @@ -49,6 +49,30 @@ static struct clk emi_fast_clk; static struct clk ipu_clk; static struct clk mipi_hsc1_clk;
+#ifdef CONFIG_OF +/* + * The pointers are defined to save the references to the clocks + * dynamically created, and then could be used to replace those + * static references in non-dt clock code. + */ +static struct clk *osc_clk_dt; +static struct clk *pll1_main_clk_dt; +static struct clk *pll1_sw_clk_dt; +static struct clk *pll2_sw_clk_dt; +static struct clk *pll3_sw_clk_dt; +static struct clk *lp_apm_clk_dt; +static struct clk *periph_apm_clk_dt; +static struct clk *main_bus_clk_dt; +static struct clk *ipg_clk_dt; +static struct clk *ipg_per_clk_dt; +static struct clk *cpu_clk_dt; +static struct clk *iim_clk_dt; +static struct clk *usboh3_clk_dt; +static struct clk *usb_phy1_clk_dt; +static struct clk *esdhc1_clk_dt; +static struct clk *esdhc2_clk_dt; +#endif + #define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */
/* calculate best pre and post dividers to get the required divider */ @@ -163,10 +187,18 @@ static inline void __iomem *_mx53_get_pll_base(struct clk *pll) return NULL; }
+#ifdef CONFIG_OF +static void __iomem *dt_mx51_get_pll_base(struct clk *pll); +#endif + static inline void __iomem *_get_pll_base(struct clk *pll) { if (cpu_is_mx51()) +#ifdef CONFIG_OF + return dt_mx51_get_pll_base(pll); +#else return _mx51_get_pll_base(pll); +#endif else return _mx53_get_pll_base(pll); } @@ -1037,6 +1069,22 @@ static unsigned long clk_##name##_get_rate(struct clk *clk) \ (pred + 1) * (podf + 1)); \ }
+#ifdef CONFIG_OF +#define CLK_SET_PARENT(name, nr, bitsname) \ +static int clk_##name##_set_parent(struct clk *clk, struct clk *parent) \ +{ \ + u32 reg, mux; \ + \ + mux = _get_mux(parent, pll1_sw_clk_dt, pll2_sw_clk_dt, \ + pll3_sw_clk_dt, lp_apm_clk_dt); \ + reg = __raw_readl(MXC_CCM_CSCMR##nr) & \ + ~MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_MASK; \ + reg |= mux << MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_OFFSET; \ + __raw_writel(reg, MXC_CCM_CSCMR##nr); \ + \ + return 0; \ +} +#else #define CLK_SET_PARENT(name, nr, bitsname) \ static int clk_##name##_set_parent(struct clk *clk, struct clk *parent) \ { \ @@ -1051,6 +1099,7 @@ static int clk_##name##_set_parent(struct clk *clk, struct clk *parent) \ \ return 0; \ } +#endif
#define CLK_SET_RATE(name, nr, bitsname) \ static int clk_##name##_set_rate(struct clk *clk, unsigned long rate) \ @@ -1439,37 +1488,1361 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, return 0; }
+/* + * Dynamically create and register clks per dt nodes + */ #ifdef CONFIG_OF -static struct clk *mx5_dt_clk_get(struct device_node *np, - const char *output_id, void *data) +static inline void __iomem *dt_mx51_get_pll_base(struct clk *pll) +{ + if (pll == pll1_main_clk_dt) + return MX51_DPLL1_BASE; + else if (pll == pll2_sw_clk_dt) + return MX51_DPLL2_BASE; + else if (pll == pll3_sw_clk_dt) + return MX51_DPLL3_BASE; + else + BUG(); + + return NULL; +} + +static unsigned long dt_clk_pll1_sw_get_rate(struct clk *clk) +{ + u32 reg, div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CCSR); + + if (clk->parent == pll2_sw_clk_dt) { + div = ((reg & MXC_CCM_CCSR_PLL2_PODF_MASK) >> + MXC_CCM_CCSR_PLL2_PODF_OFFSET) + 1; + } else if (clk->parent == pll3_sw_clk_dt) { + div = ((reg & MXC_CCM_CCSR_PLL3_PODF_MASK) >> + MXC_CCM_CCSR_PLL3_PODF_OFFSET) + 1; + } else + div = 1; + return parent_rate / div; +} + +static int dt_clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, step; + + reg = __raw_readl(MXC_CCM_CCSR); + + /* When switching from pll_main_clk to a bypass clock, first select a + * multiplexed clock in 'step_sel', then shift the glitchless mux + * 'pll1_sw_clk_sel'. + * + * When switching back, do it in reverse order + */ + if (parent == pll1_main_clk_dt) { + /* Switch to pll1_main_clk */ + reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + /* step_clk mux switched to lp_apm, to save power. */ + reg = __raw_readl(MXC_CCM_CCSR); + reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK; + reg |= (MXC_CCM_CCSR_STEP_SEL_LP_APM << + MXC_CCM_CCSR_STEP_SEL_OFFSET); + } else { + if (parent == lp_apm_clk_dt) { + step = MXC_CCM_CCSR_STEP_SEL_LP_APM; + } else if (parent == pll2_sw_clk_dt) { + step = MXC_CCM_CCSR_STEP_SEL_PLL2_DIVIDED; + } else if (parent == pll3_sw_clk_dt) { + step = MXC_CCM_CCSR_STEP_SEL_PLL3_DIVIDED; + } else + return -EINVAL; + + reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK; + reg |= (step << MXC_CCM_CCSR_STEP_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CCSR); + /* Switch to step_clk */ + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + } + __raw_writel(reg, MXC_CCM_CCSR); + return 0; +} + +static int dt_clk_pll2_sw_set_parent(struct clk *clk, struct clk *parent) { - return data; + u32 reg; + + reg = __raw_readl(MXC_CCM_CCSR); + + if (parent == pll2_sw_clk_dt) + reg &= ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL; + else + reg |= MXC_CCM_CCSR_PLL2_SW_CLK_SEL; + + __raw_writel(reg, MXC_CCM_CCSR); + return 0; }
-static __init void mx5_dt_scan_clks(void) +static int dt_clk_lp_apm_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + if (parent == osc_clk_dt) + reg = __raw_readl(MXC_CCM_CCSR) & ~MXC_CCM_CCSR_LP_APM_SEL; + else + return -EINVAL; + + __raw_writel(reg, MXC_CCM_CCSR); + + return 0; +} + +static int dt_clk_periph_apm_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + int i = 0; + + mux = _get_mux(parent, pll1_sw_clk_dt, pll3_sw_clk_dt, lp_apm_clk_dt, NULL); + + reg = __raw_readl(MXC_CCM_CBCMR) & ~MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + + /* Wait for lock */ + do { + reg = __raw_readl(MXC_CCM_CDHIPR); + if (!(reg & MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY)) + break; + + udelay(1); + } while (++i < MAX_DPLL_WAIT_TRIES); + + if (i == MAX_DPLL_WAIT_TRIES) { + pr_err("MX5: Set parent for periph_apm clock failed\n"); + return -EINVAL; + } + + return 0; +} + +static int dt_clk_main_bus_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CBCDR); + + if (parent == pll2_sw_clk_dt) + reg &= ~MXC_CCM_CBCDR_PERIPH_CLK_SEL; + else if (parent == periph_apm_clk_dt) + reg |= MXC_CCM_CBCDR_PERIPH_CLK_SEL; + else + return -EINVAL; + + __raw_writel(reg, MXC_CCM_CBCDR); + + return 0; +} + +static int dt_clk_ipg_per_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CBCMR); + + reg &= ~MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; + reg &= ~MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; + + if (parent == ipg_clk_dt) + reg |= MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; + else if (parent == lp_apm_clk_dt) + reg |= MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; + else if (parent != main_bus_clk_dt) + return -EINVAL; + + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static int dt_clk_usb_phy1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL; + + if (parent == pll3_sw_clk_dt) + reg |= 1 << MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET; + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +#define ALLOC_CLK_LOOKUP() \ + struct clk_lookup *cl; \ + struct clk *clk; \ + const char *dev_id; \ + int ret; \ + \ + do { \ + cl = kzalloc(sizeof(*cl) + sizeof(*clk), GFP_KERNEL); \ + if (!cl) \ + return -ENOMEM; \ + clk = (struct clk *) (cl + 1); \ + \ + dev_id = of_get_property(node, \ + "clock-outputs", NULL); \ + if (!dev_id) { \ + ret = -EINVAL; \ + goto out_kfree; \ + } \ + \ + clk->parent = mx5_get_source_clk(node); \ + clk->secondary = mx5_get_source_clk(node); \ + } while (0) + +#define ADD_CLK_LOOKUP() \ + do { \ + node->data = clk; \ + \ + cl->dev_id = dev_id; \ + cl->clk = clk; \ + clkdev_add(cl); \ + \ + return 0; \ + \ + out_kfree: \ + kfree(cl); \ + return ret; \ + } while (0) + +static unsigned long get_fixed_clk_rate(struct clk *clk) +{ + return clk->rate; +} + +static __init int mx5_scan_fixed_clks(void) { struct device_node *node; + struct clk_lookup *cl; struct clk *clk; - const char *id; - int rc; + const __be32 *rate; + const char *dev_id; + int ret = 0; + + for_each_compatible_node(node, NULL, "fixed-clock") { + cl = kzalloc(sizeof(*cl) + sizeof(*clk), GFP_KERNEL); + if (!cl) { + ret = -ENOMEM; + break; + } + clk = (struct clk *) (cl + 1);
- for_each_compatible_node(node, NULL, "clock") { - id = of_get_property(node, "clock-outputs", NULL); - if (!id) + dev_id = of_get_property(node, "clock-outputs", NULL); + if (!dev_id) { + kfree(cl); continue; + }
- clk = clk_get_sys(id, NULL); - if (IS_ERR(clk)) + rate = of_get_property(node, "clock-frequency", NULL); + if (!rate) { + kfree(cl); continue; + } + clk->rate = be32_to_cpu(*rate); + clk->get_rate = get_fixed_clk_rate; + + if (!strcmp(node->name, "osc")) + osc_clk_dt = clk;
- rc = of_clk_add_provider(node, mx5_dt_clk_get, clk); - if (rc) - pr_err("error adding fixed clk %s\n", node->name); + node->data = clk; + + cl->dev_id = dev_id; + cl->clk = clk; + clkdev_add(cl); } + + return ret; +} + +static struct clk *mx5_prop_name_to_clk(struct device_node *node, + const char *prop_name) +{ + struct device_node *provnode; + struct clk *clk; + const void *prop; + u32 provhandle; + + prop = of_get_property(node, prop_name, NULL); + if (!prop) + return NULL; + provhandle = be32_to_cpup(prop); + + provnode = of_find_node_by_phandle(provhandle); + if (!provnode) + return NULL; + + clk = provnode->data; + + of_node_put(provnode); + + return clk; +} + +static inline struct clk *mx5_get_source_clk(struct device_node *node) +{ + return mx5_prop_name_to_clk(node, "clock-source"); +} + +static inline struct clk *mx5_get_depend_clk(struct device_node *node) +{ + return mx5_prop_name_to_clk(node, "clock-depend"); +} + +static __init int mx5_add_dummy_clk(struct device_node *node) +{ + struct clk_lookup *cl; + struct clk *clk; + + cl = kzalloc(sizeof(*cl) + sizeof(*clk), GFP_KERNEL); + if (!cl) + return -ENOMEM; + clk = (struct clk *) (cl + 1); + + node->data = clk; + + cl->clk = clk; + clkdev_add(cl); + + return 0; +} + +static __init int mx5_add_usb_phy1_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR2; + clk->enable_shift = MXC_CCM_CCGRx_CG0_OFFSET; + clk->set_parent = dt_clk_usb_phy1_set_parent; + + usb_phy1_clk_dt = clk; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_usb_ahb_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR2; + clk->enable_shift = MXC_CCM_CCGRx_CG13_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_usboh3_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->get_rate = clk_usboh3_get_rate; + clk->set_parent = clk_usboh3_set_parent; + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR2; + clk->enable_shift = MXC_CCM_CCGRx_CG14_OFFSET; + + usboh3_clk_dt = clk; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_mipi_hsp_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_hsc_enable; + clk->disable = _clk_hsc_disable; + clk->enable_reg = MXC_CCM_CCGR4; + clk->enable_shift = MXC_CCM_CCGRx_CG6_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ipu_di_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 1) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR6; + clk->enable_shift = (id == 0) ? MXC_CCM_CCGRx_CG5_OFFSET : + MXC_CCM_CCGRx_CG6_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ipu_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = clk_ipu_enable; + clk->disable = clk_ipu_disable; + clk->enable_reg = MXC_CCM_CCGR5; + clk->enable_shift = MXC_CCM_CCGRx_CG5_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ipu_sec_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_mipi_hsc_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 1) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR4; + clk->enable_shift = (id == 0) ? MXC_CCM_CCGRx_CG3_OFFSET : + MXC_CCM_CCGRx_CG4_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_mipi_esc_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR4; + clk->enable_shift = MXC_CCM_CCGRx_CG5_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_esdhc_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 1) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_max_enable; + clk->disable = _clk_max_disable; + clk->enable_reg = MXC_CCM_CCGR3; + + if (id == 0) { + clk->enable_shift = MXC_CCM_CCGRx_CG1_OFFSET; + clk->get_rate = clk_esdhc1_get_rate; + clk->set_rate = clk_esdhc1_set_rate; + clk->set_parent = clk_esdhc1_set_parent; + esdhc1_clk_dt = clk; + } else { + clk->enable_shift = MXC_CCM_CCGRx_CG3_OFFSET; + clk->get_rate = clk_esdhc2_get_rate; + clk->set_rate = clk_esdhc2_set_rate; + clk->set_parent = clk_esdhc2_set_parent; + esdhc2_clk_dt = clk; + } + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_esdhc_ipg_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 1) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_max_enable; + clk->disable = _clk_max_disable; + clk->enable_reg = MXC_CCM_CCGR3; + clk->enable_shift = (id == 0) ? MXC_CCM_CCGRx_CG0_OFFSET : + MXC_CCM_CCGRx_CG2_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_sdma_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR4; + clk->enable_shift = MXC_CCM_CCGRx_CG15_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ecspi_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 1) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR4; + clk->enable_shift = (id == 0) ? MXC_CCM_CCGRx_CG10_OFFSET : + MXC_CCM_CCGRx_CG12_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ecspi_ipg_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 1) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_ccgr_enable_inrun; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR4; + clk->enable_shift = (id == 0) ? MXC_CCM_CCGRx_CG9_OFFSET : + MXC_CCM_CCGRx_CG11_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ecspi_main_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->get_rate = clk_ecspi_get_rate; + clk->set_parent = clk_ecspi_set_parent; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_cspi_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR4; + clk->enable_shift = MXC_CCM_CCGRx_CG13_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_cspi_ipg_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR4; + clk->enable_shift = MXC_CCM_CCGRx_CG9_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ssi_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 2) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR3; + + switch (id) { + case 0: + clk->enable_shift = MXC_CCM_CCGRx_CG9_OFFSET; + break; + case 1: + clk->enable_shift = MXC_CCM_CCGRx_CG11_OFFSET; + break; + case 2: + clk->enable_shift = MXC_CCM_CCGRx_CG13_OFFSET; + } + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ssi_ipg_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 2) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR3; + + switch (id) { + case 0: + clk->enable_shift = MXC_CCM_CCGRx_CG8_OFFSET; + break; + case 1: + clk->enable_shift = MXC_CCM_CCGRx_CG10_OFFSET; + break; + case 2: + clk->enable_shift = MXC_CCM_CCGRx_CG12_OFFSET; + } + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_nfc_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR5; + clk->enable_shift = MXC_CCM_CCGRx_CG10_OFFSET; + clk->get_rate = clk_nfc_get_rate; + clk->set_rate = clk_nfc_set_rate; + clk->round_rate = clk_nfc_round_rate; + clk->set_parent = clk_nfc_set_parent; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_i2c_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 2) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR1; + + switch (id) { + case 0: + clk->enable_shift = MXC_CCM_CCGRx_CG9_OFFSET; + break; + case 1: + clk->enable_shift = MXC_CCM_CCGRx_CG10_OFFSET; + break; + case 2: + clk->enable_shift = MXC_CCM_CCGRx_CG11_OFFSET; + } + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_pwm_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 1) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR2; + clk->enable_shift = (id == 0) ? MXC_CCM_CCGRx_CG6_OFFSET : + MXC_CCM_CCGRx_CG8_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_fec_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR2; + clk->enable_shift = MXC_CCM_CCGRx_CG12_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_uart_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 2) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR1; + + switch (id) { + case 0: + clk->enable_shift = MXC_CCM_CCGRx_CG4_OFFSET; + break; + case 1: + clk->enable_shift = MXC_CCM_CCGRx_CG6_OFFSET; + break; + case 2: + clk->enable_shift = MXC_CCM_CCGRx_CG8_OFFSET; + } + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_uart_root_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->get_rate = clk_uart_get_rate; + clk->set_parent = clk_uart_set_parent; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_uart_ipg_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 2) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR1; + + switch (id) { + case 0: + clk->enable_shift = MXC_CCM_CCGRx_CG3_OFFSET; + break; + case 1: + clk->enable_shift = MXC_CCM_CCGRx_CG5_OFFSET; + break; + case 2: + clk->enable_shift = MXC_CCM_CCGRx_CG7_OFFSET; + } + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_gpt_32k_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_gpt_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR2; + clk->enable_shift = MXC_CCM_CCGRx_CG9_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_gpt_ipg_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR2; + clk->enable_shift = MXC_CCM_CCGRx_CG10_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ahbmux1_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable_inwait; + clk->enable_reg = MXC_CCM_CCGR0; + clk->enable_shift = MXC_CCM_CCGRx_CG8_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_aips_tz_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 1) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable_inwait; + clk->enable_reg = MXC_CCM_CCGR0; + clk->enable_shift = (id == 0) ? MXC_CCM_CCGRx_CG12_OFFSET : + MXC_CCM_CCGRx_CG13_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ahb_max_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_max_enable; + clk->disable = _clk_max_disable; + clk->enable_reg = MXC_CCM_CCGR0; + clk->enable_shift = MXC_CCM_CCGRx_CG14_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_iim_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable_reg = MXC_CCM_CCGR0; + clk->enable_shift = MXC_CCM_CCGRx_CG15_OFFSET; + + iim_clk_dt = clk; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_spba_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable; + clk->enable_reg = MXC_CCM_CCGR5; + clk->enable_shift = MXC_CCM_CCGRx_CG0_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ipg_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->get_rate = clk_ipg_get_rate; + + ipg_clk_dt = clk; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ahb_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->get_rate = clk_ahb_get_rate; + clk->set_rate = _clk_ahb_set_rate; + clk->round_rate = _clk_ahb_round_rate; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_emi_slow_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable_inwait; + clk->enable_reg = MXC_CCM_CCGR5; + clk->enable_shift = MXC_CCM_CCGRx_CG8_OFFSET; + clk->get_rate = clk_emi_slow_get_rate; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_main_bus_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->set_parent = dt_clk_main_bus_set_parent; + + main_bus_clk_dt = clk; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_emi_fast_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->enable = _clk_ccgr_enable; + clk->disable = _clk_ccgr_disable_inwait; + clk->enable_reg = MXC_CCM_CCGR5; + clk->enable_shift = MXC_CCM_CCGRx_CG7_OFFSET; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ddr_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ddr_hf_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->get_rate = _clk_ddr_hf_get_rate; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_cpu_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->get_rate = clk_cpu_get_rate; + clk->set_rate = clk_cpu_set_rate; + + cpu_clk_dt = clk; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_ipg_per_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->get_rate = clk_ipg_per_get_rate; + clk->set_parent = dt_clk_ipg_per_set_parent; + + ipg_per_clk_dt = clk; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_periph_apm_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->set_parent = dt_clk_periph_apm_set_parent; + + periph_apm_clk_dt = clk; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_lp_apm_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->set_parent = dt_clk_lp_apm_set_parent; + + lp_apm_clk_dt = clk; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_pll_switch_clk(struct device_node *node) +{ + const __be32 *reg; + int id; + + ALLOC_CLK_LOOKUP(); + + reg = of_get_property(node, "reg", NULL); + if (!reg) { + ret = -ENOENT; + goto out_kfree; + } + + id = be32_to_cpu(*reg); + if (id < 0 || id > 2) { + ret = -EINVAL; + goto out_kfree; + } + + clk->id = id; + + switch (id) { + case 0: + clk->get_rate = dt_clk_pll1_sw_get_rate; + clk->set_parent = dt_clk_pll1_sw_set_parent; + pll1_sw_clk_dt = clk; + break; + case 1: + clk->get_rate = clk_pll_get_rate; + clk->set_rate = _clk_pll_set_rate; + clk->enable = _clk_pll_enable; + clk->disable = _clk_pll_disable; + clk->set_parent = dt_clk_pll2_sw_set_parent; + pll2_sw_clk_dt = clk; + break; + case 2: + clk->get_rate = clk_pll_get_rate; + clk->set_rate = _clk_pll_set_rate; + clk->enable = _clk_pll_enable; + clk->disable = _clk_pll_disable; + pll3_sw_clk_dt = clk; + } + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_add_pll1_main_clk(struct device_node *node) +{ + ALLOC_CLK_LOOKUP(); + + clk->get_rate = clk_pll_get_rate; + clk->enable = _clk_pll_enable; + clk->disable = _clk_pll_disable; + + pll1_main_clk_dt = clk; + + ADD_CLK_LOOKUP(); +} + +static __init int mx5_dt_scan_clks(void) +{ + struct device_node *node; + int ret; + + ret = mx5_scan_fixed_clks(); + if (ret) { + pr_err("%s: fixed-clock failed %d\n", __func__, ret); + return ret; + } + + for_each_compatible_node(node, NULL, "fsl,mxc-clock") { + if (!strcmp(node->name, "pll1_main")) + ret = mx5_add_pll1_main_clk(node); + else if (!strcmp(node->name, "pll_switch")) + ret = mx5_add_pll_switch_clk(node); + else if (!strcmp(node->name, "lp_apm")) + ret = mx5_add_lp_apm_clk(node); + else if (!strcmp(node->name, "periph_apm")) + ret = mx5_add_periph_apm_clk(node); + else if (!strcmp(node->name, "ipg_per")) + ret = mx5_add_ipg_per_clk(node); + else if (!strcmp(node->name, "cpu")) + ret = mx5_add_cpu_clk(node); + else if (!strcmp(node->name, "ddr_hf")) + ret = mx5_add_ddr_hf_clk(node); + else if (!strcmp(node->name, "ddr")) + ret = mx5_add_ddr_clk(node); + else if (!strcmp(node->name, "emi_fast")) + ret = mx5_add_emi_fast_clk(node); + else if (!strcmp(node->name, "main_bus")) + ret = mx5_add_main_bus_clk(node); + else if (!strcmp(node->name, "emi_slow")) + ret = mx5_add_emi_slow_clk(node); + else if (!strcmp(node->name, "ahb")) + ret = mx5_add_ahb_clk(node); + else if (!strcmp(node->name, "ipg")) + ret = mx5_add_ipg_clk(node); + else if (!strcmp(node->name, "spba")) + ret = mx5_add_spba_clk(node); + else if (!strcmp(node->name, "iim")) + ret = mx5_add_iim_clk(node); + else if (!strcmp(node->name, "ahb_max")) + ret = mx5_add_ahb_max_clk(node); + else if (!strcmp(node->name, "aips_tz")) + ret = mx5_add_aips_tz_clk(node); + else if (!strcmp(node->name, "ahbmux1")) + ret = mx5_add_ahbmux1_clk(node); + else if (!strcmp(node->name, "gpt_ipg")) + ret = mx5_add_gpt_ipg_clk(node); + else if (!strcmp(node->name, "gpt")) + ret = mx5_add_gpt_clk(node); + else if (!strcmp(node->name, "gpt_32k")) + ret = mx5_add_gpt_32k_clk(node); + else if (!strcmp(node->name, "uart_ipg")) + ret = mx5_add_uart_ipg_clk(node); + else if (!strcmp(node->name, "uart_root")) + ret = mx5_add_uart_root_clk(node); + else if (!strcmp(node->name, "uart")) + ret = mx5_add_uart_clk(node); + else if (!strcmp(node->name, "fec")) + ret = mx5_add_fec_clk(node); + else if (!strcmp(node->name, "pwm")) + ret = mx5_add_pwm_clk(node); + else if (!strcmp(node->name, "i2c")) + ret = mx5_add_i2c_clk(node); + else if (!strcmp(node->name, "nfc")) + ret = mx5_add_nfc_clk(node); + else if (!strcmp(node->name, "ssi_ipg")) + ret = mx5_add_ssi_ipg_clk(node); + else if (!strcmp(node->name, "ssi")) + ret = mx5_add_ssi_clk(node); + else if (!strcmp(node->name, "cspi_ipg")) + ret = mx5_add_cspi_ipg_clk(node); + else if (!strcmp(node->name, "cspi")) + ret = mx5_add_cspi_clk(node); + else if (!strcmp(node->name, "ecspi_main")) + ret = mx5_add_ecspi_main_clk(node); + else if (!strcmp(node->name, "ecspi_ipg")) + ret = mx5_add_ecspi_ipg_clk(node); + else if (!strcmp(node->name, "ecspi")) + ret = mx5_add_ecspi_clk(node); + else if (!strcmp(node->name, "sdma")) + ret = mx5_add_sdma_clk(node); + else if (!strcmp(node->name, "esdhc_ipg")) + ret = mx5_add_esdhc_ipg_clk(node); + else if (!strcmp(node->name, "esdhc")) + ret = mx5_add_esdhc_clk(node); + else if (!strcmp(node->name, "mipi_esc")) + ret = mx5_add_mipi_esc_clk(node); + else if (!strcmp(node->name, "mipi_hsc")) + ret = mx5_add_mipi_hsc_clk(node); + else if (!strcmp(node->name, "ipu_sec")) + ret = mx5_add_ipu_sec_clk(node); + else if (!strcmp(node->name, "ipu")) + ret = mx5_add_ipu_clk(node); + else if (!strcmp(node->name, "ipu_di")) + ret = mx5_add_ipu_di_clk(node); + else if (!strcmp(node->name, "mipi_hsp")) + ret = mx5_add_mipi_hsp_clk(node); + else if (!strcmp(node->name, "usboh3")) + ret = mx5_add_usboh3_clk(node); + else if (!strcmp(node->name, "usb_ahb")) + ret = mx5_add_usb_ahb_clk(node); + else if (!strcmp(node->name, "usb_phy1")) + ret = mx5_add_usb_phy1_clk(node); + else if (!strcmp(node->name, "dummy")) + ret = mx5_add_dummy_clk(node); + else + pr_warn("%s: unknown clock node %s\n", + __func__, node->name); + + if (ret) { + pr_err("%s: clock %s failed %d\n", + __func__, node->name, ret); + break; + } + } + + return ret; }
void __init mx5_clk_dt_init(void) { + u32 reg; + mx5_dt_scan_clks(); + + /* clk_tree_init(); */ + clk_set_parent(ipg_per_clk_dt, lp_apm_clk_dt); + + /* + * Initialise the IPG PER CLK dividers to 3. IPG_PER_CLK should be at + * 8MHz, its derived from lp_apm. + * + * FIXME: Verify if true for all boards + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_PERCLK_PRED1_MASK; + reg &= ~MXC_CCM_CBCDR_PERCLK_PRED2_MASK; + reg &= ~MXC_CCM_CBCDR_PERCLK_PODF_MASK; + reg |= (2 << MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + clk_enable(cpu_clk_dt); + clk_enable(main_bus_clk_dt); + + clk_enable(iim_clk_dt); + mx51_revision(); + clk_disable(iim_clk_dt); + + /* move usb_phy_clk to 24MHz */ + clk_set_parent(usb_phy1_clk_dt, osc_clk_dt); + + /* set the usboh3_clk parent to pll2_sw_clk */ + clk_set_parent(usboh3_clk_dt, pll2_sw_clk_dt); + + /* Set SDHC parents to be PLL2 */ + clk_set_parent(esdhc1_clk_dt, pll2_sw_clk_dt); + clk_set_parent(esdhc2_clk_dt, pll2_sw_clk_dt); + + /* set SDHC root clock as 166.25MHZ*/ + clk_set_rate(esdhc1_clk_dt, 166250000); + clk_set_rate(esdhc2_clk_dt, 166250000); } #endif
On Mon, Mar 14, 2011 at 09:18:40PM +0800, Shawn Guo wrote:
This patch is to change the static clock creating and registering to the dynamic way, which scans dt clock nodes, associate clk with device_node, and then add them to clkdev accordingly.
It's a pretty straight translation from non-dt clock code to dt one, and it does not really change any actual clock code.
Signed-off-by: Shawn Guo shawn.guo@linaro.org
arch/arm/mach-mx5/clock-mx51-mx53.c | 1401 ++++++++++++++++++++++++++++++++++- 1 files changed, 1387 insertions(+), 14 deletions(-)
diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c index dedb7f9..c3ec7f6 100644 --- a/arch/arm/mach-mx5/clock-mx51-mx53.c +++ b/arch/arm/mach-mx5/clock-mx51-mx53.c @@ -49,6 +49,30 @@ static struct clk emi_fast_clk; static struct clk ipu_clk; static struct clk mipi_hsc1_clk; +#ifdef CONFIG_OF +/*
- The pointers are defined to save the references to the clocks
- dynamically created, and then could be used to replace those
- static references in non-dt clock code.
- */
+static struct clk *osc_clk_dt; +static struct clk *pll1_main_clk_dt; +static struct clk *pll1_sw_clk_dt; +static struct clk *pll2_sw_clk_dt; +static struct clk *pll3_sw_clk_dt; +static struct clk *lp_apm_clk_dt; +static struct clk *periph_apm_clk_dt; +static struct clk *main_bus_clk_dt; +static struct clk *ipg_clk_dt; +static struct clk *ipg_per_clk_dt; +static struct clk *cpu_clk_dt; +static struct clk *iim_clk_dt; +static struct clk *usboh3_clk_dt; +static struct clk *usb_phy1_clk_dt; +static struct clk *esdhc1_clk_dt; +static struct clk *esdhc2_clk_dt; +#endif
Heh, yeah this seems sub-optimal. It would be better to share common clock initialization between dt and non-dt boards, even if it means that a lot of the clocks are node described in the device tree (at least for the on-chip SoC clocks; board-accessible clocks still need to appear in the device tree though.
#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */ /* calculate best pre and post dividers to get the required divider */ @@ -163,10 +187,18 @@ static inline void __iomem *_mx53_get_pll_base(struct clk *pll) return NULL; } +#ifdef CONFIG_OF +static void __iomem *dt_mx51_get_pll_base(struct clk *pll); +#endif
static inline void __iomem *_get_pll_base(struct clk *pll) { if (cpu_is_mx51()) +#ifdef CONFIG_OF
return dt_mx51_get_pll_base(pll);
+#else return _mx51_get_pll_base(pll); +#endif
If you do it this way, you need to make sure dt_mx51_get_pll_base() falls back to _mx51_get_pll_base() when a dt is not provided.
g.
On Tue, Mar 15, 2011 at 01:48:08AM -0600, Grant Likely wrote:
On Mon, Mar 14, 2011 at 09:18:40PM +0800, Shawn Guo wrote:
This patch is to change the static clock creating and registering to the dynamic way, which scans dt clock nodes, associate clk with device_node, and then add them to clkdev accordingly.
It's a pretty straight translation from non-dt clock code to dt one, and it does not really change any actual clock code.
Signed-off-by: Shawn Guo shawn.guo@linaro.org
arch/arm/mach-mx5/clock-mx51-mx53.c | 1401 ++++++++++++++++++++++++++++++++++- 1 files changed, 1387 insertions(+), 14 deletions(-)
diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c index dedb7f9..c3ec7f6 100644 --- a/arch/arm/mach-mx5/clock-mx51-mx53.c +++ b/arch/arm/mach-mx5/clock-mx51-mx53.c @@ -49,6 +49,30 @@ static struct clk emi_fast_clk; static struct clk ipu_clk; static struct clk mipi_hsc1_clk; +#ifdef CONFIG_OF +/*
- The pointers are defined to save the references to the clocks
- dynamically created, and then could be used to replace those
- static references in non-dt clock code.
- */
+static struct clk *osc_clk_dt; +static struct clk *pll1_main_clk_dt; +static struct clk *pll1_sw_clk_dt; +static struct clk *pll2_sw_clk_dt; +static struct clk *pll3_sw_clk_dt; +static struct clk *lp_apm_clk_dt; +static struct clk *periph_apm_clk_dt; +static struct clk *main_bus_clk_dt; +static struct clk *ipg_clk_dt; +static struct clk *ipg_per_clk_dt; +static struct clk *cpu_clk_dt; +static struct clk *iim_clk_dt; +static struct clk *usboh3_clk_dt; +static struct clk *usb_phy1_clk_dt; +static struct clk *esdhc1_clk_dt; +static struct clk *esdhc2_clk_dt; +#endif
Heh, yeah this seems sub-optimal. It would be better to share common clock initialization between dt and non-dt boards, even if it means that a lot of the clocks are node described in the device tree (at least for the on-chip SoC clocks; board-accessible clocks still need to appear in the device tree though.
I do not understand the above comment. These are not statically defining 'struct clk' but the pointers to them. They are used to solve the references to static 'clk' in existing code, since all clk are created dynamically in dt code.
The big deal here is that it removes the call to mx51_clocks_init, where all the possible clocks are added to clkdev in static way.
Signed-off-by: Shawn Guo shawn.guo@linaro.org --- arch/arm/mach-mx5/board-dt.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-mx5/board-dt.c b/arch/arm/mach-mx5/board-dt.c index 19c60a4..45d1e37 100644 --- a/arch/arm/mach-mx5/board-dt.c +++ b/arch/arm/mach-mx5/board-dt.c @@ -16,6 +16,7 @@ #include <linux/dma-mapping.h> #include <linux/of_platform.h> #include <linux/of_fdt.h> +#include <linux/clk.h>
#include <mach/common.h> #include <mach/hardware.h> @@ -42,8 +43,14 @@ static void __init mx51_dt_board_init(void)
static void __init mx51_dt_timer_init(void) { - mx51_clocks_init(32768, 24000000, 22579200, 0); + struct clk *clk; + mx5_clk_dt_init(); + + clk = clk_get_sys("gpt", NULL); + if (!IS_ERR(clk)) + mxc_timer_init(clk, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR), + MX51_MXC_INT_GPT); }
static struct sys_timer mxc_timer = {
With the platform clock support, the 'struct clk' should have been associated with device_node->data. So the use of function __of_clk_get_from_provider can be eliminated.
Signed-off-by: Shawn Guo shawn.guo@linaro.org --- drivers/of/clock.c | 23 ++--------------------- 1 files changed, 2 insertions(+), 21 deletions(-)
diff --git a/drivers/of/clock.c b/drivers/of/clock.c index 7b5ea67..f124d0a 100644 --- a/drivers/of/clock.c +++ b/drivers/of/clock.c @@ -71,24 +71,6 @@ void of_clk_del_provider(struct device_node *np, mutex_unlock(&of_clk_lock); }
-static struct clk *__of_clk_get_from_provider(struct device_node *np, const char *clk_output) -{ - struct of_clk_provider *provider; - struct clk *clk = NULL; - - /* Check if we have such a provider in our array */ - mutex_lock(&of_clk_lock); - list_for_each_entry(provider, &of_clk_providers, link) { - if (provider->node == np) - clk = provider->get(np, clk_output, provider->data); - if (clk) - break; - } - mutex_unlock(&of_clk_lock); - - return clk; -} - struct clk *of_clk_get(struct device *dev, const char *id) { struct device_node *provnode; @@ -123,9 +105,8 @@ struct clk *of_clk_get(struct device *dev, const char *id) __func__, prop_name, dev->of_node->full_name); return NULL; } - clk = __of_clk_get_from_provider(provnode, prop); - if (clk) - dev_dbg(dev, "Using clock from %s\n", provnode->full_name); + + clk = provnode->data;
of_node_put(provnode);
On Mon, Mar 14, 2011 at 09:18:42PM +0800, Shawn Guo wrote:
With the platform clock support, the 'struct clk' should have been associated with device_node->data. So the use of function __of_clk_get_from_provider can be eliminated.
Signed-off-by: Shawn Guo shawn.guo@linaro.org
drivers/of/clock.c | 23 ++--------------------- 1 files changed, 2 insertions(+), 21 deletions(-)
diff --git a/drivers/of/clock.c b/drivers/of/clock.c index 7b5ea67..f124d0a 100644 --- a/drivers/of/clock.c +++ b/drivers/of/clock.c @@ -71,24 +71,6 @@ void of_clk_del_provider(struct device_node *np, mutex_unlock(&of_clk_lock); } -static struct clk *__of_clk_get_from_provider(struct device_node *np, const char *clk_output) -{
- struct of_clk_provider *provider;
- struct clk *clk = NULL;
- /* Check if we have such a provider in our array */
- mutex_lock(&of_clk_lock);
- list_for_each_entry(provider, &of_clk_providers, link) {
if (provider->node == np)
clk = provider->get(np, clk_output, provider->data);
if (clk)
break;
- }
- mutex_unlock(&of_clk_lock);
- return clk;
-}
struct clk *of_clk_get(struct device *dev, const char *id) { struct device_node *provnode; @@ -123,9 +105,8 @@ struct clk *of_clk_get(struct device *dev, const char *id) __func__, prop_name, dev->of_node->full_name); return NULL; }
- clk = __of_clk_get_from_provider(provnode, prop);
- if (clk)
dev_dbg(dev, "Using clock from %s\n", provnode->full_name);
- clk = provnode->data;
Where is the device_node->data pointer getting set?
In general the ->data pointer of struct device_node should be avoided. There are no strong rules about its usage which means there is a very real risk that another driver or subsystem will try to use it for a different purpose.
Iterating over the whole device tree is safer, and it really isn't very expensive. If you really want to store the struct_clk pointer in the device node, then it would be better to add a struct clk * field to struct device_node.
g.
On Tue, Mar 15, 2011 at 01:54:05AM -0600, Grant Likely wrote:
On Mon, Mar 14, 2011 at 09:18:42PM +0800, Shawn Guo wrote:
With the platform clock support, the 'struct clk' should have been associated with device_node->data. So the use of function __of_clk_get_from_provider can be eliminated.
Signed-off-by: Shawn Guo shawn.guo@linaro.org
drivers/of/clock.c | 23 ++--------------------- 1 files changed, 2 insertions(+), 21 deletions(-)
diff --git a/drivers/of/clock.c b/drivers/of/clock.c index 7b5ea67..f124d0a 100644 --- a/drivers/of/clock.c +++ b/drivers/of/clock.c @@ -71,24 +71,6 @@ void of_clk_del_provider(struct device_node *np, mutex_unlock(&of_clk_lock); } -static struct clk *__of_clk_get_from_provider(struct device_node *np, const char *clk_output) -{
- struct of_clk_provider *provider;
- struct clk *clk = NULL;
- /* Check if we have such a provider in our array */
- mutex_lock(&of_clk_lock);
- list_for_each_entry(provider, &of_clk_providers, link) {
if (provider->node == np)
clk = provider->get(np, clk_output, provider->data);
if (clk)
break;
- }
- mutex_unlock(&of_clk_lock);
- return clk;
-}
struct clk *of_clk_get(struct device *dev, const char *id) { struct device_node *provnode; @@ -123,9 +105,8 @@ struct clk *of_clk_get(struct device *dev, const char *id) __func__, prop_name, dev->of_node->full_name); return NULL; }
- clk = __of_clk_get_from_provider(provnode, prop);
- if (clk)
dev_dbg(dev, "Using clock from %s\n", provnode->full_name);
- clk = provnode->data;
Where is the device_node->data pointer getting set?
+#define ADD_CLK_LOOKUP() \ + do { \ + node->data = clk; \ ^^^^^^^^^^^^^^^^^ + \ + cl->dev_id = dev_id; \ + cl->clk = clk; \ + clkdev_add(cl); \ + \ + return 0; \ + \ + out_kfree: \ + kfree(cl); \ + return ret; \ + } while (0)
In general the ->data pointer of struct device_node should be avoided. There are no strong rules about its usage which means there is a very real risk that another driver or subsystem will try to use it for a different purpose.
Iterating over the whole device tree is safer, and it really isn't very expensive. If you really want to store the struct_clk pointer in the device node, then it would be better to add a struct clk * field to struct device_node.
On Tue, Mar 15, 2011 at 03:59:16PM +0800, Shawn Guo wrote:
On Tue, Mar 15, 2011 at 01:54:05AM -0600, Grant Likely wrote:
On Mon, Mar 14, 2011 at 09:18:42PM +0800, Shawn Guo wrote:
With the platform clock support, the 'struct clk' should have been associated with device_node->data. So the use of function __of_clk_get_from_provider can be eliminated.
Signed-off-by: Shawn Guo shawn.guo@linaro.org
drivers/of/clock.c | 23 ++--------------------- 1 files changed, 2 insertions(+), 21 deletions(-)
diff --git a/drivers/of/clock.c b/drivers/of/clock.c index 7b5ea67..f124d0a 100644 --- a/drivers/of/clock.c +++ b/drivers/of/clock.c @@ -71,24 +71,6 @@ void of_clk_del_provider(struct device_node *np, mutex_unlock(&of_clk_lock); } -static struct clk *__of_clk_get_from_provider(struct device_node *np, const char *clk_output) -{
- struct of_clk_provider *provider;
- struct clk *clk = NULL;
- /* Check if we have such a provider in our array */
- mutex_lock(&of_clk_lock);
- list_for_each_entry(provider, &of_clk_providers, link) {
if (provider->node == np)
clk = provider->get(np, clk_output, provider->data);
if (clk)
break;
- }
- mutex_unlock(&of_clk_lock);
- return clk;
-}
struct clk *of_clk_get(struct device *dev, const char *id) { struct device_node *provnode; @@ -123,9 +105,8 @@ struct clk *of_clk_get(struct device *dev, const char *id) __func__, prop_name, dev->of_node->full_name); return NULL; }
- clk = __of_clk_get_from_provider(provnode, prop);
- if (clk)
dev_dbg(dev, "Using clock from %s\n", provnode->full_name);
- clk = provnode->data;
Where is the device_node->data pointer getting set?
+#define ADD_CLK_LOOKUP() \
- do { \
^^^^^^^^^^^^^^^^^node->data = clk; \
\
cl->dev_id = dev_id; \
cl->clk = clk; \
clkdev_add(cl); \
\
return 0; \
\
- out_kfree: \
kfree(cl); \
return ret; \
- } while (0)
Yeah... don't do that! :-)
g.
On Tue, Mar 15, 2011 at 01:54:05AM -0600, Grant Likely wrote:
On Mon, Mar 14, 2011 at 09:18:42PM +0800, Shawn Guo wrote:
With the platform clock support, the 'struct clk' should have been associated with device_node->data. So the use of function __of_clk_get_from_provider can be eliminated.
Signed-off-by: Shawn Guo shawn.guo@linaro.org
drivers/of/clock.c | 23 ++--------------------- 1 files changed, 2 insertions(+), 21 deletions(-)
diff --git a/drivers/of/clock.c b/drivers/of/clock.c index 7b5ea67..f124d0a 100644 --- a/drivers/of/clock.c +++ b/drivers/of/clock.c @@ -71,24 +71,6 @@ void of_clk_del_provider(struct device_node *np, mutex_unlock(&of_clk_lock); } -static struct clk *__of_clk_get_from_provider(struct device_node *np, const char *clk_output) -{
- struct of_clk_provider *provider;
- struct clk *clk = NULL;
- /* Check if we have such a provider in our array */
- mutex_lock(&of_clk_lock);
- list_for_each_entry(provider, &of_clk_providers, link) {
if (provider->node == np)
clk = provider->get(np, clk_output, provider->data);
if (clk)
break;
- }
- mutex_unlock(&of_clk_lock);
- return clk;
-}
struct clk *of_clk_get(struct device *dev, const char *id) { struct device_node *provnode; @@ -123,9 +105,8 @@ struct clk *of_clk_get(struct device *dev, const char *id) __func__, prop_name, dev->of_node->full_name); return NULL; }
- clk = __of_clk_get_from_provider(provnode, prop);
- if (clk)
dev_dbg(dev, "Using clock from %s\n", provnode->full_name);
- clk = provnode->data;
Where is the device_node->data pointer getting set?
In general the ->data pointer of struct device_node should be avoided. There are no strong rules about its usage which means there is a very real risk that another driver or subsystem will try to use it for a different purpose.
Iterating over the whole device tree is safer, and it really isn't very expensive. If you really want to store the struct_clk pointer in
I do not understand how we can get the pointer to the 'struct clk' from device tree. The clock code reads nodes from device tree and creates 'struct clk' dynamically. If we do not save the pointer somewhere, the pointer will get lost outside the clock code. How can we possibly get it back from device tree later?
the device node, then it would be better to add a struct clk * field to struct device_node.