extend the recently added COMMON_CLK platform support for MPC512x such
that it works with incomplete device tree data which lacks clock specs
Cc: Mike Turquette mturque...@linaro.org
Cc: Anatolij Gustschin ag...@denx.de
Cc: linux-arm-ker...@lists.infradead.org
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Gerhard Sittig g...@denx.de
---
arch/powerpc/platforms/512x/clock-commonclk.c | 173 -
1 file changed, 172 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c
b/arch/powerpc/platforms/512x/clock-commonclk.c
index 818927248392..945e4609e773 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -11,6 +11,7 @@
* (at your option) any later version.
*/
+#include linux/bitops.h
#include linux/clk-provider.h
#include linux/clkdev.h
#include linux/device.h
@@ -745,7 +746,177 @@ static void mpc5121_clk_provide_migration_support(void)
*/
static void mpc5121_clk_provide_backwards_compat(void)
{
- /* TODO */
+ enum did_reg_flags {
+ DID_REG_PSC = BIT(0),
+ DID_REG_PSCFIFO = BIT(1),
+ DID_REG_NFC = BIT(2),
+ DID_REG_CAN = BIT(3),
+ DID_REG_I2C = BIT(4),
+ DID_REG_DIU = BIT(5),
+ DID_REG_VIU = BIT(6),
+ DID_REG_FEC = BIT(7),
+ DID_REG_USB = BIT(8),
+ DID_REG_PATA= BIT(9),
+ };
+
+ int did_register;
+ struct device_node *np;
+ struct resource res;
+ int idx;
+ char devname[32];
+
+ /*
+* those macros are not exactly pretty, but they encapsulate a lot
+* of copy'n'paste heavy code which is even more ugly, and reduce
+* the potential for inconsistencies in those many code copies
+*/
+
+#define FOR_NODES(compatname) \
+ for_each_compatible_node(np, NULL, compatname)
+
+#define NODE_PREP do { \
+ of_address_to_resource(np, 0, res); \
+ snprintf(devname, sizeof(devname), %08x.%s, res.start, np-name); \
+} while (0)
+
+#define NODE_CHK(clkname, clkitem, regnode, regflag) do { \
+ struct clk *clk; \
+ clk = of_clk_get_by_name(np, clkname); \
+ if (IS_ERR(clk)) { \
+ clk = clkitem; \
+ clk_register_clkdev(clk, clkname, devname); \
+ if (regnode) \
+ clk_register_clkdev(clk, clkname, np-name); \
+ did_register |= DID_REG_ ## regflag; \
+ pr_debug(clock alias name '%s' for dev '%s' pointer %p\n, \
+clkname, devname, clk); \
+ } else { \
+ clk_put(clk); \
+ } \
+} while (0)
+
+ did_register = 0;
+
+ FOR_NODES(mpc512x_select_psc_compat()) {
+ NODE_PREP;
+ idx = (res.start 8) 0xf;
+ NODE_CHK(ipg, clks[MPC512x_CLK_PSC0 + idx], 0, PSC);
+ NODE_CHK(mclk, clks[MPC512x_CLK_PSC0_MCLK + idx], 0, PSC);
+ }
+
+ FOR_NODES(fsl,mpc5121-psc-fifo) {
+ NODE_PREP;
+ NODE_CHK(ipg, clks[MPC512x_CLK_PSC_FIFO], 1, PSCFIFO);
+ }
+
+ FOR_NODES(fsl,mpc5121-nfc) {
+ NODE_PREP;
+ NODE_CHK(ipg, clks[MPC512x_CLK_NFC], 0, NFC);
+ }
+
+ FOR_NODES(fsl,mpc5121-mscan) {
+ NODE_PREP;
+ idx = 0;
+ idx += (res.start 0x2000) ? 2 : 0;
+ idx += (res.start 0x0080) ? 1 : 0;
+ NODE_CHK(ipg, clks[MPC512x_CLK_BDLC], 0, CAN);
+ NODE_CHK(mclk, clks[MPC512x_CLK_MSCAN0_MCLK + idx], 0, CAN);
+ }
+
+ /*
+* do register the 'ips', 'sys', and 'ref' names globally
+* instead of inside each individual CAN node, as there is no
+* potential for a name conflict (in contrast to 'ipg' and 'mclk')
+*/
+ if (did_register DID_REG_CAN) {
+ clk_register_clkdev(clks[MPC512x_CLK_IPS], ips, NULL);
+ clk_register_clkdev(clks[MPC512x_CLK_SYS], sys, NULL);
+ clk_register_clkdev(clks[MPC512x_CLK_REF], ref, NULL);
+ }
+
+ FOR_NODES(fsl,mpc5121-i2c) {
+ NODE_PREP;
+ NODE_CHK(ipg, clks[MPC512x_CLK_I2C], 0, I2C);
+ }
+
+ /*
+* workaround for the fact that the I2C driver does an anonymous
+* lookup (NULL name spec, which yields the first clock spec) for
+* which we cannot register an alias -- a _global_ 'ipg' alias that
+* is not bound to any device name and returns the I2C clock item
+* is not a good idea
+*
+* so we have the lookup in the peripheral driver fail, which is
+* silent and non-fatal, and pre-enable the clock item here such
+* that register access is possible
+*
+* see commit b3bfce2b i2c: mpc: cleanup clock API use for
+* details, adjusting