[PATCH v2 00/24] add COMMON_CLK support for PowerPC MPC512x

STALE4723d

138 messages, 11 authors, 2013-08-28 · page 1 of 2 · open the first message on its own page

[PATCH v2 00/24] add COMMON_CLK support for PowerPC MPC512x

From: Gerhard Sittig <hidden>
Date: 2013-07-18 17:00:31

this series introduces support for the common clock framework (CCF,
COMMON_CLK Kconfig option) in the PowerPC based MPC512x platform

although the series does touch several subsystems -- serial, spi, net
(can, fs_enet), mtd (nfc), usb, i2c, media (viu), and dts -- all of the
patches are strictly clock related

it appears most appropriate to take this series through either the clk
or the powerpc trees after it has passed review and other subsystem
maintainers ACKed the clock setup related driver modifications

the series passes 'checkpatch.pl --strict' except for one warning which
cannot get resolved, since that either breaks compilation (the data type
is preset by the clk-provider.h API) or requires a cast which shadows
real mismatches:

  WARNING: static const char * array should probably be static const char * const
  #413: FILE: arch/powerpc/platforms/512x/clock-commonclk.c:335:
  +static const char *parent_names_mux0[] = {

  total: 0 errors, 1 warnings, 0 checks, 836 lines checked

each step in the series was build and run tested (with a display that is
attached to the DIU as well as SPI, with an SPI attached NOR flash, with
multiple UART ports such that one is not the boot console, with EEPROMs
attached to I2C, with an SD card, booting from network)


changes in v2:
- cleanup of the UART and SPI clock handling before the introduction of
  common clock support for the platform, as incomplete clock handling
  becomes fatal or more dangerous later (which in turn changes the
  context of the "device tree lookup only" followup patch later)
- reordered the sequence of patches to keep the serial communication
  related parts together (UART, SPI, and PSC FIFO changes after common
  clock support was introduced)
- updated commit messages for the clock API use cleanup in the serial
  communication drivers, updated comments and reworded commit messages
  in the core clock driver to expand on the pre-enable workaround and
  clkdev registration
- keep a reference to the PSC FIFO clock during use instead of looking
  up the clock again in the uninit() routine
- remove the clkdev.h header file inclusion directive with the removal
  of the clkdev registration call


Gerhard Sittig (24):
  spi: mpc512x: cleanup clock API use
  serial: mpc512x: cleanup clock API use
  mtd: mpc5121_nfc: prepare clocks before enabling them
  powerpc: mpc512x: array decl for MCLK registers in CCM
  clk: wrap I/O access for improved portability
  dts: mpc512x: prepare for preprocessor support
  dts: mpc512x: introduce dt-bindings/clock/ header
  dts: mpc512x: add clock related device tree specs
  clk: mpc512x: introduce COMMON_CLK for MPC512x
  dts: mpc512x: add clock specs for client lookups
  spi: mpc512x: remove now obsolete clock lookup name
  serial: mpc512x: remove now obsolete clock lookup name
  clk: mpc512x: remove now obsolete clkdev registration
  serial: mpc512x: setup the PSC FIFO clock as well
  net: can: mscan: add a comment on reg to idx mapping
  net: can: mscan: make mpc512x code use common clock
  powerpc/mpc512x: improve DIU related clock setup
  i2c: mpc: OF clock lookup for MPC512x
  USB: fsl-mph-dr-of: OF clock lookup, prepare and enable
  fs_enet: OF clock lookup (non-fatal), prepare and enable
  [media] fsl-viu: OF clock lookup, prepare before enable
  powerpc/fsl-pci: OF clock lookup, prepare before enable
  clk: mpc512x: switch to COMMON_CLK, remove PPC_CLOCK
  net: can: mscan: remove MPC512x non-COMMON_CLK code path

 arch/powerpc/boot/dts/ac14xx.dts                   |    9 +-
 arch/powerpc/boot/dts/include/dt-bindings          |    1 +
 arch/powerpc/boot/dts/mpc5121.dtsi                 |   94 ++-
 arch/powerpc/boot/dts/mpc5121ads.dts               |    2 +-
 arch/powerpc/boot/dts/pdm360ng.dts                 |    2 +-
 arch/powerpc/include/asm/mpc5121.h                 |   18 +-
 arch/powerpc/platforms/512x/Kconfig                |    2 +-
 arch/powerpc/platforms/512x/Makefile               |    3 +-
 arch/powerpc/platforms/512x/clock-commonclk.c      |  761 ++++++++++++++++++++
 arch/powerpc/platforms/512x/clock.c                |  753 -------------------
 arch/powerpc/platforms/512x/mpc512x_shared.c       |  165 +++--
 arch/powerpc/sysdev/fsl_pci.c                      |   15 +
 drivers/clk/clk-divider.c                          |    6 +-
 drivers/clk/clk-gate.c                             |    6 +-
 drivers/clk/clk-mux.c                              |    6 +-
 drivers/i2c/busses/i2c-mpc.c                       |    9 +
 drivers/media/platform/fsl-viu.c                   |   12 +-
 drivers/mtd/nand/mpc5121_nfc.c                     |    4 +-
 drivers/net/can/mscan/mpc5xxx_can.c                |  234 +++---
 .../net/ethernet/freescale/fs_enet/fs_enet-main.c  |   27 +-
 drivers/spi/spi-mpc512x-psc.c                      |   45 +-
 drivers/tty/serial/mpc52xx_uart.c                  |  137 +++-
 drivers/usb/host/fsl-mph-dr-of.c                   |   24 +-
 include/dt-bindings/clock/mpc512x-clock.h          |   59 ++
 include/linux/clk-provider.h                       |   33 +
 include/linux/fs_enet_pd.h                         |    3 +
 26 files changed, 1392 insertions(+), 1038 deletions(-)
 create mode 120000 arch/powerpc/boot/dts/include/dt-bindings
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
 delete mode 100644 arch/powerpc/platforms/512x/clock.c
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h


# uname -srm
Linux 3.11.0-rc1-00024-g96ff9fe ppc
# cat /sys/kernel/debug/clk/clk_summary
   clock                        enable_cnt  prepare_cnt  rate
---------------------------------------------------------------------
 ac97                           0           0            24567000
 spdif_rx_in                    0           0            0
 spdif_tx_in                    0           0            0
 psc_mclk_in                    0           0            25000000
 dummy                          1           1            0
 osc                            1           1            25000000
    ref                         1           1            25000000
       sys                      10          10           320000000
          spdif-mux0            0           0            320000000
             spdif-en0          0           0            320000000
                spdif_mclk_div  0           0            80000000
                   spdif_mclk_out 0           0            80000000
                      spdif_mclk 0           0            80000000
          mscan3-mux0           1           1            320000000
             mscan3-en0         1           1            320000000
                mscan3_mclk_div 1           1            80000000
                   mscan3_mclk_out 1           1            80000000
                      mscan3_mclk 1           1            80000000
          mscan2-mux0           1           1            320000000
             mscan2-en0         1           1            320000000
                mscan2_mclk_div 1           1            80000000
                   mscan2_mclk_out 1           1            80000000
                      mscan2_mclk 1           1            80000000
          mscan1-mux0           1           1            320000000
             mscan1-en0         1           1            320000000
                mscan1_mclk_div 1           1            16000000
                   mscan1_mclk_out 1           1            16000000
                      mscan1_mclk 2           2            16000000
          mscan0-mux0           1           1            320000000
             mscan0-en0         1           1            320000000
                mscan0_mclk_div 1           1            16000000
                   mscan0_mclk_out 1           1            16000000
                      mscan0_mclk 2           2            16000000
          psc11-mux0            0           0            320000000
             psc11-en0          0           0            320000000
                psc11_mclk_div  0           0            80000000
                   psc11_mclk_out 0           0            80000000
                      psc11_mclk 0           0            80000000
          psc10-mux0            0           0            320000000
             psc10-en0          0           0            320000000
                psc10_mclk_div  0           0            80000000
                   psc10_mclk_out 0           0            80000000
                      psc10_mclk 0           0            80000000
          psc9-mux0             0           0            320000000
             psc9-en0           0           0            320000000
                psc9_mclk_div   0           0            80000000
                   psc9_mclk_out 0           0            80000000
                      psc9_mclk 0           0            80000000
          psc8-mux0             0           0            320000000
             psc8-en0           0           0            320000000
                psc8_mclk_div   0           0            80000000
                   psc8_mclk_out 0           0            80000000
                      psc8_mclk 0           0            80000000
          psc7-mux0             1           1            320000000
             psc7-en0           1           1            320000000
                psc7_mclk_div   1           1            80000000
                   psc7_mclk_out 1           1            80000000
                      psc7_mclk 1           1            80000000
          psc6-mux0             0           0            320000000
             psc6-en0           0           0            320000000
                psc6_mclk_div   0           0            80000000
                   psc6_mclk_out 0           0            80000000
                      psc6_mclk 0           0            80000000
          psc5-mux0             1           1            320000000
             psc5-en0           1           1            320000000
                psc5_mclk_div   1           1            80000000
                   psc5_mclk_out 1           1            80000000
                      psc5_mclk 1           1            80000000
          psc4-mux0             1           1            320000000
             psc4-en0           1           1            320000000
                psc4_mclk_div   1           1            80000000
                   psc4_mclk_out 1           1            80000000
                      psc4_mclk 1           1            80000000
          psc3-mux0             1           1            320000000
             psc3-en0           1           1            320000000
                psc3_mclk_div   1           1            80000000
                   psc3_mclk_out 1           1            80000000
                      psc3_mclk 2           2            80000000
          psc2-mux0             0           0            320000000
             psc2-en0           0           0            320000000
                psc2_mclk_div   0           0            80000000
                   psc2_mclk_out 0           0            80000000
                      psc2_mclk 0           0            80000000
          psc1-mux0             0           0            320000000
             psc1-en0           0           0            320000000
                psc1_mclk_div   0           0            80000000
                   psc1_mclk_out 0           0            80000000
                      psc1_mclk 0           0            80000000
          psc0-mux0             0           0            320000000
             psc0-en0           0           0            320000000
                psc0_mclk_div   0           0            80000000
                   psc0_mclk_out 0           0            80000000
                      psc0_mclk 0           0            80000000
          ddr-ug                1           1            160000000
             ddr                1           1            160000000
          csb                   4           4            160000000
             viu                0           0            160000000
             iim                0           0            160000000
             usb2               0           0            160000000
             usb1               0           0            160000000
             axe                0           0            160000000
             pci-ug             0           0            26666666
                pci             0           0            26666666
             mbx-bus-ug         0           0            80000000
                mbx-bus         0           0            80000000
                mbx-ug          0           0            80000000
                   mbx          0           0            80000000
                   mbx-3d-ug    0           0            80000000
                      mbx-3d    0           0            80000000
             e300               1           1            400000000
             diu-x4             1           1            640000000
                diu-ug          1           1            2509803
                   diu          2           2            2509803
             sdhc-x4            1           1            640000000
                sdhc-ug         1           1            53333333
                   sdhc-2       0           0            53333333
                   sdhc         1           1            53333333
             ips                7           7            80000000
                i2c             3           3            80000000
                mem             1           1            80000000
                fec             1           1            80000000
                sata            0           0            80000000
                psc-fifo        1           1            80000000
                pata            0           0            80000000
                lpc-ug          1           1            40000000
                   lpc          1           1            40000000
                nfc-ug          0           0            40000000
                   nfc          0           0            40000000

-- 
1.7.10.4

[PATCH v2 03/24] mtd: mpc5121_nfc: prepare clocks before enabling them

From: Gerhard Sittig <hidden>
Date: 2013-07-18 17:00:34

must prepare clocks before enabling them, unprepare after disable

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/mtd/nand/mpc5121_nfc.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
index 3c9cdcb..eb7771d 100644
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -618,7 +618,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
 	struct mpc5121_nfc_prv *prv = chip->priv;
 
 	if (prv->clk) {
-		clk_disable(prv->clk);
+		clk_disable_unprepare(prv->clk);
 		clk_put(prv->clk);
 	}
 
@@ -737,7 +737,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
 		goto error;
 	}
 
-	clk_enable(prv->clk);
+	clk_prepare_enable(prv->clk);
 
 	/* Reset NAND Flash controller */
 	nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
-- 
1.7.10.4

[PATCH v2 04/24] powerpc: mpc512x: array decl for MCLK registers in CCM

From: Gerhard Sittig <hidden>
Date: 2013-07-18 17:00:35

reword the clock control module's registers declaration such that the
MCLK related registers form an array and get indexed by PSC number

this change is in preparation to COMMON_CLK support for the MPC512x
platform, the changed declaration remains neutral to existing code since
the PSC and MSCAN CCR fields declared here aren't referenced anywhere

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/include/asm/mpc5121.h |   18 ++----------------
 1 file changed, 2 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/include/asm/mpc5121.h b/arch/powerpc/include/asm/mpc5121.h
index 8ae133e..887d3d6 100644
--- a/arch/powerpc/include/asm/mpc5121.h
+++ b/arch/powerpc/include/asm/mpc5121.h
@@ -32,25 +32,11 @@ struct mpc512x_ccm {
 	u32	scfr2;	/* System Clock Frequency Register 2 */
 	u32	scfr2s;	/* System Clock Frequency Shadow Register 2 */
 	u32	bcr;	/* Bread Crumb Register */
-	u32	p0ccr;	/* PSC0 Clock Control Register */
-	u32	p1ccr;	/* PSC1 CCR */
-	u32	p2ccr;	/* PSC2 CCR */
-	u32	p3ccr;	/* PSC3 CCR */
-	u32	p4ccr;	/* PSC4 CCR */
-	u32	p5ccr;	/* PSC5 CCR */
-	u32	p6ccr;	/* PSC6 CCR */
-	u32	p7ccr;	/* PSC7 CCR */
-	u32	p8ccr;	/* PSC8 CCR */
-	u32	p9ccr;	/* PSC9 CCR */
-	u32	p10ccr;	/* PSC10 CCR */
-	u32	p11ccr;	/* PSC11 CCR */
+	u32	psc_ccr[12];	/* PSC Clock Control Registers */
 	u32	spccr;	/* SPDIF Clock Control Register */
 	u32	cccr;	/* CFM Clock Control Register */
 	u32	dccr;	/* DIU Clock Control Register */
-	u32	m1ccr;	/* MSCAN1 CCR */
-	u32	m2ccr;	/* MSCAN2 CCR */
-	u32	m3ccr;	/* MSCAN3 CCR */
-	u32	m4ccr;	/* MSCAN4 CCR */
+	u32	mscan_ccr[4];	/* MSCAN Clock Control Registers */
 	u8	res[0x98]; /* Reserved */
 };
 
-- 
1.7.10.4

[PATCH v2 05/24] clk: wrap I/O access for improved portability

From: Gerhard Sittig <hidden>
Date: 2013-07-18 17:00:36

the common clock drivers were motivated/initiated by ARM development
and apparently assume little endian peripherals

wrap register/peripherals access in the common code (div, gate, mux)
in preparation of adding COMMON_CLK support for other platforms

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/clk/clk-divider.c    |    6 +++---
 drivers/clk/clk-gate.c       |    6 +++---
 drivers/clk/clk-mux.c        |    6 +++---
 include/linux/clk-provider.h |   17 +++++++++++++++++
 4 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 6d55eb2..2c07061 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	struct clk_divider *divider = to_clk_divider(hw);
 	unsigned int div, val;
 
-	val = readl(divider->reg) >> divider->shift;
+	val = clk_readl(divider->reg) >> divider->shift;
 	val &= div_mask(divider);
 
 	div = _get_div(divider, val);
@@ -230,11 +230,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
 		val = div_mask(divider) << (divider->shift + 16);
 	} else {
-		val = readl(divider->reg);
+		val = clk_readl(divider->reg);
 		val &= ~(div_mask(divider) << divider->shift);
 	}
 	val |= value << divider->shift;
-	writel(val, divider->reg);
+	clk_writel(val, divider->reg);
 
 	if (divider->lock)
 		spin_unlock_irqrestore(divider->lock, flags);
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 790306e..b7fbd96 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -58,7 +58,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 		if (set)
 			reg |= BIT(gate->bit_idx);
 	} else {
-		reg = readl(gate->reg);
+		reg = clk_readl(gate->reg);
 
 		if (set)
 			reg |= BIT(gate->bit_idx);
@@ -66,7 +66,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 			reg &= ~BIT(gate->bit_idx);
 	}
 
-	writel(reg, gate->reg);
+	clk_writel(reg, gate->reg);
 
 	if (gate->lock)
 		spin_unlock_irqrestore(gate->lock, flags);
@@ -89,7 +89,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
 	u32 reg;
 	struct clk_gate *gate = to_clk_gate(hw);
 
-	reg = readl(gate->reg);
+	reg = clk_readl(gate->reg);
 
 	/* if a set bit disables this clk, flip it before masking */
 	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 614444c..02ef506 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -42,7 +42,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
 	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
 	 * val = 0x4 really means "bit 2, index starts at bit 0"
 	 */
-	val = readl(mux->reg) >> mux->shift;
+	val = clk_readl(mux->reg) >> mux->shift;
 	val &= mux->mask;
 
 	if (mux->table) {
@@ -89,11 +89,11 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
 	if (mux->flags & CLK_MUX_HIWORD_MASK) {
 		val = mux->mask << (mux->shift + 16);
 	} else {
-		val = readl(mux->reg);
+		val = clk_readl(mux->reg);
 		val &= ~(mux->mask << mux->shift);
 	}
 	val |= index << mux->shift;
-	writel(val, mux->reg);
+	clk_writel(val, mux->reg);
 
 	if (mux->lock)
 		spin_unlock_irqrestore(mux->lock, flags);
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 1ec14a7..c4f7799 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -12,6 +12,7 @@
 #define __LINUX_CLK_PROVIDER_H
 
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #ifdef CONFIG_COMMON_CLK
 
@@ -490,5 +491,21 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
 #define of_clk_init(matches) \
 	{ while (0); }
 #endif /* CONFIG_OF */
+
+/*
+ * wrap access to peripherals in accessor routines
+ * for improved portability across platforms
+ */
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+	return readl(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+	writel(val, reg);
+}
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
-- 
1.7.10.4

[PATCH v2 06/24] dts: mpc512x: prepare for preprocessor support

From: Gerhard Sittig <hidden>
Date: 2013-07-18 17:00:37

prepare C preprocessor support when processing MPC512x DTS files
- switch from DTS syntax to CPP syntax for include specs
- create a symlink such that DTS processing can reference includes

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/boot/dts/ac14xx.dts          |    2 +-
 arch/powerpc/boot/dts/include/dt-bindings |    1 +
 arch/powerpc/boot/dts/mpc5121ads.dts      |    2 +-
 arch/powerpc/boot/dts/pdm360ng.dts        |    2 +-
 4 files changed, 4 insertions(+), 3 deletions(-)
 create mode 120000 arch/powerpc/boot/dts/include/dt-bindings
diff --git a/arch/powerpc/boot/dts/ac14xx.dts b/arch/powerpc/boot/dts/ac14xx.dts
index a27a460..a543c40 100644
--- a/arch/powerpc/boot/dts/ac14xx.dts
+++ b/arch/powerpc/boot/dts/ac14xx.dts
@@ -10,7 +10,7 @@
  */
 
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "ac14xx";
diff --git a/arch/powerpc/boot/dts/include/dt-bindings b/arch/powerpc/boot/dts/include/dt-bindings
new file mode 120000
index 0000000..08c00e4
--- /dev/null
+++ b/arch/powerpc/boot/dts/include/dt-bindings
@@ -0,0 +1 @@
+../../../../../include/dt-bindings
\ No newline at end of file
diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
index 7d3cb79..c228a0a 100644
--- a/arch/powerpc/boot/dts/mpc5121ads.dts
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -9,7 +9,7 @@
  * option) any later version.
  */
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "mpc5121ads";
diff --git a/arch/powerpc/boot/dts/pdm360ng.dts b/arch/powerpc/boot/dts/pdm360ng.dts
index 7433740..871c16d 100644
--- a/arch/powerpc/boot/dts/pdm360ng.dts
+++ b/arch/powerpc/boot/dts/pdm360ng.dts
@@ -13,7 +13,7 @@
  * option) any later version.
  */
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "pdm360ng";
-- 
1.7.10.4

[PATCH v2 08/24] dts: mpc512x: add clock related device tree specs

From: Gerhard Sittig <hidden>
Date: 2013-07-18 17:00:39

this addresses the clock driver aka provider's side of clocks
- prepare for future '<&clks ID>' phandle references for device tree
  based clock lookup in client drivers
- introduce a 'clocks' subtree with an 'osc' node for the crystal
  or oscillator SoC input (fixed frequency)
- provide default values with 33MHz oscillator frequency in the
  common include (the 66MHz IPS bus already was there), add
  override values for the ifm AC14xx board which deviates from
  the reference design (25MHz xtal, 80MHz IPS bus)

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/boot/dts/ac14xx.dts   |    7 +++++++
 arch/powerpc/boot/dts/mpc5121.dtsi |   15 ++++++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/boot/dts/ac14xx.dts b/arch/powerpc/boot/dts/ac14xx.dts
index a543c40..a1b8837 100644
--- a/arch/powerpc/boot/dts/ac14xx.dts
+++ b/arch/powerpc/boot/dts/ac14xx.dts
@@ -139,7 +139,14 @@
 		};
 	};
 
+	clocks {
+		osc {
+			clock-frequency = <25000000>;
+		};
+	};
+
 	soc@80000000 {
+		bus-frequency = <80000000>;	/* 80 MHz ips bus */
 
 		clock@f00 {
 			compatible = "fsl,mpc5121rev2-clock", "fsl,mpc5121-clock";
diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
index bd14c00..8f4cba0 100644
--- a/arch/powerpc/boot/dts/mpc5121.dtsi
+++ b/arch/powerpc/boot/dts/mpc5121.dtsi
@@ -9,6 +9,8 @@
  * option) any later version.
  */
 
+#include <dt-bindings/clock/mpc512x-clock.h>
+
 /dts-v1/;
 
 / {
@@ -73,6 +75,16 @@
 		ranges = <0x0 0x0 0xfc000000 0x04000000>;
 	};
 
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		osc {
+			compatible = "fsl,mpc512x-osc", "fixed-clock";
+			clock-frequency = <33000000>;
+		};
+	};
+
 	soc@80000000 {
 		compatible = "fsl,mpc5121-immr";
 		#address-cells = <1>;
@@ -118,9 +130,10 @@
 		};
 
 		/* Clock control */
-		clock@f00 {
+		clks: clock@f00 {
 			compatible = "fsl,mpc5121-clock";
 			reg = <0xf00 0x100>;
+			#clock-cells = <1>;
 		};
 
 		/* Power Management Controller */
-- 
1.7.10.4

[PATCH v2 09/24] clk: mpc512x: introduce COMMON_CLK for MPC512x

From: Gerhard Sittig <hidden>
Date: 2013-07-18 17:00:40

this change introduces a clock infrastructure implementation for the
MPC512x PowerPC platform which follows the COMMON_CLK approach and uses
common clock drivers shared with other platforms

this driver implements the publicly announced set of clocks (which can
get referenced by means of symbolic identifiers from the dt-bindings
header file), as well as generates additional 'struct clk' items where
the SoC hardware cannot easily get mapped to the common primitives of
the clock API, or requires "intermediate" clock nodes to represent
clocks that have both gates and dividers

the previous PPC_CLOCK implementation is kept in place and resides in
parallel to the common clock implementation for test and comparison
during migration, a compile time option picks one of the two
alternatives (Kconfig switch, common clock used by default)

since not all drivers for peripherals were adjusted yet to properly
allocate and release their clock items, this platform clock driver
implementation pre-enables some of the clock items to not break
peripheral drivers during migration -- these clock pre-enable
workarounds will get removed as peripheral drivers get adjusted

to provide clock names which the serial communication drivers are using
and where the PSC index number is encoded into, clkdev registration is
done to not break these peripheral drivers -- this workaround will get
removed as these drivers get adjusted after device tree based clock
lookup has become available

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/Kconfig           |   14 +-
 arch/powerpc/platforms/512x/Makefile          |    4 +-
 arch/powerpc/platforms/512x/clock-commonclk.c |  778 +++++++++++++++++++++++++
 include/linux/clk-provider.h                  |   16 +
 4 files changed, 810 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index fc9c1cb..c5fcdd0 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -1,9 +1,21 @@
+config MPC512x_COMMON_CLK
+	bool "MPC512x platform uses COMMON_CLK"
+	default y
+	depends on PPC_MPC512x
+	help
+	  This option is only here to support tests and comparison
+	  during development and migration.  This option will get
+	  removed after the COMMON_CLK support for MPC512x has become
+	  fully operational and all drivers were adjusted to explicitly
+	  acquire their required clocks.
+
 config PPC_MPC512x
 	bool "512x-based boards"
 	depends on 6xx
 	select FSL_SOC
 	select IPIC
-	select PPC_CLOCK
+	select PPC_CLOCK if !MPC512x_COMMON_CLK
+	select COMMON_CLK if MPC512x_COMMON_CLK
 	select PPC_PCI_CHOICE
 	select FSL_PCI if PCI
 	select ARCH_WANT_OPTIONAL_GPIOLIB
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
index 72fb934..1e05f9d 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -1,7 +1,9 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-y				+= clock.o mpc512x_shared.o
+obj-$(CONFIG_PPC_CLOCK)		+= clock.o
+obj-$(CONFIG_COMMON_CLK)	+= clock-commonclk.o
+obj-y				+= mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)	+= mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)	+= mpc512x_generic.o
 obj-$(CONFIG_PDM360NG)		+= pdm360ng.o
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
new file mode 100644
index 0000000..6627957
--- /dev/null
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -0,0 +1,778 @@
+/*
+ * Copyright (C) 2013 DENX Software Engineering
+ *
+ * Gerhard Sittig, <gsi@denx.de>
+ *
+ * common clock driver support for the MPC512x platform
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <asm/mpc5121.h>
+#include <dt-bindings/clock/mpc512x-clock.h>
+
+#include "mpc512x.h"		/* our public mpc5121_clk_init() API */
+
+/* helpers to keep the MCLK intermediates "somewhere" in our table */
+enum {
+	MCLK_IDX_MUX0,
+	MCLK_IDX_EN0,
+	MCLK_IDX_DIV0,
+	MCLK_IDX_MUX1,
+	MCLK_MAX_IDX,
+};
+
+#define NR_PSCS			12
+#define NR_MSCANS		4
+#define NR_SPDIFS		1
+#define NR_MCLKS		(NR_PSCS + NR_MSCANS + NR_SPDIFS)
+
+/* extend the public set of clocks by adding internal slots for management */
+enum {
+	/* arrange for adjacent numbers after the public set */
+	MPC512x_CLK_START_PRIVATE = MPC512x_CLK_LAST_PUBLIC,
+	/* clocks which aren't announced to the public */
+	MPC512x_CLK_DDR,
+	MPC512x_CLK_MEM,
+	MPC512x_CLK_IIM,
+	MPC512x_CLK_SDHC_2,
+	/* intermediates in div+gate combos or fractional dividers */
+	MPC512x_CLK_DDR_UG,
+	MPC512x_CLK_SDHC_x4,
+	MPC512x_CLK_SDHC_UG,
+	MPC512x_CLK_DIU_x4,
+	MPC512x_CLK_DIU_UG,
+	MPC512x_CLK_MBX_BUS_UG,
+	MPC512x_CLK_MBX_UG,
+	MPC512x_CLK_MBX_3D_UG,
+	MPC512x_CLK_PCI_UG,
+	MPC512x_CLK_NFC_UG,
+	MPC512x_CLK_LPC_UG,
+	MPC512x_CLK_SPDIF_TX_IN,
+	/* intermediates for the mux+gate+div+mux MCLK generation */
+	MPC512x_CLK_MCLKS_FIRST,
+	MPC512x_CLK_MCLKS_LAST = MPC512x_CLK_MCLKS_FIRST
+				+ NR_MCLKS * MCLK_MAX_IDX,
+	/* internal, symbolic spec for the number of slots */
+	MPC512x_CLK_LAST_PRIVATE,
+};
+
+/* data required for the OF clock provider registration */
+static struct clk *clks[MPC512x_CLK_LAST_PRIVATE];
+static struct clk_onecell_data clk_data;
+
+/* CCM register access */
+static struct mpc512x_ccm __iomem *clkregs;
+static DEFINE_SPINLOCK(clklock);
+
+/* convenience wrappers around the common clk API */
+static inline struct clk *mpc512x_clk_fixed(const char *name, int rate)
+{
+	return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);
+}
+
+static inline struct clk *mpc512x_clk_factor(
+	const char *name, const char *parent_name,
+	int mul, int div)
+{
+	int clkflags;
+
+	clkflags = CLK_SET_RATE_PARENT;
+	return clk_register_fixed_factor(NULL, name, parent_name, clkflags,
+					 mul, div);
+}
+
+static inline struct clk *mpc512x_clk_divider(
+	const char *name, const char *parent_name, u8 clkflags,
+	u32 __iomem *reg, u8 pos, u8 len, int divflags)
+{
+	return clk_register_divider(NULL, name, parent_name, clkflags,
+				    reg, pos, len, divflags, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_divtable(
+	const char *name, const char *parent_name,
+	u32 __iomem *reg, u8 pos, u8 len,
+	const struct clk_div_table *divtab)
+{
+	u8 divflags;
+
+	divflags = 0;
+	return clk_register_divider_table(NULL, name, parent_name, 0,
+					  reg, pos, len, divflags,
+					  divtab, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_gated(
+	const char *name, const char *parent_name,
+	u32 __iomem *reg, u8 pos)
+{
+	int clkflags;
+
+	clkflags = CLK_SET_RATE_PARENT;
+	return clk_register_gate(NULL, name, parent_name, clkflags,
+				 reg, pos, 0, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_muxed(const char *name,
+	const char **parent_names, int parent_count,
+	u32 __iomem *reg, u8 pos, u8 len)
+{
+	int clkflags;
+	u8 muxflags;
+
+	clkflags = CLK_SET_RATE_PARENT;
+	muxflags = 0;
+	return clk_register_mux(NULL, name,
+				parent_names, parent_count, clkflags,
+				reg, pos, len, muxflags, &clklock);
+}
+
+/* helper to isolate a bit field from a register */
+static inline int get_bit_field(uint32_t __iomem *reg, uint8_t pos, uint8_t len)
+{
+	uint32_t val;
+
+	val = in_be32(reg);
+	val >>= pos;
+	val &= (1 << len) - 1;
+	return val;
+}
+
+/* get the SPMF and translate it into the "sys pll" multiplier */
+static int get_spmf_mult(void)
+{
+	static int spmf_to_mult[] = {
+		68, 1, 12, 16, 20, 24, 28, 32,
+		36, 40, 44, 48, 52, 56, 60, 64,
+	};
+	int spmf;
+
+	spmf = get_bit_field(&clkregs->spmr, 24, 4);
+	return spmf_to_mult[spmf];
+}
+
+/*
+ * get the SYS_DIV value and translate it into a divide factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * divide ratio is fractional
+ */
+static int get_sys_div_x2(void)
+{
+	static int sysdiv_code_to_x2[] = {
+		4, 5, 6, 7, 8, 9, 10, 14,
+		12, 16, 18, 22, 20, 24, 26, 30,
+		28, 32, 34, 38, 36, 40, 42, 46,
+		44, 48, 50, 54, 52, 56, 58, 62,
+		60, 64, 66,
+	};
+	int divcode;
+
+	divcode = get_bit_field(&clkregs->scfr2, 26, 6);
+	return sysdiv_code_to_x2[divcode];
+}
+
+/*
+ * get the CPMF value and translate it into a multiplier factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * multiplier ratio is fractional
+ */
+static int get_cpmf_mult_x2(void)
+{
+	static int cpmf_to_mult[] = {
+		72, 2, 2, 3, 4, 5, 6, 7,
+	};
+	int cpmf;
+
+	cpmf = get_bit_field(&clkregs->spmr, 16, 4);
+	return cpmf_to_mult[cpmf];
+}
+
+/*
+ * some of the clock dividers do scale in a linear way, yet not all of
+ * their bit combinations are legal; use a divider table to get a
+ * resulting set of applicable divider values
+ */
+
+/* applies to the IPS_DIV, and PCI_DIV values */
+static struct clk_div_table divtab_2346[] = {
+	{ .val = 2, .div = 2, },
+	{ .val = 3, .div = 3, },
+	{ .val = 4, .div = 4, },
+	{ .val = 6, .div = 6, },
+	{ .div = 0, },
+};
+
+/* applies to the MBX_DIV, LPC_DIV, and NFC_DIV values */
+static struct clk_div_table divtab_1234[] = {
+	{ .val = 1, .div = 1, },
+	{ .val = 2, .div = 2, },
+	{ .val = 3, .div = 3, },
+	{ .val = 4, .div = 4, },
+	{ .div = 0, },
+};
+
+static int get_freq_from_dt(char *propname)
+{
+	struct device_node *np;
+	const unsigned int *prop;
+	int val;
+
+	val = 0;
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
+	if (np) {
+		prop = of_get_property(np, propname, NULL);
+		if (prop)
+			val = *prop;
+	    of_node_put(np);
+	}
+	return val;
+}
+
+static void mpc512x_clk_preset_data(void)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(clks); i++)
+		clks[i] = ERR_PTR(-ENODEV);
+}
+
+/*
+ * - receives the "bus frequency" from the caller (that's the IPS clock
+ *   rate, the historical source of clock information)
+ * - fetches the system PLL multiplier and divider values as well as the
+ *   IPS divider value from hardware
+ * - determines the REF clock rate either from the XTAL/OSC spec (if
+ *   there is a device tree node describing the oscillator) or from the
+ *   IPS bus clock (supported for backwards compatibility, such that
+ *   setups without XTAL/OSC specs keep working)
+ * - creates the "ref" clock item in the clock tree, such that
+ *   subsequent code can create the remainder of the hierarchy (REF ->
+ *   SYS -> CSB -> IPS) from the REF clock rate and the returned mul/div
+ *   values
+ */
+static void mpc512x_clk_setup_ref_clock(int bus_freq,
+	int *sys_mul, int *sys_div, int *ips_div)
+{
+	struct clk *osc_clk;
+	int calc_freq;
+
+	/* fetch mul/div factors from the hardware */
+	*sys_mul = get_spmf_mult();
+	*sys_mul *= 2;		/* compensate for the fractional divider */
+	*sys_div = get_sys_div_x2();
+	*ips_div = get_bit_field(&clkregs->scfr1, 23, 3);
+
+	/* lookup the oscillator node */
+	osc_clk = clk_get(NULL, "osc");
+	if (osc_clk) {
+		/* descend REF directly from OSC, verify the IPS rate */
+		clks[MPC512x_CLK_REF] = mpc512x_clk_factor("ref", "osc", 1, 1);
+		calc_freq = clk_get_rate(clks[MPC512x_CLK_REF]);
+		calc_freq *= *sys_mul;
+		calc_freq /= *sys_div;
+		calc_freq /= 2;
+		calc_freq /= *ips_div;
+		if (bus_freq && calc_freq != bus_freq)
+			pr_warn("calc rate %d != OF spec %d\n",
+				calc_freq, bus_freq);
+	} else {
+		/* calculate OSC rate and create REF from the freq value */
+		calc_freq = bus_freq;	/* start with IPS */
+		calc_freq *= *ips_div;	/* IPS -> CSB */
+		calc_freq *= 2;		/* CSB -> SYS */
+		calc_freq *= *sys_div;	/* SYS -> PLL out */
+		calc_freq /= *sys_mul;	/* PLL out -> REF == OSC */
+		clks[MPC512x_CLK_REF] = mpc512x_clk_fixed("ref", calc_freq);
+	}
+}
+
+/*
+ * helper code for the MCLK subtree setup
+ *
+ * the overview in section 5.2.4 of the MPC5121e Reference Manual rev4
+ * suggests that all instances of the "PSC clock generation" are equal,
+ * and that one might re-use the PSC setup for MSCAN clock generation
+ * (section 5.2.5) as well, at least the logic if not the data for
+ * description
+ *
+ * the details (starting at page 5-20) show differences in the specific
+ * inputs of the first mux stage ("can clk in", "spdif tx"), and the
+ * factual non-availability of the second mux stage (it's present yet
+ * only one input is valid)
+ *
+ * the MSCAN clock related registers (starting at page 5-35) all
+ * reference "spdif clk" at the first mux stage and don't mention any
+ * "can clk" at all, which somehow is unexpected
+ *
+ * TODO re-check the document, and clarify whether the RM is correct in
+ * the overview or in the details, and whether the difference is a
+ * clipboard induced error or results from chip revisions
+ *
+ * it turns out that the RM rev4 as of 2012-06 talks about "can" for the
+ * PSCs while RM rev3 as of 2008-10 talks about "spdif", so I guess that
+ * first a doc update is required which better reflects reality in the
+ * SoC before the implementation should follow while no questions remain
+ */
+
+/*
+ * note that this declaration raises a checkpatch warning, but
+ * it's the very data type which <linux/clk-provider.h> expects,
+ * making this declaration pass checkpatch will break compilation
+ */
+static const char *parent_names_mux0[] = {
+	"sys", "ref", "psc-mclk-in", "spdif-tx",
+};
+
+enum mclk_type {
+	MCLK_TYPE_PSC,
+	MCLK_TYPE_MSCAN,
+	MCLK_TYPE_SPDIF,
+};
+
+struct mclk_setup_data {
+	enum mclk_type type;
+	int comp_idx;
+	bool has_mclk1;
+	int bit_sccr1, bit_sccr2;
+	const char *name_mux0;
+	const char *name_en0;
+	const char *name_div0;
+	const char *parent_names_mux1[2];
+	const char *name_mux1;
+	const char *name_mclk;
+};
+
+#define MCLK_SETUP_DATA_PSC(id) { \
+	MCLK_TYPE_PSC, id, \
+	0, 27 - id, -1, \
+	"psc" #id "-mux0", \
+	"psc" #id "-en0", \
+	"psc" #id "_mclk_div", \
+	{ "psc" #id "_mclk_div", "dummy", }, \
+	"psc" #id "_mclk_out", \
+	"psc" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_MSCAN(id) { \
+	MCLK_TYPE_MSCAN, id, \
+	0, -1, 25, \
+	"mscan" #id "-mux0", \
+	"mscan" #id "-en0", \
+	"mscan" #id "_mclk_div", \
+	{ "mscan" #id "_mclk_div", "dummy", }, \
+	"mscan" #id "_mclk_out", \
+	"mscan" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_SPDIF { \
+	MCLK_TYPE_SPDIF, 0, \
+	1, -1, 23, \
+	"spdif-mux0", \
+	"spdif-en0", \
+	"spdif_mclk_div", \
+	{ "spdif_mclk_div", "spdif-rx", }, \
+	"spdif_mclk_out", \
+	"spdif_mclk", \
+}
+
+static struct mclk_setup_data mclk_psc_data[] = {
+	MCLK_SETUP_DATA_PSC(0),
+	MCLK_SETUP_DATA_PSC(1),
+	MCLK_SETUP_DATA_PSC(2),
+	MCLK_SETUP_DATA_PSC(3),
+	MCLK_SETUP_DATA_PSC(4),
+	MCLK_SETUP_DATA_PSC(5),
+	MCLK_SETUP_DATA_PSC(6),
+	MCLK_SETUP_DATA_PSC(7),
+	MCLK_SETUP_DATA_PSC(8),
+	MCLK_SETUP_DATA_PSC(9),
+	MCLK_SETUP_DATA_PSC(10),
+	MCLK_SETUP_DATA_PSC(11),
+};
+
+static struct mclk_setup_data mclk_mscan_data[] = {
+	MCLK_SETUP_DATA_MSCAN(0),
+	MCLK_SETUP_DATA_MSCAN(1),
+	MCLK_SETUP_DATA_MSCAN(2),
+	MCLK_SETUP_DATA_MSCAN(3),
+};
+
+static struct mclk_setup_data mclk_spdif_data[] = {
+	MCLK_SETUP_DATA_SPDIF,
+};
+
+/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
+static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
+{
+	size_t clks_idx_pub, clks_idx_int;
+	u32 __iomem *mccr_reg;	/* MCLK control register (mux, en, div) */
+	u32 __iomem *sccr_reg;	/* system clock control register (enable) */
+	int sccr_bit;
+	int div;
+
+	/* derive a few parameters from the component type and index */
+	switch (entry->type) {
+	case MCLK_TYPE_PSC:
+		clks_idx_pub = MPC512x_CLK_PSC0_MCLK + entry->comp_idx;
+		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+			     + (entry->comp_idx) * MCLK_MAX_IDX;
+		mccr_reg = &clkregs->psc_ccr[entry->comp_idx];
+		break;
+	case MCLK_TYPE_MSCAN:
+		clks_idx_pub = MPC512x_CLK_MSCAN0_MCLK + entry->comp_idx;
+		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+			     + (NR_PSCS + entry->comp_idx) * MCLK_MAX_IDX;
+		mccr_reg = &clkregs->mscan_ccr[entry->comp_idx];
+		break;
+	case MCLK_TYPE_SPDIF:
+		clks_idx_pub = MPC512x_CLK_SPDIF_MCLK;
+		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+			     + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
+		mccr_reg = &clkregs->spccr;
+		break;
+	default:
+		return;
+	}
+	if (entry->bit_sccr1 >= 0) {
+		sccr_reg = &clkregs->sccr1;
+		sccr_bit = entry->bit_sccr1;
+	} else if (entry->bit_sccr2 >= 0) {
+		sccr_reg = &clkregs->sccr2;
+		sccr_bit = entry->bit_sccr2;
+	} else {
+		sccr_reg = NULL;
+	}
+
+	/*
+	 * this was grabbed from the PPC_CLOCK implementation, which
+	 * enforced a specific MCLK divider while the clock was gated
+	 * during setup (that's a documented hardware requirement)
+	 *
+	 * the PPC_CLOCK implementation might even have violated the
+	 * "MCLK <= IPS" constraint, the fixed divider value of 1
+	 * results in a divider of 2 and thus MCLK = SYS/2 which equals
+	 * CSB which is greater than IPS; the serial port setup may have
+	 * adjusted the divider which the clock setup might have left in
+	 * an undesirable state
+	 *
+	 * initial setup is:
+	 * - MCLK 0 from SYS
+	 * - MCLK DIV such to not exceed the IPS clock
+	 * - MCLK 0 enabled
+	 * - MCLK 1 from MCLK DIV
+	 */
+	div = clk_get_rate(clks[MPC512x_CLK_SYS]);
+	div /= clk_get_rate(clks[MPC512x_CLK_IPS]);
+	out_be32(mccr_reg, (0 << 16));
+	out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
+	out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
+
+	/*
+	 * create the 'struct clk' items of the MCLK's clock subtree
+	 *
+	 * note that by design we always create all nodes and won't take
+	 * shortcuts here, because
+	 * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
+	 *   selectable inputs to the CFM while those who "actually use"
+	 *   the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
+	 *   for their bitrate
+	 * - in the absence of "aliases" for clocks we need to create
+	 *   individial 'struct clk' items for whatever might get
+	 *   referenced or looked up, even if several of those items are
+	 *   identical from the logical POV (their rate value)
+	 * - for easier future maintenance and for better reflection of
+	 *   the SoC's documentation, it appears appropriate to generate
+	 *   clock items even for those muxers which actually are NOPs
+	 *   (those with two inputs of which one is reserved)
+	 */
+	clks[clks_idx_int + MCLK_IDX_MUX0] = mpc512x_clk_muxed(
+			entry->name_mux0,
+			&parent_names_mux0[0], ARRAY_SIZE(parent_names_mux0),
+			mccr_reg, 14, 2);
+	clks[clks_idx_int + MCLK_IDX_EN0] = mpc512x_clk_gated(
+			entry->name_en0, entry->name_mux0,
+			mccr_reg, 16);
+	clks[clks_idx_int + MCLK_IDX_DIV0] = mpc512x_clk_divider(
+			entry->name_div0,
+			entry->name_en0, CLK_SET_RATE_GATE,
+			mccr_reg, 17, 15, 0);
+	if (entry->has_mclk1) {
+		clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_muxed(
+				entry->name_mux1,
+				&entry->parent_names_mux1[0],
+				ARRAY_SIZE(entry->parent_names_mux1),
+				mccr_reg, 7, 1);
+	} else {
+		clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_factor(
+				entry->name_mux1, entry->parent_names_mux1[0],
+				1, 1);
+	}
+	if (sccr_reg) {
+		clks[clks_idx_pub] = mpc512x_clk_gated(
+				entry->name_mclk,
+				entry->name_mux1, sccr_reg, sccr_bit);
+	} else {
+		clks[clks_idx_pub] = mpc512x_clk_factor(
+				entry->name_mclk,
+				entry->name_mux1, 1, 1);
+	}
+
+	/*
+	 * without this "clock device" registration, "simple" lookups in
+	 * the SPI master initialization and serial port setup will fail
+	 *
+	 * those drivers need to get adjusted to lookup their required
+	 * clocks from device tree specs, and device tree nodes need to
+	 * provide the clock specs, before this clkdev registration
+	 * becomes obsolete
+	 */
+	clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
+}
+
+static void mpc512x_clk_setup_mclks(struct mclk_setup_data *table, size_t count)
+{
+	while (count-- > 0)
+		mpc512x_clk_setup_mclk(table++);
+}
+
+static void mpc512x_clk_setup_clock_tree(int busfreq)
+{
+	int sys_mul, sys_div, ips_div;
+	int mul, div;
+	int freq;
+
+	/*
+	 * TODO
+	 * - consider whether to handle clocks which have both gates and
+	 *   dividers via intermediates or by means of composites
+	 * - fractional dividers appear to not map well to composites
+	 *   since they can be seen as a fixed multiplier and an
+	 *   adjustable divider, while composites can only combine at
+	 *   most one of a mux, div, and gate each into one 'struct clk'
+	 *   item
+	 * - PSC/MSCAN/SPDIF clock generation OTOH already is very
+	 *   specific and cannot get mapped to componsites (at least not
+	 *   a single one, maybe two of them, but see the comment about
+	 *   "intermediates are referenced from elsewhere, too")
+	 * - trim the list of auto-enabled clocks after drivers acquire
+	 *   them correctly as needed
+	 */
+
+	/* regardless of whether XTAL/OSC exists, have REF created */
+	mpc512x_clk_setup_ref_clock(busfreq, &sys_mul, &sys_div, &ips_div);
+
+	/* now setup the REF -> SYS -> CSB -> IPS hierarchy */
+	clks[MPC512x_CLK_SYS] = mpc512x_clk_factor("sys", "ref",
+						   sys_mul, sys_div);
+	clks[MPC512x_CLK_CSB] = mpc512x_clk_factor("csb", "sys", 1, 2);
+	clks[MPC512x_CLK_IPS] = mpc512x_clk_divtable("ips", "csb",
+						     &clkregs->scfr1, 23, 3,
+						     divtab_2346);
+
+	/* now setup anything below SYS and CSB and IPS */
+	clks[MPC512x_CLK_DDR_UG] = mpc512x_clk_factor("ddr-ug", "sys", 1, 2);
+	clks[MPC512x_CLK_SDHC_x4] = mpc512x_clk_factor("sdhc-x4", "csb", 4, 1);
+	clks[MPC512x_CLK_SDHC_UG] = mpc512x_clk_divider("sdhc-ug", "sdhc-x4", 0,
+							&clkregs->scfr2, 0, 8,
+							CLK_DIVIDER_ONE_BASED);
+	clks[MPC512x_CLK_DIU_x4] = mpc512x_clk_factor("diu-x4", "csb", 4, 1);
+	clks[MPC512x_CLK_DIU_UG] = mpc512x_clk_divider("diu-ug", "diu-x4", 0,
+						       &clkregs->scfr1, 0, 8,
+						       CLK_DIVIDER_ONE_BASED);
+
+	/*
+	 * the "power architecture PLL" was setup from data which was
+	 * sampled from the reset config word, at this point in time the
+	 * configuration can be considered fixed and read only (i.e. no
+	 * longer adjustable, or no longer in need of adjustment), which
+	 * is why we don't register a PLL here but assume fixed factors
+	 */
+	mul = get_cpmf_mult_x2();
+	div = 2;	/* compensate for the fractional factor */
+	clks[MPC512x_CLK_E300] = mpc512x_clk_factor("e300", "csb", mul, div);
+
+	clks[MPC512x_CLK_MBX_BUS_UG] = mpc512x_clk_factor("mbx-bus-ug", "csb",
+							  1, 2);
+	clks[MPC512x_CLK_MBX_UG] = mpc512x_clk_divtable("mbx-ug", "mbx-bus-ug",
+							&clkregs->scfr1, 14, 3,
+							divtab_1234);
+	clks[MPC512x_CLK_MBX_3D_UG] = mpc512x_clk_factor("mbx-3d-ug", "mbx-ug",
+							 1, 1);
+	clks[MPC512x_CLK_PCI_UG] = mpc512x_clk_divtable("pci-ug", "csb",
+							&clkregs->scfr1, 20, 3,
+							divtab_2346);
+	clks[MPC512x_CLK_NFC_UG] = mpc512x_clk_divtable("nfc-ug", "ips",
+							&clkregs->scfr1, 8, 3,
+							divtab_1234);
+	clks[MPC512x_CLK_LPC_UG] = mpc512x_clk_divtable("lpc-ug", "ips",
+							&clkregs->scfr1, 11, 3,
+							divtab_1234);
+
+	clks[MPC512x_CLK_LPC] = mpc512x_clk_gated("lpc", "lpc-ug",
+						  &clkregs->sccr1, 30);
+	clks[MPC512x_CLK_NFC] = mpc512x_clk_gated("nfc", "nfc-ug",
+						  &clkregs->sccr1, 29);
+	clks[MPC512x_CLK_PATA] = mpc512x_clk_gated("pata", "ips",
+						   &clkregs->sccr1, 28);
+	mpc512x_clk_setup_mclks(mclk_psc_data, ARRAY_SIZE(mclk_psc_data));
+	clks[MPC512x_CLK_PSC_FIFO] = mpc512x_clk_gated("psc-fifo", "ips",
+						       &clkregs->sccr1, 15);
+	clks[MPC512x_CLK_SATA] = mpc512x_clk_gated("sata", "ips",
+						   &clkregs->sccr1, 14);
+	clks[MPC512x_CLK_FEC] = mpc512x_clk_gated("fec", "ips",
+						  &clkregs->sccr1, 13);
+	clks[MPC512x_CLK_PCI] = mpc512x_clk_gated("pci", "pci-ug",
+						  &clkregs->sccr1, 11);
+	clks[MPC512x_CLK_DDR] = mpc512x_clk_gated("ddr", "ddr-ug",
+						  &clkregs->sccr1, 10);
+
+	clks[MPC512x_CLK_DIU] = mpc512x_clk_gated("diu", "diu-ug",
+						  &clkregs->sccr2, 31);
+	clks[MPC512x_CLK_AXE] = mpc512x_clk_gated("axe", "csb",
+						  &clkregs->sccr2, 30);
+	clks[MPC512x_CLK_MEM] = mpc512x_clk_gated("mem", "ips",
+						  &clkregs->sccr2, 29);
+	clks[MPC512x_CLK_USB1] = mpc512x_clk_gated("usb1", "csb",
+						   &clkregs->sccr2, 28);
+	clks[MPC512x_CLK_USB2] = mpc512x_clk_gated("usb2", "csb",
+						   &clkregs->sccr2, 27);
+	clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips",
+						  &clkregs->sccr2, 26);
+	mpc512x_clk_setup_mclks(mclk_mscan_data, ARRAY_SIZE(mclk_mscan_data));
+	clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug",
+						   &clkregs->sccr2, 24);
+	mpc512x_clk_setup_mclks(mclk_spdif_data, ARRAY_SIZE(mclk_spdif_data));
+	clks[MPC512x_CLK_MBX_BUS] = mpc512x_clk_gated("mbx-bus", "mbx-bus-ug",
+						      &clkregs->sccr2, 22);
+	clks[MPC512x_CLK_MBX] = mpc512x_clk_gated("mbx", "mbx-ug",
+						  &clkregs->sccr2, 21);
+	clks[MPC512x_CLK_MBX_3D] = mpc512x_clk_gated("mbx-3d", "mbx-3d-ug",
+						     &clkregs->sccr2, 20);
+	clks[MPC512x_CLK_IIM] = mpc512x_clk_gated("iim", "csb",
+						  &clkregs->sccr2, 19);
+	clks[MPC512x_CLK_VIU] = mpc512x_clk_gated("viu", "csb",
+						  &clkregs->sccr2, 18);
+	clks[MPC512x_CLK_SDHC_2] = mpc512x_clk_gated("sdhc-2", "sdhc-ug",
+						     &clkregs->sccr2, 17);
+
+	/*
+	 * externally provided clocks (when implemented in hardware,
+	 * device tree may specify values which otherwise were unknown)
+	 */
+	freq = get_freq_from_dt("psc_mclk_in");
+	if (!freq)
+		freq = 25000000;
+	clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq);
+	freq = get_freq_from_dt("spdif_tx_in");
+	clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_tx_in", freq);
+	freq = get_freq_from_dt("spdif_rx_in");
+	clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_rx_in", freq);
+
+	/* fixed frequency for AC97, always 24.567MHz */
+	clks[MPC512x_CLK_AC97] = mpc512x_clk_fixed("ac97", 24567000);
+
+	pr_debug("clock tree setup complete\n");
+	freq = clk_get_rate(clks[MPC512x_CLK_E300]);
+	pr_debug("derived PPC freq [%d]\n", freq);
+	freq = clk_get_rate(clks[MPC512x_CLK_IPS]);
+	pr_debug("derived IPS freq [%d]\n", freq);
+	freq = clk_get_rate(clks[MPC512x_CLK_LPC]);
+	pr_debug("derived LPC freq [%d]\n", freq);
+
+	/* enable some of the clocks here unconditionally because ... */
+	pr_debug("automatically enabling some clocks\n");
+	/* some are essential yet never get claimed by any driver */
+	clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
+	clk_prepare_enable(clks[MPC512x_CLK_E300]);	/* PowerPC CPU */
+	clk_prepare_enable(clks[MPC512x_CLK_DDR]);	/* DRAM */
+	clk_prepare_enable(clks[MPC512x_CLK_MEM]);	/* SRAM */
+	clk_prepare_enable(clks[MPC512x_CLK_IPS]);	/* SoC periph */
+	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
+	/* some are required yet no dependencies were declared */
+	clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
+	/* some are not yet acquired by their respective drivers */
+	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
+	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
+	clk_prepare_enable(clks[MPC512x_CLK_DIU]);	/* display */
+	clk_prepare_enable(clks[MPC512x_CLK_I2C]);
+	/*
+	 * some have their individual clock subtree with separate clock
+	 * items and their individual enable counters, yet share a
+	 * common gate (refer to the same register location) while the
+	 * common clock driver code is not aware of the fact and the
+	 * platform's code doesn't provide specific support either
+	 *
+	 * what might happen is that e.g. enabling two MSCAN clock items
+	 * and disabling one of them will disable the common gate and
+	 * thus break the other MSCAN clock as well
+	 */
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN0_MCLK]);
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN1_MCLK]);
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN2_MCLK]);
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN3_MCLK]);
+}
+
+/*
+ * registers the set of public clocks (those listed in the dt-bindings/
+ * header file) for OF lookups, keeps the intermediates private to us
+ */
+static void mpc5121_clk_register_of_provider(struct device_node *np)
+{
+	clk_data.clks = clks;
+	clk_data.clk_num = MPC512x_CLK_LAST_PUBLIC + 1;	/* _not_ ARRAY_SIZE() */
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+int __init mpc5121_clk_init(void)
+{
+	struct device_node *clk_np;
+	int busfreq;
+
+	/* map the clock control registers */
+	clk_np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+	if (!clk_np)
+		return -ENODEV;
+	clkregs = of_iomap(clk_np, 0);
+	WARN_ON(!clkregs);
+
+	/* invalidate all not yet registered clock slots */
+	mpc512x_clk_preset_data();
+
+	/*
+	 * have the device tree scanned for "fixed-clock" nodes (which
+	 * includes the oscillator node if the board's DT provides one)
+	 */
+	of_clk_init(NULL);
+
+	/*
+	 * add a dummy clock for those situations where a clock spec is
+	 * required yet no real clock is involved
+	 */
+	clks[MPC512x_CLK_DUMMY] = mpc512x_clk_fixed("dummy", 0);
+
+	/*
+	 * have all the real nodes in the clock tree populated from REF
+	 * down to all leaves, either starting from the OSC node or from
+	 * a REF root that was created from the IPS bus clock input
+	 */
+	busfreq = get_freq_from_dt("bus-frequency");
+	mpc512x_clk_setup_clock_tree(busfreq);
+
+	/* register as an OF clock provider */
+	mpc5121_clk_register_of_provider(clk_np);
+
+	return 0;
+}
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index c4f7799..7f8fc64 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -497,6 +497,20 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
  * for improved portability across platforms
  */
 
+#if IS_ENABLED(CONFIG_PPC)
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+	return ioread32be(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+	iowrite32be(val, reg);
+}
+
+#else	/* platform dependent I/O accessors */
+
 static inline u32 clk_readl(u32 __iomem *reg)
 {
 	return readl(reg);
@@ -507,5 +521,7 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
 	writel(val, reg);
 }
 
+#endif	/* platform dependent I/O accessors */
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
-- 
1.7.10.4

[PATCH v2 10/24] dts: mpc512x: add clock specs for client lookups

From: Gerhard Sittig <hidden>
Date: 2013-07-18 17:00:41

this addresses the client side of device tree based clock lookups:
add clock specifiers to the mbx, nfc, mscan, sdhc, i2c, axe, diu,
viu, mdio, fec, usb, pata, psc, psc fifo, and pci nodes in the
shared mpc5121.dtsi include

these specs map 'clock-names' encoded in drivers to their respective
'struct clk' items in the platform's clock driver; some drivers
still need to learn how to lookup OF clocks, other drivers will
transparently probe successfully on MPC512x as well (sdhc)

few 'clock-names' (nfc, viu) use strings that are encoded in their
respective drivers to keep up compatibility, an alternative approach
would be to register clkdev items in the platform's clock driver for
the migration period

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/boot/dts/mpc5121.dtsi |   79 ++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
index 8f4cba0..983da9c 100644
--- a/arch/powerpc/boot/dts/mpc5121.dtsi
+++ b/arch/powerpc/boot/dts/mpc5121.dtsi
@@ -51,6 +51,10 @@
 		compatible = "fsl,mpc5121-mbx";
 		reg = <0x20000000 0x4000>;
 		interrupts = <66 0x8>;
+		clocks = <&clks MPC512x_CLK_MBX_BUS>,
+			 <&clks MPC512x_CLK_MBX_3D>,
+			 <&clks MPC512x_CLK_MBX>;
+		clock-names = "mbx-bus", "mbx-3d", "mbx";
 	};
 
 	sram@30000000 {
@@ -64,6 +68,8 @@
 		interrupts = <6 8>;
 		#address-cells = <1>;
 		#size-cells = <1>;
+		clocks = <&clks MPC512x_CLK_NFC>;
+		clock-names = "nfc_clk";	/* backwards compat */
 	};
 
 	localbus@80000020 {
@@ -153,12 +159,22 @@
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x1300 0x80>;
 			interrupts = <12 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN0_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		can@1380 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x1380 0x80>;
 			interrupts = <13 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN1_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		sdhc@1500 {
@@ -167,6 +183,9 @@
 			interrupts = <8 0x8>;
 			dmas = <&dma0 30>;
 			dma-names = "rx-tx";
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SDHC>;
+			clock-names = "ipg", "per";
 		};
 
 		i2c@1700 {
@@ -175,6 +194,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1700 0x20>;
 			interrupts = <9 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2c@1720 {
@@ -183,6 +204,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1720 0x20>;
 			interrupts = <10 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2c@1740 {
@@ -191,6 +214,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1740 0x20>;
 			interrupts = <11 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2ccontrol@1760 {
@@ -202,30 +227,46 @@
 			compatible = "fsl,mpc5121-axe";
 			reg = <0x2000 0x100>;
 			interrupts = <42 0x8>;
+			clocks = <&clks MPC512x_CLK_AXE>;
+			clock-names = "per";
 		};
 
 		display@2100 {
 			compatible = "fsl,mpc5121-diu";
 			reg = <0x2100 0x100>;
 			interrupts = <64 0x8>;
+			clocks = <&clks MPC512x_CLK_DIU>;
+			clock-names = "per";
 		};
 
 		can@2300 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x2300 0x80>;
 			interrupts = <90 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN2_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		can@2380 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x2380 0x80>;
 			interrupts = <91 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN3_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		viu@2400 {
 			compatible = "fsl,mpc5121-viu";
 			reg = <0x2400 0x400>;
 			interrupts = <67 0x8>;
+			clocks = <&clks MPC512x_CLK_VIU>;
+			clock-names = "viu_clk";	/* backwards compat */
 		};
 
 		mdio@2800 {
@@ -233,6 +274,8 @@
 			reg = <0x2800 0x800>;
 			#address-cells = <1>;
 			#size-cells = <0>;
+			clocks = <&clks MPC512x_CLK_FEC>;
+			clock-names = "per";
 		};
 
 		eth0: ethernet@2800 {
@@ -241,6 +284,8 @@
 			reg = <0x2800 0x800>;
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <4 0x8>;
+			clocks = <&clks MPC512x_CLK_FEC>;
+			clock-names = "per";
 		};
 
 		/* USB1 using external ULPI PHY */
@@ -252,6 +297,8 @@
 			interrupts = <43 0x8>;
 			dr_mode = "otg";
 			phy_type = "ulpi";
+			clocks = <&clks MPC512x_CLK_USB1>;
+			clock-names = "per";
 		};
 
 		/* USB0 using internal UTMI PHY */
@@ -263,6 +310,8 @@
 			interrupts = <44 0x8>;
 			dr_mode = "otg";
 			phy_type = "utmi_wide";
+			clocks = <&clks MPC512x_CLK_USB2>;
+			clock-names = "per";
 		};
 
 		/* IO control */
@@ -281,6 +330,8 @@
 			compatible = "fsl,mpc5121-pata";
 			reg = <0x10200 0x100>;
 			interrupts = <5 0x8>;
+			clocks = <&clks MPC512x_CLK_PATA>;
+			clock-names = "per";
 		};
 
 		/* 512x PSCs are not 52xx PSC compatible */
@@ -292,6 +343,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC0_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC1 */
@@ -301,6 +354,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC1_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC2 */
@@ -310,6 +365,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC2_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC3 */
@@ -319,6 +376,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC3_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC4 */
@@ -328,6 +387,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC4_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC5 */
@@ -337,6 +398,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC5_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC6 */
@@ -346,6 +409,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC6_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC7 */
@@ -355,6 +420,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC7_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC8 */
@@ -364,6 +431,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC8_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC9 */
@@ -373,6 +442,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC9_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC10 */
@@ -382,6 +453,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC10_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC11 */
@@ -391,12 +464,16 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC11_MCLK>;
+			clock-names = "mclk";
 		};
 
 		pscfifo@11f00 {
 			compatible = "fsl,mpc5121-psc-fifo";
 			reg = <0x11f00 0x100>;
 			interrupts = <40 0x8>;
+			clocks = <&clks MPC512x_CLK_PSC_FIFO>;
+			clock-names = "per";
 		};
 
 		dma0: dma@14000 {
@@ -414,6 +491,8 @@
 		#address-cells = <3>;
 		#size-cells = <2>;
 		#interrupt-cells = <1>;
+		clocks = <&clks MPC512x_CLK_PCI>;
+		clock-names = "per";
 
 		reg = <0x80008500 0x100	/* internal registers */
 		       0x80008300 0x8>;	/* config space access registers */
-- 
1.7.10.4

[PATCH v2 11/24] spi: mpc512x: remove now obsolete clock lookup name

From: Gerhard Sittig <hidden>
Date: 2013-07-18 17:00:42

after device tree based clock lookup became available, the peripheral
driver need no longer construct clock names which include the PSC index,
remove the "psc%d_mclk" template and unconditionally use "mclk"

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/spi/spi-mpc512x-psc.c |    6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 7a32373..b04f094 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -474,8 +474,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 	struct spi_master *master;
 	int ret;
 	void *tempp;
-	int psc_num;
-	char clk_name[16];
 
 	master = spi_alloc_master(dev, sizeof *mps);
 	if (master == NULL)
@@ -518,9 +516,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 		goto free_master;
 	init_completion(&mps->txisrdone);
 
-	psc_num = master->bus_num;
-	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-	mps->clk_mclk = clk_get(dev, clk_name);
+	mps->clk_mclk = clk_get(dev, "mclk");
 	if (IS_ERR(mps->clk_mclk))
 		goto free_irq;
 	ret = clk_prepare_enable(mps->clk_mclk);
-- 
1.7.10.4

[PATCH v2 12/24] serial: mpc512x: remove now obsolete clock lookup name

From: Gerhard Sittig <hidden>
Date: 2013-07-18 17:00:43

after device tree based clock lookup became available, the peripheral
driver need no longer construct clock names which include the PSC index,
remove the "psc%d_mclk" template and unconditionally use "mclk"

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/tty/serial/mpc52xx_uart.c |    8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 98a1f43..8643dcf 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -623,14 +623,11 @@ static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM];
 /* called from within the .request_port() callback (allocation) */
 static int mpc512x_psc_alloc_clock(struct uart_port *port)
 {
-	int psc_num;
-	char clk_name[16];
 	struct clk *clk;
 	int err;
+	int psc_num;
 
-	psc_num = (port->mapbase & 0xf00) >> 8;
-	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-	clk = clk_get(port->dev, clk_name);
+	clk = clk_get(port->dev, "mclk");
 	if (IS_ERR(clk)) {
 		dev_err(port->dev, "Failed to get MCLK!\n");
 		return PTR_ERR(clk);
@@ -641,6 +638,7 @@ static int mpc512x_psc_alloc_clock(struct uart_port *port)
 		clk_put(clk);
 		return err;
 	}
+	psc_num = (port->mapbase & 0xf00) >> 8;
 	psc_mclk_clk[psc_num] = clk;
 	return 0;
 }
-- 
1.7.10.4

[PATCH v2 13/24] clk: mpc512x: remove now obsolete clkdev registration

From: Gerhard Sittig <hidden>
Date: 2013-07-18 17:00:44

after the peripheral drivers for UART and SPI mode (both using the PSC
controller) got converted to device tree based clock lookups, the
platform clock driver need no longer provide the "psc%d_mclk" name which
depends on the PSC index number -- remove the clk_register_clkdev() call

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/clock-commonclk.c |   12 ------------
 1 file changed, 12 deletions(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index 6627957..b822469 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -12,7 +12,6 @@
  */
 
 #include <linux/clk-provider.h>
-#include <linux/clkdev.h>
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/io.h>
@@ -529,17 +528,6 @@ static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
 				entry->name_mclk,
 				entry->name_mux1, 1, 1);
 	}
-
-	/*
-	 * without this "clock device" registration, "simple" lookups in
-	 * the SPI master initialization and serial port setup will fail
-	 *
-	 * those drivers need to get adjusted to lookup their required
-	 * clocks from device tree specs, and device tree nodes need to
-	 * provide the clock specs, before this clkdev registration
-	 * becomes obsolete
-	 */
-	clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
 }
 
 static void mpc512x_clk_setup_mclks(struct mclk_setup_data *table, size_t count)
-- 
1.7.10.4

[PATCH v2 14/24] serial: mpc512x: setup the PSC FIFO clock as well

From: Gerhard Sittig <hidden>
Date: 2013-07-18 17:00:45

prepare and enable the FIFO clock upon PSC FIFO initialization,
disable and unprepare the FIFO clock upon PSC FIFO uninitialization,
remove the pre-enable workaround from the platform's clock driver

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/clock-commonclk.c |    2 --
 drivers/tty/serial/mpc52xx_uart.c             |   39 +++++++++++++++++++++----
 2 files changed, 33 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index b822469..99d197d 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -689,8 +689,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	clk_prepare_enable(clks[MPC512x_CLK_MEM]);	/* SRAM */
 	clk_prepare_enable(clks[MPC512x_CLK_IPS]);	/* SoC periph */
 	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
-	/* some are required yet no dependencies were declared */
-	clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
 	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 8643dcf..3fdadf9 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -421,6 +421,7 @@ struct psc_fifoc {
 
 static struct psc_fifoc __iomem *psc_fifoc;
 static unsigned int psc_fifoc_irq;
+static struct clk *psc_fifoc_clk;
 
 static void mpc512x_psc_fifo_init(struct uart_port *port)
 {
@@ -574,30 +575,56 @@ static int __init mpc512x_psc_fifoc_init(void)
 				     "fsl,mpc5121-psc-fifo");
 	if (!np) {
 		pr_err("%s: Can't find FIFOC node\n", __func__);
-		return -ENODEV;
+		goto out_err;
+	}
+
+	psc_fifoc_clk = of_clk_get_by_name(np, "per");
+	if (IS_ERR(psc_fifoc_clk)) {
+		pr_err("%s: Can't lookup FIFO clock\n", __func__);
+		goto out_ofnode_put;
+	}
+	if (clk_prepare_enable(psc_fifoc_clk)) {
+		pr_err("%s: Can't enable FIFO clock\n", __func__);
+		goto out_clk_put;
 	}
 
 	psc_fifoc = of_iomap(np, 0);
 	if (!psc_fifoc) {
 		pr_err("%s: Can't map FIFOC\n", __func__);
-		of_node_put(np);
-		return -ENODEV;
+		goto out_clk_disable;
 	}
 
 	psc_fifoc_irq = irq_of_parse_and_map(np, 0);
-	of_node_put(np);
 	if (psc_fifoc_irq == 0) {
 		pr_err("%s: Can't get FIFOC irq\n", __func__);
-		iounmap(psc_fifoc);
-		return -ENODEV;
+		goto out_unmap;
 	}
 
+	of_node_put(np);
 	return 0;
+
+out_unmap:
+	iounmap(psc_fifoc);
+out_clk_disable:
+	clk_disable_unprepare(psc_fifoc_clk);
+out_clk_put:
+	clk_put(psc_fifoc_clk);
+out_ofnode_put:
+	of_node_put(np);
+out_err:
+	return -ENODEV;
 }
 
 static void __exit mpc512x_psc_fifoc_uninit(void)
 {
 	iounmap(psc_fifoc);
+
+	/* disable the clock, errors are not fatal */
+	if (psc_fifoc_clk && !IS_ERR(psc_fifoc_clk)) {
+		clk_disable_unprepare(psc_fifoc_clk);
+		clk_put(psc_fifoc_clk);
+		psc_fifoc_clk = NULL;
+	}
 }
 
 /* 512x specific interrupt handler. The caller holds the port lock */
-- 
1.7.10.4

[PATCH v2 15/24] net: can: mscan: add a comment on reg to idx mapping

From: Gerhard Sittig <hidden>
Date: 2013-07-18 20:20:49

add a comment about the magic of deriving an MSCAN component index
from the peripheral's physical address / register offset

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/net/can/mscan/mpc5xxx_can.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index 5b0ee8e..bc422ba 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -148,7 +148,10 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 		goto exit_put;
 	}
 
-	/* Determine the MSCAN device index from the physical address */
+	/* Determine the MSCAN device index from the peripheral's
+	 * physical address. Register address offsets against the
+	 * IMMR base are:  0x1300, 0x1380, 0x2300, 0x2380
+	 */
 	pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
 	BUG_ON(!pval || plen < sizeof(*pval));
 	clockidx = (*pval & 0x80) ? 1 : 0;
-- 
1.7.10.4

[PATCH v2 18/24] i2c: mpc: OF clock lookup for MPC512x

From: Gerhard Sittig <hidden>
Date: 2013-07-18 20:20:52

make the MPC I2C driver prepare and enable the peripheral clock
('per' for register access) in the MPC512x setup routine,
make this clock setup non-fatal to allow for a migration period,
remove the pre-enabling hack in the platform's clock driver

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/clock-commonclk.c |    1 -
 drivers/i2c/busses/i2c-mpc.c                  |    9 +++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index b8963b7..49c52bc 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -692,7 +692,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
 	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
-	clk_prepare_enable(clks[MPC512x_CLK_I2C]);
 	/*
 	 * some have their individual clock subtree with separate clock
 	 * items and their individual enable counters, yet share a
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 7607dc0..13d6822 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -21,6 +21,7 @@
 #include <linux/of_i2c.h>
 #include <linux/slab.h>
 
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/fsl_devices.h>
 #include <linux/i2c.h>
@@ -264,11 +265,19 @@ static void mpc_i2c_setup_512x(struct device_node *node,
 					 struct mpc_i2c *i2c,
 					 u32 clock, u32 prescaler)
 {
+	struct clk *clk;
 	struct device_node *node_ctrl;
 	void __iomem *ctrl;
 	const u32 *pval;
 	u32 idx;
 
+	/* enable clock for the I2C peripheral (non fatal) */
+	clk = of_clk_get_by_name(node, "per");
+	if (!IS_ERR(clk)) {
+		clk_prepare_enable(clk);
+		clk_put(clk);
+	}
+
 	/* Enable I2C interrupts for mpc5121 */
 	node_ctrl = of_find_compatible_node(NULL, NULL,
 					    "fsl,mpc5121-i2c-ctrl");
-- 
1.7.10.4

[PATCH v2 19/24] USB: fsl-mph-dr-of: OF clock lookup, prepare and enable

From: Gerhard Sittig <hidden>
Date: 2013-07-18 20:20:53

device tree based clock lookup in the MPC512x initialization (lookup
'per' for register access), add error check in the clock setup, must
prepare clocks before they can get enabled, unprepare after disable

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/usb/host/fsl-mph-dr-of.c |   24 +++++++++---------------
 1 file changed, 9 insertions(+), 15 deletions(-)
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 11e0b79..eb564f3 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -260,25 +260,19 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)
 {
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 	struct clk *clk;
-	char clk_name[10];
-	int base, clk_num;
-
-	base = pdev->resource->start & 0xf000;
-	if (base == 0x3000)
-		clk_num = 1;
-	else if (base == 0x4000)
-		clk_num = 2;
-	else
-		return -ENODEV;
+	int err;
 
-	snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num);
-	clk = clk_get(&pdev->dev, clk_name);
+	clk = clk_get(&pdev->dev, "per");
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "failed to get clk\n");
 		return PTR_ERR(clk);
 	}
-
-	clk_enable(clk);
+	err = clk_prepare_enable(clk);
+	if (err) {
+		dev_err(&pdev->dev, "failed to enable clk\n");
+		clk_put(clk);
+		return err;
+	}
 	pdata->clk = clk;
 
 	if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
@@ -303,7 +297,7 @@ static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
 	pdata->regs = NULL;
 
 	if (pdata->clk) {
-		clk_disable(pdata->clk);
+		clk_disable_unprepare(pdata->clk);
 		clk_put(pdata->clk);
 	}
 }
-- 
1.7.10.4

[PATCH v2 20/24] fs_enet: OF clock lookup (non-fatal), prepare and enable

From: Gerhard Sittig <hidden>
Date: 2013-07-18 20:20:54

device tree based clock lookup, must prepare clocks before enabling
them, unprepare after disable, error check in the clock setup, remove
the pre-enable workaround in the MPC512x platform's clock driver

this change implements non-fatal clock lookup since not all platforms
provide device tree specs for clocks, but failure to enable a specified
clock is considered fatal

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/clock-commonclk.c      |    1 -
 .../net/ethernet/freescale/fs_enet/fs_enet-main.c  |   27 +++++++++++++++++++-
 include/linux/fs_enet_pd.h                         |    3 +++
 3 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index 49c52bc..e9451a7 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -691,7 +691,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
-	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
 	/*
 	 * some have their individual clock subtree with separate clock
 	 * items and their individual enable counters, yet share a
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index 8de53a1..df92e12 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -1020,6 +1020,21 @@ static int fs_enet_probe(struct platform_device *ofdev)
 		fpi->cp_command = *data;
 	}
 
+	/* make clock lookup non-fatal (the driver is shared among platforms),
+	 * but require enable to succeed when a clock was specified/found
+	 */
+	fpi->clk_per = clk_get(&ofdev->dev, "per");
+	if (IS_ERR(fpi->clk_per))
+		fpi->clk_per = NULL;
+	if (fpi->clk_per) {
+		int err;
+		err = clk_prepare_enable(fpi->clk_per);
+		if (err) {
+			ret = err;
+			goto out_clk_put;
+		}
+	}
+
 	fpi->rx_ring = 32;
 	fpi->tx_ring = 32;
 	fpi->rx_copybreak = 240;
@@ -1028,7 +1043,7 @@ static int fs_enet_probe(struct platform_device *ofdev)
 	fpi->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0);
 	if ((!fpi->phy_node) && (!of_get_property(ofdev->dev.of_node, "fixed-link",
 						  NULL)))
-		goto out_free_fpi;
+		goto out_clk_dis;
 
 	if (of_device_is_compatible(ofdev->dev.of_node, "fsl,mpc5125-fec")) {
 		phy_connection_type = of_get_property(ofdev->dev.of_node,
@@ -1108,6 +1123,12 @@ out_free_dev:
 	free_netdev(ndev);
 out_put:
 	of_node_put(fpi->phy_node);
+out_clk_dis:
+	if (fpi->clk_per)
+		clk_disable_unprepare(fpi->clk_per);
+out_clk_put:
+	if (fpi->clk_per)
+		clk_put(fpi->clk_per);
 out_free_fpi:
 	kfree(fpi);
 	return ret;
@@ -1124,6 +1145,10 @@ static int fs_enet_remove(struct platform_device *ofdev)
 	fep->ops->cleanup_data(ndev);
 	dev_set_drvdata(fep->dev, NULL);
 	of_node_put(fep->fpi->phy_node);
+	if (fep->fpi->clk_per) {
+		clk_disable_unprepare(fep->fpi->clk_per);
+		clk_put(fep->fpi->clk_per);
+	}
 	free_netdev(ndev);
 	return 0;
 }
diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h
index 51b7934..a978d0d 100644
--- a/include/linux/fs_enet_pd.h
+++ b/include/linux/fs_enet_pd.h
@@ -16,6 +16,7 @@
 #ifndef FS_ENET_PD_H
 #define FS_ENET_PD_H
 
+#include <linux/clk.h>
 #include <linux/string.h>
 #include <linux/of_mdio.h>
 #include <asm/types.h>
@@ -142,6 +143,8 @@ struct fs_platform_info {
 
 	int use_rmii;		/* use RMII mode 	       */
 	int has_phy;            /* if the network is phy container as well...*/
+
+	struct clk *clk_per;	/* 'per' clock for register access */
 };
 struct fs_mii_fec_platform_info {
 	u32 irq[32];
-- 
1.7.10.4

[PATCH v2 21/24] [media] fsl-viu: OF clock lookup, prepare before enable

From: Gerhard Sittig <hidden>
Date: 2013-07-18 20:20:55

device tree based clock lookup, must prepare clocks before enabling
them, unprepare after disable, error check in the clock setup

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/media/platform/fsl-viu.c |   12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
index 221ec42..b95aa43 100644
--- a/drivers/media/platform/fsl-viu.c
+++ b/drivers/media/platform/fsl-viu.c
@@ -1582,8 +1582,11 @@ static int viu_of_probe(struct platform_device *op)
 		dev_err(&op->dev, "failed to find the clock module!\n");
 		ret = -ENODEV;
 		goto err_clk;
-	} else {
-		clk_enable(viu_dev->clk);
+	}
+	ret = clk_prepare_enable(viu_dev->clk);
+	if (ret) {
+		dev_err(&op->dev, "failed to enable the clock!\n");
+		goto err_clk_put;
 	}
 
 	/* reset VIU module */
@@ -1602,7 +1605,8 @@ static int viu_of_probe(struct platform_device *op)
 	return ret;
 
 err_irq:
-	clk_disable(viu_dev->clk);
+	clk_disable_unprepare(viu_dev->clk);
+err_clk_put:
 	clk_put(viu_dev->clk);
 err_clk:
 	video_unregister_device(viu_dev->vdev);
@@ -1626,7 +1630,7 @@ static int viu_of_remove(struct platform_device *op)
 	free_irq(dev->irq, (void *)dev);
 	irq_dispose_mapping(dev->irq);
 
-	clk_disable(dev->clk);
+	clk_disable_unprepare(dev->clk);
 	clk_put(dev->clk);
 
 	video_unregister_device(dev->vdev);
-- 
1.7.10.4

[PATCH v2 24/24] net: can: mscan: remove MPC512x non-COMMON_CLK code path

From: Gerhard Sittig <hidden>
Date: 2013-07-18 20:20:58

transition to the COMMON_CLK framework has completed for the MPC512x
platform, remove the now obsolete code path of the mpc5xxx mscan
driver which accessed clock control module registers directly

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/net/can/mscan/mpc5xxx_can.c |  136 -----------------------------------
 1 file changed, 136 deletions(-)
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index dd26ab6..cf5e4cfc 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -108,9 +108,6 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
-
-#if IS_ENABLED(CONFIG_COMMON_CLK)
-
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_source, int *mscan_clksrc)
 {
@@ -244,139 +241,6 @@ err_notavail:
 	dev_err(&ofdev->dev, "cannot acquire or setup clock source\n");
 	return 0;
 }
-#else	/* COMMON_CLK */
-struct mpc512x_clockctl {
-	u32 spmr;		/* System PLL Mode Reg */
-	u32 sccr[2];		/* System Clk Ctrl Reg 1 & 2 */
-	u32 scfr1;		/* System Clk Freq Reg 1 */
-	u32 scfr2;		/* System Clk Freq Reg 2 */
-	u32 reserved;
-	u32 bcr;		/* Bread Crumb Reg */
-	u32 pccr[12];		/* PSC Clk Ctrl Reg 0-11 */
-	u32 spccr;		/* SPDIF Clk Ctrl Reg */
-	u32 cccr;		/* CFM Clk Ctrl Reg */
-	u32 dccr;		/* DIU Clk Cnfg Reg */
-	u32 mccr[4];		/* MSCAN Clk Ctrl Reg 1-3 */
-};
-
-static struct of_device_id mpc512x_clock_ids[] = {
-	{ .compatible = "fsl,mpc5121-clock", },
-	{}
-};
-
-static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
-				 const char *clock_name, int *mscan_clksrc)
-{
-	struct mpc512x_clockctl __iomem *clockctl;
-	struct device_node *np_clock;
-	struct clk *sys_clk, *ref_clk;
-	int plen, clockidx, clocksrc = -1;
-	u32 sys_freq, val, clockdiv = 1, freq = 0;
-	const u32 *pval;
-
-	np_clock = of_find_matching_node(NULL, mpc512x_clock_ids);
-	if (!np_clock) {
-		dev_err(&ofdev->dev, "couldn't find clock node\n");
-		return 0;
-	}
-	clockctl = of_iomap(np_clock, 0);
-	if (!clockctl) {
-		dev_err(&ofdev->dev, "couldn't map clock registers\n");
-		goto exit_put;
-	}
-
-	/* Determine the MSCAN device index from the peripheral's
-	 * physical address. Register address offsets against the
-	 * IMMR base are:  0x1300, 0x1380, 0x2300, 0x2380
-	 */
-	pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
-	BUG_ON(!pval || plen < sizeof(*pval));
-	clockidx = (*pval & 0x80) ? 1 : 0;
-	if (*pval & 0x2000)
-		clockidx += 2;
-
-	/*
-	 * Clock source and divider selection: 3 different clock sources
-	 * can be selected: "ip", "ref" or "sys". For the latter two, a
-	 * clock divider can be defined as well. If the clock source is
-	 * not specified by the device tree, we first try to find an
-	 * optimal CAN source clock based on the system clock. If that
-	 * is not posslible, the reference clock will be used.
-	 */
-	if (clock_name && !strcmp(clock_name, "ip")) {
-		*mscan_clksrc = MSCAN_CLKSRC_IPS;
-		freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
-	} else {
-		*mscan_clksrc = MSCAN_CLKSRC_BUS;
-
-		pval = of_get_property(ofdev->dev.of_node,
-				       "fsl,mscan-clock-divider", &plen);
-		if (pval && plen == sizeof(*pval))
-			clockdiv = *pval;
-		if (!clockdiv)
-			clockdiv = 1;
-
-		if (!clock_name || !strcmp(clock_name, "sys")) {
-			sys_clk = clk_get(&ofdev->dev, "sys_clk");
-			if (IS_ERR(sys_clk)) {
-				dev_err(&ofdev->dev, "couldn't get sys_clk\n");
-				goto exit_unmap;
-			}
-			/* Get and round up/down sys clock rate */
-			sys_freq = 1000000 *
-				((clk_get_rate(sys_clk) + 499999) / 1000000);
-
-			if (!clock_name) {
-				/* A multiple of 16 MHz would be optimal */
-				if ((sys_freq % 16000000) == 0) {
-					clocksrc = 0;
-					clockdiv = sys_freq / 16000000;
-					freq = sys_freq / clockdiv;
-				}
-			} else {
-				clocksrc = 0;
-				freq = sys_freq / clockdiv;
-			}
-		}
-
-		if (clocksrc < 0) {
-			ref_clk = clk_get(&ofdev->dev, "ref_clk");
-			if (IS_ERR(ref_clk)) {
-				dev_err(&ofdev->dev, "couldn't get ref_clk\n");
-				goto exit_unmap;
-			}
-			clocksrc = 1;
-			freq = clk_get_rate(ref_clk) / clockdiv;
-		}
-	}
-
-	/* Disable clock */
-	out_be32(&clockctl->mccr[clockidx], 0x0);
-	if (clocksrc >= 0) {
-		/* Set source and divider */
-		val = (clocksrc << 14) | ((clockdiv - 1) << 17);
-		out_be32(&clockctl->mccr[clockidx], val);
-		/* Enable clock */
-		out_be32(&clockctl->mccr[clockidx], val | 0x10000);
-	}
-
-	/* Enable MSCAN clock domain */
-	val = in_be32(&clockctl->sccr[1]);
-	if (!(val & (1 << 25)))
-		out_be32(&clockctl->sccr[1], val | (1 << 25));
-
-	dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n",
-		*mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" :
-		clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
-
-exit_unmap:
-	iounmap(clockctl);
-exit_put:
-	of_node_put(np_clock);
-	return freq;
-}
-#endif	/* COMMON_CLK */
-
 #else /* !CONFIG_PPC_MPC512x */
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_name, int *mscan_clksrc)
-- 
1.7.10.4

Re: [PATCH v2 18/24] i2c: mpc: OF clock lookup for MPC512x

From: Russell King - ARM Linux <hidden>
Date: 2013-07-18 20:33:24

On Thu, Jul 18, 2013 at 10:20:52PM +0200, Gerhard Sittig wrote:
+	/* enable clock for the I2C peripheral (non fatal) */
+	clk = of_clk_get_by_name(node, "per");
+	if (!IS_ERR(clk)) {
+		clk_prepare_enable(clk);
+		clk_put(clk);
+	}
+
This kind of hacked up approach to the clk API is exactly the thing I
really don't like seeing.  I don't know what it is... is the clk API
somehow difficult to use or what's the problem with doing stuff correctly?

1. Get the clock in your probe function.
2. Prepare it at the appropriate time.
3. Enable it appropriately.  (or if you want to combine 2 and 3, use
   clk_prepare_enable().)
4. Ensure that enables/disables and prepares/unprepares are appropriately
   balanced.
5. 'put' the clock in your remove function.

Certainly do not get-enable-put a clock.  You're supposed to hold on to
the clock all the time that you're actually using it.

Final point - if you want to make it non-fatal, don't play games like:

	clk = clk_get(whatever);
	if (IS_ERR(clk))
		clk = NULL;

	...
	if (clk)
		clk_prepare(clk);

Do this instead:

	clk = clk_get(whatever);
	...

	if (!IS_ERR(clk))
		clk_prepare(clk);
etc.

(And on this subject, I'm considering whether to make a change to the
clk API where clk_prepare() and clk_enable() return zero when passed
an error pointer - this means drivers with optional clocks don't have
to burden themselves with these kinds of checks.)

[PATCH v3 00/31] add COMMON_CLK support for PowerPC MPC512x

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:27

this series
- fixes several drivers that are used in the MPC512x platform (UART,
  SPI, ethernet, PCI, USB, CAN, NAND flash, video capture) in how they
  handle clocks (appropriately acquire and setup them, hold references
  during use, release clocks after use)
- introduces support for the common clock framework (CCF, COMMON_CLK
  Kconfig option) in the PowerPC based MPC512x platform, which brings
  device tree based clock lookup as well

although the series does touch several subsystems -- tty (serial), spi,
net (can, fs_enet), mtd (nfc), usb, i2c, media (viu), and dts -- all of
the patches are strictly clock related

it appears most appropriate to take this series through either the clk
or the powerpc trees after it has passed review and other subsystem
maintainers ACKed the clock setup related driver modifications

the series passes 'checkpatch.pl --strict' except for one warning which
cannot get resolved, since that either breaks compilation (the data type
is preset by the clk-provider.h API) or requires a cast which shadows
real mismatches:

  WARNING: static const char * array should probably be static const char * const
  #436: FILE: arch/powerpc/platforms/512x/clock-commonclk.c:335:
  +static const char *parent_names_mux0[] = {

  total: 0 errors, 1 warnings, 0 checks, 845 lines checked

each step in the series was build and run tested (with a display that is
attached to the DIU as well as SPI, with an SPI attached NOR flash, with
multiple UART ports such that one is not the boot console, with EEPROMs
attached to I2C, with an SD card, booting from network)


changes in v3:
- rebase the series against v3.11-rc2
- re-ordered the series to first address all general clock handling
  concerns in existing drivers, before introducing common clock support
  in the platform's clock driver
- slightly rework the SPI (01/31), UART (02/31), and PSC FIFO (23/31)
  clock handling in comparison to v2 which introduced those fixes
  (devm_{get,put}_clk() calls, fewer goto labels in error paths)
- fix and improve clock handling (balance allocation and release of
  clocks, check for errors during setup) in all of the other drivers
  which this series has touched before in naive ways: USB (03/31), NAND
  flash (04/31), video capture (05/31), I2C (06/31), ethernet (08/31),
  PCI (09/31), CAN (11/31)
- silence a build warning in the ethernet driver (07/31)
- eliminate all PPC_CLOCK references, use 'per' clock names for NAND
  flash (25/31) and VIU (26/31) as well
- unbreak CAN operation for the period between introducing common clock
  support in the platform's clock driver and introducing common clock
  support in the CAN peripheral driver as well as providing clock specs
  in the device tree (provide clkdev aliases for SYS and REF)
- improve common clock support for CAN (devm_{get,put}_clk() calls,
  check enable() errors, keep a reference to used clocks, disable and
  put clocks after use)
- reworded several commit messages to better reflect the kind of change
  and because fixes were applied before adding common infrastructure
  support
- point to individual numbered patches of the series in the list of
  changes for v2 as well

changes in v2:
- cleanup of the UART (02/24) and SPI (01/24) clock handling before the
  introduction of common clock support for the platform, as incomplete
  clock handling becomes fatal or more dangerous later (which in turn
  changes the context of the "device tree lookup only" followup patch
  later)
- reordered the sequence of patches to keep the serial communication
  related parts together (UART, SPI, and PSC FIFO changes after common
  clock support was introduced, which have become 11-14/24 now)
- updated commit messages for the clock API use cleanup in the serial
  communication drivers, updated comments and reworded commit messages
  in the core clock driver to expand on the pre-enable workaround and
  clkdev registration (09/24)
- keep a reference to the PSC FIFO clock during use instead of looking
  up the clock again in the uninit() routine (14/24)
- remove the clkdev.h header file inclusion directive with the removal
  of the clkdev registration call (13/24)


Gerhard Sittig (31):
  spi: mpc512x: cleanup clock API use
  serial: mpc512x: cleanup clock API use
  USB: fsl-mph-dr-of: cleanup clock API use
  mtd: mpc5121_nfc: cleanup clock API use
  [media] fsl-viu: cleanup clock API use
  i2c: mpc: cleanup clock API use
  fs_enet: silence a build warning (unused variable)
  fs_enet: cleanup clock API use
  powerpc/fsl-pci: improve clock API use
  net: can: mscan: add a comment on reg to idx mapping
  net: can: mscan: improve clock API use
  powerpc: mpc512x: array decl for MCLK registers in CCM
  clk: wrap I/O access for improved portability
  dts: mpc512x: prepare for preprocessor support
  dts: mpc512x: introduce dt-bindings/clock/ header
  dts: mpc512x: add clock related device tree specs
  clk: mpc512x: introduce COMMON_CLK for MPC512x
  dts: mpc512x: add clock specs for client lookups
  clk: mpc512x: don't pre-enable FEC and I2C clocks
  spi: mpc512x: remove now obsolete clock lookup name
  serial: mpc512x: remove now obsolete clock lookup name
  clk: mpc512x: remove clkdev registration (uart, spi)
  serial: mpc512x: setup the PSC FIFO clock as well
  USB: fsl-mph-dr-of: remove now obsolete clock lookup name
  mtd: mpc5121_nfc: remove now obsolete clock lookup name
  [media] fsl-viu: remove now obsolete clock lookup name
  net: can: mscan: add common clock support for  mpc512x
  powerpc/mpc512x: improve DIU related clock setup
  clk: mpc512x: switch to COMMON_CLK, remove PPC_CLOCK
  net: can: mscan: remove non-common_clock code for MPC512x
  clk: mpc512x: remove clkdev registration (sys/ref, header)

 arch/powerpc/boot/dts/ac14xx.dts                   |    9 +-
 arch/powerpc/boot/dts/include/dt-bindings          |    1 +
 arch/powerpc/boot/dts/mpc5121.dtsi                 |   94 ++-
 arch/powerpc/boot/dts/mpc5121ads.dts               |    2 +-
 arch/powerpc/boot/dts/pdm360ng.dts                 |    2 +-
 arch/powerpc/include/asm/mpc5121.h                 |   18 +-
 arch/powerpc/platforms/512x/Kconfig                |    2 +-
 arch/powerpc/platforms/512x/Makefile               |    3 +-
 arch/powerpc/platforms/512x/clock-commonclk.c      |  761 ++++++++++++++++++++
 arch/powerpc/platforms/512x/clock.c                |  753 -------------------
 arch/powerpc/platforms/512x/mpc512x_shared.c       |  165 +++--
 arch/powerpc/sysdev/fsl_pci.c                      |   23 +
 drivers/clk/clk-divider.c                          |    6 +-
 drivers/clk/clk-gate.c                             |    6 +-
 drivers/clk/clk-mux.c                              |    6 +-
 drivers/i2c/busses/i2c-mpc.c                       |   28 +
 drivers/media/platform/fsl-viu.c                   |   26 +-
 drivers/mtd/nand/mpc5121_nfc.c                     |   20 +-
 drivers/net/can/mscan/mpc5xxx_can.c                |  271 ++++---
 drivers/net/can/mscan/mscan.c                      |    9 +
 drivers/net/can/mscan/mscan.h                      |    2 +
 .../net/ethernet/freescale/fs_enet/fs_enet-main.c  |   26 +-
 drivers/spi/spi-mpc512x-psc.c                      |   48 +-
 drivers/tty/serial/mpc52xx_uart.c                  |  144 +++-
 drivers/usb/host/fsl-mph-dr-of.c                   |   26 +-
 include/dt-bindings/clock/mpc512x-clock.h          |   59 ++
 include/linux/clk-provider.h                       |   33 +
 include/linux/fs_enet_pd.h                         |    3 +
 28 files changed, 1493 insertions(+), 1053 deletions(-)
 create mode 120000 arch/powerpc/boot/dts/include/dt-bindings
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
 delete mode 100644 arch/powerpc/platforms/512x/clock.c
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h


# uname -srm
Linux 3.11.0-rc2-00031-ge72cd55 ppc
# cat /sys/kernel/debug/clk/clk_summary
   clock                        enable_cnt  prepare_cnt  rate
---------------------------------------------------------------------
 ac97                           0           0            24567000
 spdif_rx_in                    0           0            0
 spdif_tx_in                    0           0            0
 psc_mclk_in                    0           0            25000000
 dummy                          1           1            0
 osc                            1           1            25000000
    ref                         1           1            25000000
       sys                      10          10           320000000
          spdif-mux0            0           0            320000000
             spdif-en0          0           0            320000000
                spdif_mclk_div  0           0            80000000
                   spdif_mclk_out 0           0            80000000
                      spdif_mclk 0           0            80000000
          mscan3-mux0           1           1            320000000
             mscan3-en0         1           1            320000000
                mscan3_mclk_div 1           1            80000000
                   mscan3_mclk_out 1           1            80000000
                      mscan3_mclk 1           1            80000000
          mscan2-mux0           1           1            320000000
             mscan2-en0         1           1            320000000
                mscan2_mclk_div 1           1            80000000
                   mscan2_mclk_out 1           1            80000000
                      mscan2_mclk 1           1            80000000
          mscan1-mux0           1           1            320000000
             mscan1-en0         1           1            320000000
                mscan1_mclk_div 1           1            16000000
                   mscan1_mclk_out 1           1            16000000
                      mscan1_mclk 1           2            16000000
          mscan0-mux0           1           1            320000000
             mscan0-en0         1           1            320000000
                mscan0_mclk_div 1           1            16000000
                   mscan0_mclk_out 1           1            16000000
                      mscan0_mclk 1           2            16000000
          psc11-mux0            0           0            320000000
             psc11-en0          0           0            320000000
                psc11_mclk_div  0           0            80000000
                   psc11_mclk_out 0           0            80000000
                      psc11_mclk 0           0            80000000
          psc10-mux0            0           0            320000000
             psc10-en0          0           0            320000000
                psc10_mclk_div  0           0            80000000
                   psc10_mclk_out 0           0            80000000
                      psc10_mclk 0           0            80000000
          psc9-mux0             0           0            320000000
             psc9-en0           0           0            320000000
                psc9_mclk_div   0           0            80000000
                   psc9_mclk_out 0           0            80000000
                      psc9_mclk 0           0            80000000
          psc8-mux0             0           0            320000000
             psc8-en0           0           0            320000000
                psc8_mclk_div   0           0            80000000
                   psc8_mclk_out 0           0            80000000
                      psc8_mclk 0           0            80000000
          psc7-mux0             1           1            320000000
             psc7-en0           1           1            320000000
                psc7_mclk_div   1           1            80000000
                   psc7_mclk_out 1           1            80000000
                      psc7_mclk 1           1            80000000
          psc6-mux0             0           0            320000000
             psc6-en0           0           0            320000000
                psc6_mclk_div   0           0            80000000
                   psc6_mclk_out 0           0            80000000
                      psc6_mclk 0           0            80000000
          psc5-mux0             1           1            320000000
             psc5-en0           1           1            320000000
                psc5_mclk_div   1           1            80000000
                   psc5_mclk_out 1           1            80000000
                      psc5_mclk 1           1            80000000
          psc4-mux0             1           1            320000000
             psc4-en0           1           1            320000000
                psc4_mclk_div   1           1            80000000
                   psc4_mclk_out 1           1            80000000
                      psc4_mclk 1           1            80000000
          psc3-mux0             1           1            320000000
             psc3-en0           1           1            320000000
                psc3_mclk_div   1           1            80000000
                   psc3_mclk_out 1           1            80000000
                      psc3_mclk 2           2            80000000
          psc2-mux0             0           0            320000000
             psc2-en0           0           0            320000000
                psc2_mclk_div   0           0            80000000
                   psc2_mclk_out 0           0            80000000
                      psc2_mclk 0           0            80000000
          psc1-mux0             0           0            320000000
             psc1-en0           0           0            320000000
                psc1_mclk_div   0           0            80000000
                   psc1_mclk_out 0           0            80000000
                      psc1_mclk 0           0            80000000
          psc0-mux0             0           0            320000000
             psc0-en0           0           0            320000000
                psc0_mclk_div   0           0            80000000
                   psc0_mclk_out 0           0            80000000
                      psc0_mclk 0           0            80000000
          ddr-ug                1           1            160000000
             ddr                1           1            160000000
          csb                   4           4            160000000
             viu                0           0            160000000
             iim                0           0            160000000
             usb2               0           0            160000000
             usb1               0           0            160000000
             axe                0           0            160000000
             pci-ug             0           0            26666666
                pci             0           0            26666666
             mbx-bus-ug         0           0            80000000
                mbx-bus         0           0            80000000
                mbx-ug          0           0            80000000
                   mbx          0           0            80000000
                   mbx-3d-ug    0           0            80000000
                      mbx-3d    0           0            80000000
             e300               1           1            400000000
             diu-x4             1           1            640000000
                diu-ug          1           1            2509803
                   diu          2           2            2509803
             sdhc-x4            1           1            640000000
                sdhc-ug         1           1            53333333
                   sdhc-2       0           0            53333333
                   sdhc         1           1            53333333
             ips                7           7            80000000
                i2c             3           3            80000000
                mem             1           1            80000000
                fec             1           1            80000000
                sata            0           0            80000000
                psc-fifo        1           1            80000000
                pata            0           0            80000000
                lpc-ug          1           1            40000000
                   lpc          1           1            40000000
                nfc-ug          0           0            40000000
                   nfc          0           0            40000000

-- 
1.7.10.4

[PATCH v3 01/31] spi: mpc512x: cleanup clock API use

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:28

cleanup the MPC512x SoC's SPI master's use of the clock API
- get, prepare, and enable the MCLK during probe; disable, unprepare and
  put the MCLK upon remove; hold a reference to the clock over the
  period of use
- fetch MCLK rate (reference) once during probe and slightly reword BCLK
  (bitrate) determination to reduce redundancy as well as to not exceed
  the maximum text line length
- stick with the PPC_CLOCK 'psc%d_mclk' name for clock lookup, only
  switch to a fixed string later after device tree based clock lookup
  will have become available

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/spi/spi-mpc512x-psc.c |   52 +++++++++++++++++++++++++++--------------
 1 file changed, 34 insertions(+), 18 deletions(-)
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 29fce6a..823e5e0 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -38,7 +38,8 @@ struct mpc512x_psc_spi {
 	struct mpc512x_psc_fifo __iomem *fifo;
 	unsigned int irq;
 	u8 bits_per_word;
-	u32 mclk;
+	struct clk *clk_mclk;
+	u32 mclk_rate;
 
 	struct completion txisrdone;
 };
@@ -72,6 +73,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
 	struct mpc52xx_psc __iomem *psc = mps->psc;
 	u32 sicr;
 	u32 ccr;
+	int speed;
 	u16 bclkdiv;
 
 	sicr = in_be32(&psc->sicr);
@@ -95,10 +97,10 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
 
 	ccr = in_be32(&psc->ccr);
 	ccr &= 0xFF000000;
-	if (cs->speed_hz)
-		bclkdiv = (mps->mclk / cs->speed_hz) - 1;
-	else
-		bclkdiv = (mps->mclk / 1000000) - 1;	/* default 1MHz */
+	speed = cs->speed_hz;
+	if (!speed)
+		speed = 1000000;	/* default 1MHz */
+	bclkdiv = (mps->mclk_rate / speed) - 1;
 
 	ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
 	out_be32(&psc->ccr, ccr);
@@ -386,19 +388,11 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 {
 	struct mpc52xx_psc __iomem *psc = mps->psc;
 	struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
-	struct clk *spiclk;
-	int ret = 0;
-	char name[32];
 	u32 sicr;
 	u32 ccr;
+	int speed;
 	u16 bclkdiv;
 
-	sprintf(name, "psc%d_mclk", master->bus_num);
-	spiclk = clk_get(&master->dev, name);
-	clk_enable(spiclk);
-	mps->mclk = clk_get_rate(spiclk);
-	clk_put(spiclk);
-
 	/* Reset the PSC into a known state */
 	out_8(&psc->command, MPC52xx_PSC_RST_RX);
 	out_8(&psc->command, MPC52xx_PSC_RST_TX);
@@ -425,7 +419,8 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 
 	ccr = in_be32(&psc->ccr);
 	ccr &= 0xFF000000;
-	bclkdiv = (mps->mclk / 1000000) - 1;	/* default 1MHz */
+	speed = 1000000;	/* default 1MHz */
+	bclkdiv = (mps->mclk_rate / speed) - 1;
 	ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
 	out_be32(&psc->ccr, ccr);
 
@@ -445,7 +440,7 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 
 	mps->bits_per_word = 8;
 
-	return ret;
+	return 0;
 }
 
 static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
@@ -479,6 +474,9 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 	struct spi_master *master;
 	int ret;
 	void *tempp;
+	int psc_num;
+	char clk_name[16];
+	struct clk *clk;
 
 	master = spi_alloc_master(dev, sizeof *mps);
 	if (master == NULL)
@@ -521,16 +519,32 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 		goto free_master;
 	init_completion(&mps->txisrdone);
 
+	psc_num = master->bus_num;
+	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
+	clk = devm_clk_get(dev, clk_name);
+	if (IS_ERR(clk))
+		goto free_irq;
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		devm_clk_put(dev, clk);
+		goto free_irq;
+	}
+	mps->clk_mclk = clk;
+	mps->mclk_rate = clk_get_rate(clk);
+
 	ret = mpc512x_psc_spi_port_config(master, mps);
 	if (ret < 0)
-		goto free_irq;
+		goto free_clock;
 
 	ret = spi_register_master(master);
 	if (ret < 0)
-		goto free_irq;
+		goto free_clock;
 
 	return ret;
 
+free_clock:
+	clk_disable_unprepare(mps->clk_mclk);
+	devm_clk_put(dev, mps->clk_mclk);
 free_irq:
 	free_irq(mps->irq, mps);
 free_master:
@@ -547,6 +561,8 @@ static int mpc512x_psc_spi_do_remove(struct device *dev)
 	struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
 
 	spi_unregister_master(master);
+	clk_disable_unprepare(mps->clk_mclk);
+	devm_clk_put(dev, mps->clk_mclk);
 	free_irq(mps->irq, mps);
 	if (mps->psc)
 		iounmap(mps->psc);
-- 
1.7.10.4

[PATCH v3 02/31] serial: mpc512x: cleanup clock API use

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:29

cleanup the clock API use of the UART driver which is shared among the
MPC512x and the MPC5200 platforms
- get, prepare, and enable the MCLK during port allocation; disable,
  unprepare and put the MCLK upon port release; hold a reference to the
  clock over the period of use; check for and propagate enable errors
- fix a buffer overflow for clock names with two digit PSC index numbers
- stick with the PPC_CLOCK 'psc%d_mclk' name for clock lookup, only
  switch to a fixed string later after device tree based clock lookup
  will have become available

to achieve support for MPC512x which is neutral to MPC5200, the
modification was done as follows
- introduce "clock alloc" and "clock release" routines in addition to
  the previous "clock enable/disable" routine in the psc_ops struct
- make the clock allocation a part of the port request (resource
  allocation), and make clock release a part of the port release, such
  that essential resources get allocated early
- just enable/disable the clock from within the .clock() callback
  without any allocation or preparation as the former implementation
  did, since this routine is called from within the startup and shutdown
  callbacks
- all of the above remains a NOP for the MPC5200 platform (no callbacks
  are provided on that platform)
- implementation note: the clock gets enabled upon allocation already
  just in case the clock is not only required for bitrate generation but
  for register access as well

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/tty/serial/mpc52xx_uart.c |  100 ++++++++++++++++++++++++++++++-------
 1 file changed, 83 insertions(+), 17 deletions(-)
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index e1280a2..8f16ed9 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -107,6 +107,8 @@ struct psc_ops {
 	unsigned int	(*set_baudrate)(struct uart_port *port,
 					struct ktermios *new,
 					struct ktermios *old);
+	int		(*clock_alloc)(struct uart_port *port);
+	void		(*clock_relse)(struct uart_port *port);
 	int		(*clock)(struct uart_port *port, int enable);
 	int		(*fifoc_init)(void);
 	void		(*fifoc_uninit)(void);
@@ -616,31 +618,75 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
 	return IRQ_NONE;
 }
 
-static int mpc512x_psc_clock(struct uart_port *port, int enable)
+static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM];
+
+/* called from within the .request_port() callback (allocation) */
+static int mpc512x_psc_alloc_clock(struct uart_port *port)
 {
-	struct clk *psc_clk;
 	int psc_num;
-	char clk_name[10];
+	char clk_name[16];
+	struct clk *clk;
+	int err;
+
+	psc_num = (port->mapbase & 0xf00) >> 8;
+	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
+	clk = devm_clk_get(port->dev, clk_name);
+	if (IS_ERR(clk)) {
+		dev_err(port->dev, "Failed to get MCLK!\n");
+		return PTR_ERR(clk);
+	}
+	err = clk_prepare_enable(clk);
+	if (err) {
+		dev_err(port->dev, "Failed to enable MCLK!\n");
+		devm_clk_put(port->dev, clk);
+		return err;
+	}
+	psc_mclk_clk[psc_num] = clk;
+	return 0;
+}
+
+/* called from within the .release_port() callback (release) */
+static void mpc512x_psc_relse_clock(struct uart_port *port)
+{
+	int psc_num;
+	struct clk *clk;
+
+	psc_num = (port->mapbase & 0xf00) >> 8;
+	clk = psc_mclk_clk[psc_num];
+	if (clk) {
+		clk_disable_unprepare(clk);
+		devm_clk_put(port->dev, clk);
+		psc_mclk_clk[psc_num] = NULL;
+	}
+}
+
+/* implementation of the .clock() callback (enable/disable) */
+static int mpc512x_psc_endis_clock(struct uart_port *port, int enable)
+{
+	int psc_num;
+	struct clk *psc_clk;
+	int ret;
 
 	if (uart_console(port))
 		return 0;
 
 	psc_num = (port->mapbase & 0xf00) >> 8;
-	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-	psc_clk = clk_get(port->dev, clk_name);
-	if (IS_ERR(psc_clk)) {
+	psc_clk = psc_mclk_clk[psc_num];
+	if (!psc_clk) {
 		dev_err(port->dev, "Failed to get PSC clock entry!\n");
 		return -ENODEV;
 	}
 
-	dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis");
-
-	if (enable)
-		clk_enable(psc_clk);
-	else
+	dev_dbg(port->dev, "mclk %sable\n", enable ? "en" : "dis");
+	if (enable) {
+		ret = clk_enable(psc_clk);
+		if (ret)
+			dev_err(port->dev, "Failed to enable MCLK!\n");
+		return ret;
+	} else {
 		clk_disable(psc_clk);
-
-	return 0;
+		return 0;
+	}
 }
 
 static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
@@ -873,7 +919,9 @@ static struct psc_ops mpc5125_psc_ops = {
 	.cw_disable_ints = mpc5125_psc_cw_disable_ints,
 	.cw_restore_ints = mpc5125_psc_cw_restore_ints,
 	.set_baudrate = mpc5125_psc_set_baudrate,
-	.clock = mpc512x_psc_clock,
+	.clock_alloc = mpc512x_psc_alloc_clock,
+	.clock_relse = mpc512x_psc_relse_clock,
+	.clock = mpc512x_psc_endis_clock,
 	.fifoc_init = mpc512x_psc_fifoc_init,
 	.fifoc_uninit = mpc512x_psc_fifoc_uninit,
 	.get_irq = mpc512x_psc_get_irq,
@@ -906,7 +954,9 @@ static struct psc_ops mpc512x_psc_ops = {
 	.cw_disable_ints = mpc512x_psc_cw_disable_ints,
 	.cw_restore_ints = mpc512x_psc_cw_restore_ints,
 	.set_baudrate = mpc512x_psc_set_baudrate,
-	.clock = mpc512x_psc_clock,
+	.clock_alloc = mpc512x_psc_alloc_clock,
+	.clock_relse = mpc512x_psc_relse_clock,
+	.clock = mpc512x_psc_endis_clock,
 	.fifoc_init = mpc512x_psc_fifoc_init,
 	.fifoc_uninit = mpc512x_psc_fifoc_uninit,
 	.get_irq = mpc512x_psc_get_irq,
@@ -1166,6 +1216,9 @@ mpc52xx_uart_type(struct uart_port *port)
 static void
 mpc52xx_uart_release_port(struct uart_port *port)
 {
+	if (psc_ops->clock_relse)
+		psc_ops->clock_relse(port);
+
 	/* remapped by us ? */
 	if (port->flags & UPF_IOREMAP) {
 		iounmap(port->membase);
@@ -1190,11 +1243,24 @@ mpc52xx_uart_request_port(struct uart_port *port)
 	err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
 			"mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
 
-	if (err && (port->flags & UPF_IOREMAP)) {
+	if (err)
+		goto out_membase;
+
+	if (psc_ops->clock_alloc) {
+		err = psc_ops->clock_alloc(port);
+		if (err)
+			goto out_mapregion;
+	}
+
+	return 0;
+
+out_mapregion:
+	release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
+out_membase:
+	if (port->flags & UPF_IOREMAP) {
 		iounmap(port->membase);
 		port->membase = NULL;
 	}
-
 	return err;
 }
 
-- 
1.7.10.4

[PATCH v3 03/31] USB: fsl-mph-dr-of: cleanup clock API use

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:30

error check in the clock setup, must prepare clocks before they
can get enabled, unprepare after disable, use devm_{get,put}_clk()

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/usb/host/fsl-mph-dr-of.c |   15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 11e0b79..5e51384 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -260,6 +260,7 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)
 {
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 	struct clk *clk;
+	int err;
 	char clk_name[10];
 	int base, clk_num;
 
@@ -272,13 +273,17 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)
 		return -ENODEV;
 
 	snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num);
-	clk = clk_get(&pdev->dev, clk_name);
+	clk = devm_clk_get(&pdev->dev, clk_name);
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "failed to get clk\n");
 		return PTR_ERR(clk);
 	}
-
-	clk_enable(clk);
+	err = clk_prepare_enable(clk);
+	if (err) {
+		dev_err(&pdev->dev, "failed to enable clk\n");
+		devm_clk_put(&pdev->dev, clk);
+		return err;
+	}
 	pdata->clk = clk;
 
 	if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
@@ -303,8 +308,8 @@ static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
 	pdata->regs = NULL;
 
 	if (pdata->clk) {
-		clk_disable(pdata->clk);
-		clk_put(pdata->clk);
+		clk_disable_unprepare(pdata->clk);
+		devm_clk_put(&pdev->dev, pdata->clk);
 	}
 }
 
-- 
1.7.10.4

[PATCH v3 04/31] mtd: mpc5121_nfc: cleanup clock API use

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:31

prepare before enable isn't optional, do check for and propagate clock
setup errors, adjust error code paths to correctly balance get/put and
prepare/unprepare and enable/disable, use devm_{get,put}_clk()

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/mtd/nand/mpc5121_nfc.c |   20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
index 3c9cdcb..9c0b8fe 100644
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -618,8 +618,8 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
 	struct mpc5121_nfc_prv *prv = chip->priv;
 
 	if (prv->clk) {
-		clk_disable(prv->clk);
-		clk_put(prv->clk);
+		clk_disable_unprepare(prv->clk);
+		devm_clk_put(dev, prv->clk);
 	}
 
 	if (prv->csreg)
@@ -629,6 +629,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
 static int mpc5121_nfc_probe(struct platform_device *op)
 {
 	struct device_node *rootnode, *dn = op->dev.of_node;
+	struct clk *clk;
 	struct device *dev = &op->dev;
 	struct mpc5121_nfc_prv *prv;
 	struct resource res;
@@ -730,14 +731,19 @@ static int mpc5121_nfc_probe(struct platform_device *op)
 	of_node_put(rootnode);
 
 	/* Enable NFC clock */
-	prv->clk = clk_get(dev, "nfc_clk");
-	if (IS_ERR(prv->clk)) {
+	clk = devm_clk_get(dev, "nfc_clk");
+	if (IS_ERR(clk)) {
 		dev_err(dev, "Unable to acquire NFC clock!\n");
-		retval = PTR_ERR(prv->clk);
+		retval = PTR_ERR(clk);
 		goto error;
 	}
-
-	clk_enable(prv->clk);
+	retval = clk_prepare_enable(clk);
+	if (retval) {
+		dev_err(dev, "Unable to enable NFC clock!\n");
+		devm_clk_put(dev, clk);
+		goto error;
+	}
+	prv->clk = clk;
 
 	/* Reset NAND Flash controller */
 	nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
-- 
1.7.10.4

[PATCH v3 05/31] [media] fsl-viu: cleanup clock API use

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:32

prepare clocks before enabling them, check for and propagate enable
errors, balance get/put and prepare/unprepare and enable/disable,
use devm_{get,put}_clk()

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/media/platform/fsl-viu.c |   26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
index 221ec42..48fced4 100644
--- a/drivers/media/platform/fsl-viu.c
+++ b/drivers/media/platform/fsl-viu.c
@@ -1485,6 +1485,7 @@ static int viu_of_probe(struct platform_device *op)
 	struct viu_reg __iomem *viu_regs;
 	struct i2c_adapter *ad;
 	int ret, viu_irq;
+	struct clk *clk;
 
 	ret = of_address_to_resource(op->dev.of_node, 0, &r);
 	if (ret) {
@@ -1577,14 +1578,19 @@ static int viu_of_probe(struct platform_device *op)
 	}
 
 	/* enable VIU clock */
-	viu_dev->clk = clk_get(&op->dev, "viu_clk");
-	if (IS_ERR(viu_dev->clk)) {
-		dev_err(&op->dev, "failed to find the clock module!\n");
-		ret = -ENODEV;
+	clk = devm_clk_get(&op->dev, "viu_clk");
+	if (IS_ERR(clk)) {
+		dev_err(&op->dev, "failed to lookup the clock!\n");
+		ret = PTR_ERR(clk);
+		goto err_clk;
+	}
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		dev_err(&op->dev, "failed to enable the clock!\n");
+		devm_clk_put(&op->dev, clk);
 		goto err_clk;
-	} else {
-		clk_enable(viu_dev->clk);
 	}
+	viu_dev->clk = clk;
 
 	/* reset VIU module */
 	viu_reset(viu_dev->vr);
@@ -1602,8 +1608,8 @@ static int viu_of_probe(struct platform_device *op)
 	return ret;
 
 err_irq:
-	clk_disable(viu_dev->clk);
-	clk_put(viu_dev->clk);
+	clk_disable_unprepare(viu_dev->clk);
+	devm_clk_put(&op->dev, viu_dev->clk);
 err_clk:
 	video_unregister_device(viu_dev->vdev);
 err_vdev:
@@ -1626,8 +1632,8 @@ static int viu_of_remove(struct platform_device *op)
 	free_irq(dev->irq, (void *)dev);
 	irq_dispose_mapping(dev->irq);
 
-	clk_disable(dev->clk);
-	clk_put(dev->clk);
+	clk_disable_unprepare(dev->clk);
+	devm_clk_put(&op->dev, dev->clk);
 
 	video_unregister_device(dev->vdev);
 	i2c_put_adapter(client->adapter);
-- 
1.7.10.4

[PATCH v3 06/31] i2c: mpc: cleanup clock API use

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:33

make the MPC I2C driver get, prepare and enable the peripheral clock
('per' for access to the peripheral's registers) during probe;
disable, unprepare and put the clock upon remove(); hold a reference
to the clock over the period of use

clock lookup is non-fatal in this implementation as not all platforms
may provide clock specs in their device tree, but enable errors for
specified clocks are considered fatal

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/i2c/busses/i2c-mpc.c |   28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 7607dc0..9e837be 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -21,6 +21,7 @@
 #include <linux/of_i2c.h>
 #include <linux/slab.h>
 
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/fsl_devices.h>
 #include <linux/i2c.h>
@@ -67,6 +68,7 @@ struct mpc_i2c {
 #ifdef CONFIG_PM
 	u8 fdr, dfsrr;
 #endif
+	struct clk *clk_per;
 };
 
 struct mpc_i2c_divider {
@@ -623,6 +625,8 @@ static int fsl_i2c_probe(struct platform_device *op)
 	u32 clock = MPC_I2C_CLOCK_LEGACY;
 	int result = 0;
 	int plen;
+	struct clk *clk;
+	int err;
 
 	match = of_match_device(mpc_i2c_of_match, &op->dev);
 	if (!match)
@@ -653,6 +657,21 @@ static int fsl_i2c_probe(struct platform_device *op)
 		}
 	}
 
+	/*
+	 * enable clock for the I2C peripheral (non fatal),
+	 * keep a reference upon successful allocation
+	 */
+	clk = devm_clk_get(&op->dev, "per");
+	if (!IS_ERR(clk)) {
+		err = clk_prepare_enable(clk);
+		if (err) {
+			dev_err(&op->dev, "failed to enable clock\n");
+			devm_clk_put(&op->dev, clk);
+		} else {
+			i2c->clk_per = clk;
+		}
+	}
+
 	if (of_get_property(op->dev.of_node, "fsl,preserve-clocking", NULL)) {
 		clock = MPC_I2C_CLOCK_PRESERVE;
 	} else {
@@ -696,6 +715,10 @@ static int fsl_i2c_probe(struct platform_device *op)
 	return result;
 
  fail_add:
+	if (i2c->clk_per) {
+		clk_disable_unprepare(i2c->clk_per);
+		devm_clk_put(&op->dev, i2c->clk_per);
+	}
 	free_irq(i2c->irq, i2c);
  fail_request:
 	irq_dispose_mapping(i2c->irq);
@@ -711,6 +734,11 @@ static int fsl_i2c_remove(struct platform_device *op)
 
 	i2c_del_adapter(&i2c->adap);
 
+	if (i2c->clk_per) {
+		clk_disable_unprepare(i2c->clk_per);
+		devm_clk_put(&op->dev, i2c->clk_per);
+	}
+
 	if (i2c->irq)
 		free_irq(i2c->irq, i2c);
 
-- 
1.7.10.4

[PATCH v3 07/31] fs_enet: silence a build warning (unused variable)

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:34

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c |    1 -
 1 file changed, 1 deletion(-)
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index 8de53a1..c04eb3a 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -583,7 +583,6 @@ static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
 					       struct sk_buff *skb)
 {
 	struct sk_buff *new_skb;
-	struct fs_enet_private *fep = netdev_priv(dev);
 
 	/* Alloc new skb */
 	new_skb = netdev_alloc_skb(dev, skb->len + 4);
-- 
1.7.10.4

[PATCH v3 08/31] fs_enet: cleanup clock API use

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:35

make the Freescale ethernet driver get, prepare and enable the FEC clock
during probe(); disable, unprepare and put the clock upon remove(); hold
a reference to the clock over the period of use; use devm_{get,put}_clk()

clock lookup is non-fatal as not all platforms provide clock specs in
their device tree; failure to enable specified clocks is fatal

Signed-off-by: Gerhard Sittig <redacted>
---
 .../net/ethernet/freescale/fs_enet/fs_enet-main.c  |   25 ++++++++++++++++++++
 include/linux/fs_enet_pd.h                         |    3 +++
 2 files changed, 28 insertions(+)
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index c04eb3a..1f58f57 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -999,6 +999,8 @@ static int fs_enet_probe(struct platform_device *ofdev)
 	struct fs_enet_private *fep;
 	struct fs_platform_info *fpi;
 	const u32 *data;
+	struct clk *clk;
+	int err;
 	const u8 *mac_addr;
 	const char *phy_connection_type;
 	int privsize, len, ret = -ENODEV;
@@ -1036,6 +1038,21 @@ static int fs_enet_probe(struct platform_device *ofdev)
 			fpi->use_rmii = 1;
 	}
 
+	/* make clock lookup non-fatal (the driver is shared among platforms),
+	 * but require enable to succeed when a clock was specified/found,
+	 * keep a reference to the clock upon successful acquisition
+	 */
+	clk = devm_clk_get(&ofdev->dev, "per");
+	if (!IS_ERR(clk)) {
+		err = clk_prepare_enable(clk);
+		if (err) {
+			devm_clk_put(&ofdev->dev, clk);
+			ret = err;
+			goto out_free_fpi;
+		}
+		fpi->clk_per = clk;
+	}
+
 	privsize = sizeof(*fep) +
 	           sizeof(struct sk_buff **) *
 	           (fpi->rx_ring + fpi->tx_ring);
@@ -1107,6 +1124,10 @@ out_free_dev:
 	free_netdev(ndev);
 out_put:
 	of_node_put(fpi->phy_node);
+	if (fpi->clk_per) {
+		clk_disable_unprepare(fpi->clk_per);
+		devm_clk_put(&ofdev->dev, fpi->clk_per);
+	}
 out_free_fpi:
 	kfree(fpi);
 	return ret;
@@ -1123,6 +1144,10 @@ static int fs_enet_remove(struct platform_device *ofdev)
 	fep->ops->cleanup_data(ndev);
 	dev_set_drvdata(fep->dev, NULL);
 	of_node_put(fep->fpi->phy_node);
+	if (fep->fpi->clk_per) {
+		clk_disable_unprepare(fep->fpi->clk_per);
+		devm_clk_put(&ofdev->dev, fep->fpi->clk_per);
+	}
 	free_netdev(ndev);
 	return 0;
 }
diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h
index 51b7934..a978d0d 100644
--- a/include/linux/fs_enet_pd.h
+++ b/include/linux/fs_enet_pd.h
@@ -16,6 +16,7 @@
 #ifndef FS_ENET_PD_H
 #define FS_ENET_PD_H
 
+#include <linux/clk.h>
 #include <linux/string.h>
 #include <linux/of_mdio.h>
 #include <asm/types.h>
@@ -142,6 +143,8 @@ struct fs_platform_info {
 
 	int use_rmii;		/* use RMII mode 	       */
 	int has_phy;            /* if the network is phy container as well...*/
+
+	struct clk *clk_per;	/* 'per' clock for register access */
 };
 struct fs_mii_fec_platform_info {
 	u32 irq[32];
-- 
1.7.10.4

[PATCH v3 09/31] powerpc/fsl-pci: improve clock API use

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:36

make the Freescale PCI driver get, prepare and enable the PCI clock
during probe()

clock lookup is non-fatal as not all platforms may provide clock specs
in their device tree, but failure to enable specified clocks are fatal

the driver appears to not have a remove() routine, so no reference to
the clock is kept during use, and the clock isn't released (the devm
approach will put the clock, but it won't get disabled or unprepared)

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/sysdev/fsl_pci.c |   23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 46ac1dd..5e2f411 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -17,6 +17,8 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  */
+
+#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -926,12 +928,33 @@ void fsl_pci_assign_primary(void)
 
 static int fsl_pci_probe(struct platform_device *pdev)
 {
+	struct clk *clk;
 	int ret;
 	struct device_node *node;
 #ifdef CONFIG_SWIOTLB
 	struct pci_controller *hose;
 #endif
 
+	/*
+	 * clock lookup is non-fatal since the driver is shared among
+	 * platforms and not all of them provide clocks specs in their
+	 * device tree, but failure to enable a specified clock is
+	 * considered fatal
+	 */
+	clk = devm_clk_get(&pdev->dev, "per");
+	if (!IS_ERR(clk)) {
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			dev_err(dev, "Could not enable peripheral clock\n");
+			devm_clk_put(&pdev->dev, clk);
+			return ret;
+		}
+		/*
+		 * TODO where to store the 'clk' reference?  there appears
+		 * to be no remove() routine which undoes what probe() does
+		 */
+	}
+
 	node = pdev->dev.of_node;
 	ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
 
-- 
1.7.10.4

[PATCH v3 10/31] net: can: mscan: add a comment on reg to idx mapping

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:37

add a comment about the magic of deriving an MSCAN component index
from the peripheral's physical address / register offset

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/net/can/mscan/mpc5xxx_can.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index 5b0ee8e..bc422ba 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -148,7 +148,10 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 		goto exit_put;
 	}
 
-	/* Determine the MSCAN device index from the physical address */
+	/* Determine the MSCAN device index from the peripheral's
+	 * physical address. Register address offsets against the
+	 * IMMR base are:  0x1300, 0x1380, 0x2300, 0x2380
+	 */
 	pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
 	BUG_ON(!pval || plen < sizeof(*pval));
 	clockidx = (*pval & 0x80) ? 1 : 0;
-- 
1.7.10.4

[PATCH v3 11/31] net: can: mscan: improve clock API use

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:38

the .get_clock() callback is run from probe() and might allocate
resources, introduce a .put_clock() callback that is run from remove()
to undo any allocation activities

use devm_get_clk() upon lookup (for SYS and REF) to have the clocks put
upon driver unload

assume that resources get prepared but not necessarily enabled in the
setup phase, make the open() and close() callbacks of the CAN network
device enable and disable a previously acquired and prepared clock

store pointers to data structures upon successful allocation already
instead of deferral until complete setup, such that subroutines in the
setup sequence may access those data structures as well to track their
resource acquisition

since clock allocation remains optional, the release callback as well as
the enable/disable calls in open/close are optional as well

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/net/can/mscan/mpc5xxx_can.c |   18 ++++++++++++------
 drivers/net/can/mscan/mscan.c       |    9 +++++++++
 drivers/net/can/mscan/mscan.h       |    2 ++
 3 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index bc422ba..e59b3a3 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -40,6 +40,7 @@ struct mpc5xxx_can_data {
 	unsigned int type;
 	u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name,
 			 int *mscan_clksrc);
+	void (*put_clock)(struct platform_device *ofdev);
 };
 
 #ifdef CONFIG_PPC_MPC52xx
@@ -180,7 +181,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 			clockdiv = 1;
 
 		if (!clock_name || !strcmp(clock_name, "sys")) {
-			sys_clk = clk_get(&ofdev->dev, "sys_clk");
+			sys_clk = devm_clk_get(&ofdev->dev, "sys_clk");
 			if (IS_ERR(sys_clk)) {
 				dev_err(&ofdev->dev, "couldn't get sys_clk\n");
 				goto exit_unmap;
@@ -203,7 +204,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 		}
 
 		if (clocksrc < 0) {
-			ref_clk = clk_get(&ofdev->dev, "ref_clk");
+			ref_clk = devm_clk_get(&ofdev->dev, "ref_clk");
 			if (IS_ERR(ref_clk)) {
 				dev_err(&ofdev->dev, "couldn't get ref_clk\n");
 				goto exit_unmap;
@@ -280,6 +281,8 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
 	dev = alloc_mscandev();
 	if (!dev)
 		goto exit_dispose_irq;
+	platform_set_drvdata(ofdev, dev);
+	SET_NETDEV_DEV(dev, &ofdev->dev);
 
 	priv = netdev_priv(dev);
 	priv->reg_base = base;
@@ -296,8 +299,6 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
 		goto exit_free_mscan;
 	}
 
-	SET_NETDEV_DEV(dev, &ofdev->dev);
-
 	err = register_mscandev(dev, mscan_clksrc);
 	if (err) {
 		dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
@@ -305,8 +306,6 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
 		goto exit_free_mscan;
 	}
 
-	platform_set_drvdata(ofdev, dev);
-
 	dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
 		 priv->reg_base, dev->irq, priv->can.clock.freq);
 
@@ -324,10 +323,17 @@ exit_unmap_mem:
 
 static int mpc5xxx_can_remove(struct platform_device *ofdev)
 {
+	const struct of_device_id *match;
+	const struct mpc5xxx_can_data *data;
 	struct net_device *dev = platform_get_drvdata(ofdev);
 	struct mscan_priv *priv = netdev_priv(dev);
 
+	match = of_match_device(mpc5xxx_can_table, &ofdev->dev);
+	data = match ? match->data : NULL;
+
 	unregister_mscandev(dev);
+	if (data && data->put_clock)
+		data->put_clock(ofdev);
 	iounmap(priv->reg_base);
 	irq_dispose_mapping(dev->irq);
 	free_candev(dev);
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index e6b4095..1c08ffe 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -573,6 +573,12 @@ static int mscan_open(struct net_device *dev)
 	struct mscan_priv *priv = netdev_priv(dev);
 	struct mscan_regs __iomem *regs = priv->reg_base;
 
+	if (priv->clk_can) {
+		ret = clk_enable(priv->clk_can);
+		if (ret)
+			return ret;
+	}
+
 	/* common open */
 	ret = open_candev(dev);
 	if (ret)
@@ -621,6 +627,9 @@ static int mscan_close(struct net_device *dev)
 	close_candev(dev);
 	free_irq(dev->irq, dev);
 
+	if (priv->clk_can)
+		clk_disable(priv->clk_can);
+
 	return 0;
 }
 
diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h
index af2ed8b..f32e190 100644
--- a/drivers/net/can/mscan/mscan.h
+++ b/drivers/net/can/mscan/mscan.h
@@ -21,6 +21,7 @@
 #ifndef __MSCAN_H__
 #define __MSCAN_H__
 
+#include <linux/clk.h>
 #include <linux/types.h>
 
 /* MSCAN control register 0 (CANCTL0) bits */
@@ -283,6 +284,7 @@ struct mscan_priv {
 	unsigned int type; 	/* MSCAN type variants */
 	unsigned long flags;
 	void __iomem *reg_base;	/* ioremap'ed address to registers */
+	struct clk *clk_can;	/* clock for registers or bitrates */
 	u8 shadow_statflg;
 	u8 shadow_canrier;
 	u8 cur_pri;
-- 
1.7.10.4

[PATCH v3 12/31] powerpc: mpc512x: array decl for MCLK registers in CCM

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:39

reword the clock control module's registers declaration such that the
MCLK related registers form an array and get indexed by PSC number

this change is in preparation to COMMON_CLK support for the MPC512x
platform, the changed declaration remains neutral to existing code since
the PSC and MSCAN CCR fields declared here aren't referenced anywhere

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/include/asm/mpc5121.h |   18 ++----------------
 1 file changed, 2 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/include/asm/mpc5121.h b/arch/powerpc/include/asm/mpc5121.h
index 8ae133e..887d3d6 100644
--- a/arch/powerpc/include/asm/mpc5121.h
+++ b/arch/powerpc/include/asm/mpc5121.h
@@ -32,25 +32,11 @@ struct mpc512x_ccm {
 	u32	scfr2;	/* System Clock Frequency Register 2 */
 	u32	scfr2s;	/* System Clock Frequency Shadow Register 2 */
 	u32	bcr;	/* Bread Crumb Register */
-	u32	p0ccr;	/* PSC0 Clock Control Register */
-	u32	p1ccr;	/* PSC1 CCR */
-	u32	p2ccr;	/* PSC2 CCR */
-	u32	p3ccr;	/* PSC3 CCR */
-	u32	p4ccr;	/* PSC4 CCR */
-	u32	p5ccr;	/* PSC5 CCR */
-	u32	p6ccr;	/* PSC6 CCR */
-	u32	p7ccr;	/* PSC7 CCR */
-	u32	p8ccr;	/* PSC8 CCR */
-	u32	p9ccr;	/* PSC9 CCR */
-	u32	p10ccr;	/* PSC10 CCR */
-	u32	p11ccr;	/* PSC11 CCR */
+	u32	psc_ccr[12];	/* PSC Clock Control Registers */
 	u32	spccr;	/* SPDIF Clock Control Register */
 	u32	cccr;	/* CFM Clock Control Register */
 	u32	dccr;	/* DIU Clock Control Register */
-	u32	m1ccr;	/* MSCAN1 CCR */
-	u32	m2ccr;	/* MSCAN2 CCR */
-	u32	m3ccr;	/* MSCAN3 CCR */
-	u32	m4ccr;	/* MSCAN4 CCR */
+	u32	mscan_ccr[4];	/* MSCAN Clock Control Registers */
 	u8	res[0x98]; /* Reserved */
 };
 
-- 
1.7.10.4

[PATCH v3 13/31] clk: wrap I/O access for improved portability

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:40

the common clock drivers were motivated/initiated by ARM development
and apparently assume little endian peripherals

wrap register/peripherals access in the common code (div, gate, mux)
in preparation of adding COMMON_CLK support for other platforms

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/clk/clk-divider.c    |    6 +++---
 drivers/clk/clk-gate.c       |    6 +++---
 drivers/clk/clk-mux.c        |    6 +++---
 include/linux/clk-provider.h |   17 +++++++++++++++++
 4 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 6d55eb2..2c07061 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	struct clk_divider *divider = to_clk_divider(hw);
 	unsigned int div, val;
 
-	val = readl(divider->reg) >> divider->shift;
+	val = clk_readl(divider->reg) >> divider->shift;
 	val &= div_mask(divider);
 
 	div = _get_div(divider, val);
@@ -230,11 +230,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
 		val = div_mask(divider) << (divider->shift + 16);
 	} else {
-		val = readl(divider->reg);
+		val = clk_readl(divider->reg);
 		val &= ~(div_mask(divider) << divider->shift);
 	}
 	val |= value << divider->shift;
-	writel(val, divider->reg);
+	clk_writel(val, divider->reg);
 
 	if (divider->lock)
 		spin_unlock_irqrestore(divider->lock, flags);
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 790306e..b7fbd96 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -58,7 +58,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 		if (set)
 			reg |= BIT(gate->bit_idx);
 	} else {
-		reg = readl(gate->reg);
+		reg = clk_readl(gate->reg);
 
 		if (set)
 			reg |= BIT(gate->bit_idx);
@@ -66,7 +66,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 			reg &= ~BIT(gate->bit_idx);
 	}
 
-	writel(reg, gate->reg);
+	clk_writel(reg, gate->reg);
 
 	if (gate->lock)
 		spin_unlock_irqrestore(gate->lock, flags);
@@ -89,7 +89,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
 	u32 reg;
 	struct clk_gate *gate = to_clk_gate(hw);
 
-	reg = readl(gate->reg);
+	reg = clk_readl(gate->reg);
 
 	/* if a set bit disables this clk, flip it before masking */
 	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 614444c..02ef506 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -42,7 +42,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
 	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
 	 * val = 0x4 really means "bit 2, index starts at bit 0"
 	 */
-	val = readl(mux->reg) >> mux->shift;
+	val = clk_readl(mux->reg) >> mux->shift;
 	val &= mux->mask;
 
 	if (mux->table) {
@@ -89,11 +89,11 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
 	if (mux->flags & CLK_MUX_HIWORD_MASK) {
 		val = mux->mask << (mux->shift + 16);
 	} else {
-		val = readl(mux->reg);
+		val = clk_readl(mux->reg);
 		val &= ~(mux->mask << mux->shift);
 	}
 	val |= index << mux->shift;
-	writel(val, mux->reg);
+	clk_writel(val, mux->reg);
 
 	if (mux->lock)
 		spin_unlock_irqrestore(mux->lock, flags);
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 1ec14a7..c4f7799 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -12,6 +12,7 @@
 #define __LINUX_CLK_PROVIDER_H
 
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #ifdef CONFIG_COMMON_CLK
 
@@ -490,5 +491,21 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
 #define of_clk_init(matches) \
 	{ while (0); }
 #endif /* CONFIG_OF */
+
+/*
+ * wrap access to peripherals in accessor routines
+ * for improved portability across platforms
+ */
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+	return readl(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+	writel(val, reg);
+}
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
-- 
1.7.10.4

[PATCH v3 14/31] dts: mpc512x: prepare for preprocessor support

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:41

prepare C preprocessor support when processing MPC512x DTS files
- switch from DTS syntax to CPP syntax for include specs
- create a symlink such that DTS processing can reference includes

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/boot/dts/ac14xx.dts          |    2 +-
 arch/powerpc/boot/dts/include/dt-bindings |    1 +
 arch/powerpc/boot/dts/mpc5121ads.dts      |    2 +-
 arch/powerpc/boot/dts/pdm360ng.dts        |    2 +-
 4 files changed, 4 insertions(+), 3 deletions(-)
 create mode 120000 arch/powerpc/boot/dts/include/dt-bindings
diff --git a/arch/powerpc/boot/dts/ac14xx.dts b/arch/powerpc/boot/dts/ac14xx.dts
index a27a460..a543c40 100644
--- a/arch/powerpc/boot/dts/ac14xx.dts
+++ b/arch/powerpc/boot/dts/ac14xx.dts
@@ -10,7 +10,7 @@
  */
 
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "ac14xx";
diff --git a/arch/powerpc/boot/dts/include/dt-bindings b/arch/powerpc/boot/dts/include/dt-bindings
new file mode 120000
index 0000000..08c00e4
--- /dev/null
+++ b/arch/powerpc/boot/dts/include/dt-bindings
@@ -0,0 +1 @@
+../../../../../include/dt-bindings
\ No newline at end of file
diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
index 7d3cb79..c228a0a 100644
--- a/arch/powerpc/boot/dts/mpc5121ads.dts
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -9,7 +9,7 @@
  * option) any later version.
  */
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "mpc5121ads";
diff --git a/arch/powerpc/boot/dts/pdm360ng.dts b/arch/powerpc/boot/dts/pdm360ng.dts
index 7433740..871c16d 100644
--- a/arch/powerpc/boot/dts/pdm360ng.dts
+++ b/arch/powerpc/boot/dts/pdm360ng.dts
@@ -13,7 +13,7 @@
  * option) any later version.
  */
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "pdm360ng";
-- 
1.7.10.4

[PATCH v3 15/31] dts: mpc512x: introduce dt-bindings/clock/ header

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:42

introduce a dt-bindings/ header file for MPC512x clocks,
providing symbolic identifiers for those SoC clocks which
clients will reference from their device tree nodes

Signed-off-by: Gerhard Sittig <redacted>
---
 include/dt-bindings/clock/mpc512x-clock.h |   59 +++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h
diff --git a/include/dt-bindings/clock/mpc512x-clock.h b/include/dt-bindings/clock/mpc512x-clock.h
new file mode 100644
index 0000000..46c560e
--- /dev/null
+++ b/include/dt-bindings/clock/mpc512x-clock.h
@@ -0,0 +1,59 @@
+/*
+ * This header provides constants for MPC512x clock specs in DT bindings.
+ *
+ * Unfortunately the clock number declaration cannot be an enum but
+ * needs to be a list of #define directives since when referenced from
+ * within DTS files they need to get resolved "at compile time".
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+
+#define MPC512x_CLK_DUMMY		0
+#define MPC512x_CLK_REF			1
+#define MPC512x_CLK_SYS			2
+#define MPC512x_CLK_DIU			3
+#define MPC512x_CLK_VIU			4
+#define MPC512x_CLK_CSB			5
+#define MPC512x_CLK_E300		6
+#define MPC512x_CLK_IPS			7
+#define MPC512x_CLK_FEC			8
+#define MPC512x_CLK_SATA		9
+#define MPC512x_CLK_PATA		10
+#define MPC512x_CLK_NFC			11
+#define MPC512x_CLK_LPC			12
+#define MPC512x_CLK_MBX_BUS		13
+#define MPC512x_CLK_MBX			14
+#define MPC512x_CLK_MBX_3D		15
+#define MPC512x_CLK_AXE			16
+#define MPC512x_CLK_USB1		17
+#define MPC512x_CLK_USB2		18
+#define MPC512x_CLK_I2C			19
+#define MPC512x_CLK_MSCAN0_MCLK		20
+#define MPC512x_CLK_MSCAN1_MCLK		21
+#define MPC512x_CLK_MSCAN2_MCLK		22
+#define MPC512x_CLK_MSCAN3_MCLK		23
+#define MPC512x_CLK_SDHC		24
+#define MPC512x_CLK_PCI			25
+#define MPC512x_CLK_PSC_MCLK_IN		26
+#define MPC512x_CLK_SPDIF_TX		27
+#define MPC512x_CLK_SPDIF_RX		28
+#define MPC512x_CLK_SPDIF_MCLK		29
+#define MPC512x_CLK_AC97		30
+#define MPC512x_CLK_PSC0_MCLK		31
+#define MPC512x_CLK_PSC1_MCLK		32
+#define MPC512x_CLK_PSC2_MCLK		33
+#define MPC512x_CLK_PSC3_MCLK		34
+#define MPC512x_CLK_PSC4_MCLK		35
+#define MPC512x_CLK_PSC5_MCLK		36
+#define MPC512x_CLK_PSC6_MCLK		37
+#define MPC512x_CLK_PSC7_MCLK		38
+#define MPC512x_CLK_PSC8_MCLK		39
+#define MPC512x_CLK_PSC9_MCLK		40
+#define MPC512x_CLK_PSC10_MCLK		41
+#define MPC512x_CLK_PSC11_MCLK		42
+#define MPC512x_CLK_PSC_FIFO		43
+
+#define MPC512x_CLK_LAST_PUBLIC		43
+
+#endif
-- 
1.7.10.4

[PATCH v3 16/31] dts: mpc512x: add clock related device tree specs

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:43

this addresses the clock driver aka provider's side of clocks
- prepare for future '<&clks ID>' phandle references for device tree
  based clock lookup in client drivers
- introduce a 'clocks' subtree with an 'osc' node for the crystal
  or oscillator SoC input (fixed frequency)
- provide default values with 33MHz oscillator frequency in the
  common include (the 66MHz IPS bus already was there), add
  override values for the ifm AC14xx board which deviates from
  the reference design (25MHz xtal, 80MHz IPS bus)

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/boot/dts/ac14xx.dts   |    7 +++++++
 arch/powerpc/boot/dts/mpc5121.dtsi |   15 ++++++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/boot/dts/ac14xx.dts b/arch/powerpc/boot/dts/ac14xx.dts
index a543c40..a1b8837 100644
--- a/arch/powerpc/boot/dts/ac14xx.dts
+++ b/arch/powerpc/boot/dts/ac14xx.dts
@@ -139,7 +139,14 @@
 		};
 	};
 
+	clocks {
+		osc {
+			clock-frequency = <25000000>;
+		};
+	};
+
 	soc@80000000 {
+		bus-frequency = <80000000>;	/* 80 MHz ips bus */
 
 		clock@f00 {
 			compatible = "fsl,mpc5121rev2-clock", "fsl,mpc5121-clock";
diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
index bd14c00..8f4cba0 100644
--- a/arch/powerpc/boot/dts/mpc5121.dtsi
+++ b/arch/powerpc/boot/dts/mpc5121.dtsi
@@ -9,6 +9,8 @@
  * option) any later version.
  */
 
+#include <dt-bindings/clock/mpc512x-clock.h>
+
 /dts-v1/;
 
 / {
@@ -73,6 +75,16 @@
 		ranges = <0x0 0x0 0xfc000000 0x04000000>;
 	};
 
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		osc {
+			compatible = "fsl,mpc512x-osc", "fixed-clock";
+			clock-frequency = <33000000>;
+		};
+	};
+
 	soc@80000000 {
 		compatible = "fsl,mpc5121-immr";
 		#address-cells = <1>;
@@ -118,9 +130,10 @@
 		};
 
 		/* Clock control */
-		clock@f00 {
+		clks: clock@f00 {
 			compatible = "fsl,mpc5121-clock";
 			reg = <0xf00 0x100>;
+			#clock-cells = <1>;
 		};
 
 		/* Power Management Controller */
-- 
1.7.10.4

[PATCH v3 17/31] clk: mpc512x: introduce COMMON_CLK for MPC512x

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:44

this change implements a clock driver for the MPC512x PowerPC platform
which follows the COMMON_CLK approach and uses common clock drivers
shared with other platforms

this driver implements the publicly announced set of clocks (which can
get referenced by means of symbolic identifiers from the dt-bindings
header file), as well as generates additional 'struct clk' items where
the SoC hardware cannot easily get mapped to the common primitives of
the clock API, or requires "intermediate" clock nodes to represent
clocks that have both gates and dividers

the previous PPC_CLOCK implementation is kept in place and remains in
parallel to the common clock implementation for test and comparison
during migration, a compile time option picks one of the two
alternatives (Kconfig switch, common clock used by default)

some of the clock items get pre-enabled in the clock driver to not have
them automatically disabled by the underlying clock subsystem because of
their being unused -- this approach is desirable because
- some of the clocks are useful to have for diagnostics and information
  despite their not getting claimed by any drivers (CPU, internal and
  external RAM, internal busses, boot media)
- some of the clocks aren't claimed by their peripheral drivers yet,
  either because of missing driver support or because device tree specs
  aren't available yet (but the workarounds will get removed as the
  drivers get adjusted and the device tree provides the clock specs)
- some help introduce support for and migrate to the common
  infrastructure, while more appropriate support for specific hardware
  constraints isn't available yet (remaining changes are strictly
  internal to the clock driver and won't affect peripheral drivers)

clkdev registration provides "alias names" for few clock items
- to not break those peripheral drivers which encode their component
  index into the name that is used for clock lookup (UART, SPI, USB)
- to not break those drivers which use names for the clock lookup which
  were encoded in the previous PPC_CLOCK implementation (NFC, VIU, CAN)
this workaround will get removed as these drivers get adjusted after
device tree based clock lookup has become available

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/Kconfig           |   14 +-
 arch/powerpc/platforms/512x/Makefile          |    4 +-
 arch/powerpc/platforms/512x/clock-commonclk.c |  786 +++++++++++++++++++++++++
 include/linux/clk-provider.h                  |   16 +
 4 files changed, 818 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index fc9c1cb..c5fcdd0 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -1,9 +1,21 @@
+config MPC512x_COMMON_CLK
+	bool "MPC512x platform uses COMMON_CLK"
+	default y
+	depends on PPC_MPC512x
+	help
+	  This option is only here to support tests and comparison
+	  during development and migration.  This option will get
+	  removed after the COMMON_CLK support for MPC512x has become
+	  fully operational and all drivers were adjusted to explicitly
+	  acquire their required clocks.
+
 config PPC_MPC512x
 	bool "512x-based boards"
 	depends on 6xx
 	select FSL_SOC
 	select IPIC
-	select PPC_CLOCK
+	select PPC_CLOCK if !MPC512x_COMMON_CLK
+	select COMMON_CLK if MPC512x_COMMON_CLK
 	select PPC_PCI_CHOICE
 	select FSL_PCI if PCI
 	select ARCH_WANT_OPTIONAL_GPIOLIB
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
index 72fb934..1e05f9d 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -1,7 +1,9 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-y				+= clock.o mpc512x_shared.o
+obj-$(CONFIG_PPC_CLOCK)		+= clock.o
+obj-$(CONFIG_COMMON_CLK)	+= clock-commonclk.o
+obj-y				+= mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)	+= mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)	+= mpc512x_generic.o
 obj-$(CONFIG_PDM360NG)		+= pdm360ng.o
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
new file mode 100644
index 0000000..762ee85
--- /dev/null
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -0,0 +1,786 @@
+/*
+ * Copyright (C) 2013 DENX Software Engineering
+ *
+ * Gerhard Sittig, <gsi@denx.de>
+ *
+ * common clock driver support for the MPC512x platform
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <asm/mpc5121.h>
+#include <dt-bindings/clock/mpc512x-clock.h>
+
+#include "mpc512x.h"		/* our public mpc5121_clk_init() API */
+
+/* helpers to keep the MCLK intermediates "somewhere" in our table */
+enum {
+	MCLK_IDX_MUX0,
+	MCLK_IDX_EN0,
+	MCLK_IDX_DIV0,
+	MCLK_IDX_MUX1,
+	MCLK_MAX_IDX,
+};
+
+#define NR_PSCS			12
+#define NR_MSCANS		4
+#define NR_SPDIFS		1
+#define NR_MCLKS		(NR_PSCS + NR_MSCANS + NR_SPDIFS)
+
+/* extend the public set of clocks by adding internal slots for management */
+enum {
+	/* arrange for adjacent numbers after the public set */
+	MPC512x_CLK_START_PRIVATE = MPC512x_CLK_LAST_PUBLIC,
+	/* clocks which aren't announced to the public */
+	MPC512x_CLK_DDR,
+	MPC512x_CLK_MEM,
+	MPC512x_CLK_IIM,
+	MPC512x_CLK_SDHC_2,
+	/* intermediates in div+gate combos or fractional dividers */
+	MPC512x_CLK_DDR_UG,
+	MPC512x_CLK_SDHC_x4,
+	MPC512x_CLK_SDHC_UG,
+	MPC512x_CLK_DIU_x4,
+	MPC512x_CLK_DIU_UG,
+	MPC512x_CLK_MBX_BUS_UG,
+	MPC512x_CLK_MBX_UG,
+	MPC512x_CLK_MBX_3D_UG,
+	MPC512x_CLK_PCI_UG,
+	MPC512x_CLK_NFC_UG,
+	MPC512x_CLK_LPC_UG,
+	MPC512x_CLK_SPDIF_TX_IN,
+	/* intermediates for the mux+gate+div+mux MCLK generation */
+	MPC512x_CLK_MCLKS_FIRST,
+	MPC512x_CLK_MCLKS_LAST = MPC512x_CLK_MCLKS_FIRST
+				+ NR_MCLKS * MCLK_MAX_IDX,
+	/* internal, symbolic spec for the number of slots */
+	MPC512x_CLK_LAST_PRIVATE,
+};
+
+/* data required for the OF clock provider registration */
+static struct clk *clks[MPC512x_CLK_LAST_PRIVATE];
+static struct clk_onecell_data clk_data;
+
+/* CCM register access */
+static struct mpc512x_ccm __iomem *clkregs;
+static DEFINE_SPINLOCK(clklock);
+
+/* convenience wrappers around the common clk API */
+static inline struct clk *mpc512x_clk_fixed(const char *name, int rate)
+{
+	return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);
+}
+
+static inline struct clk *mpc512x_clk_factor(
+	const char *name, const char *parent_name,
+	int mul, int div)
+{
+	int clkflags;
+
+	clkflags = CLK_SET_RATE_PARENT;
+	return clk_register_fixed_factor(NULL, name, parent_name, clkflags,
+					 mul, div);
+}
+
+static inline struct clk *mpc512x_clk_divider(
+	const char *name, const char *parent_name, u8 clkflags,
+	u32 __iomem *reg, u8 pos, u8 len, int divflags)
+{
+	return clk_register_divider(NULL, name, parent_name, clkflags,
+				    reg, pos, len, divflags, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_divtable(
+	const char *name, const char *parent_name,
+	u32 __iomem *reg, u8 pos, u8 len,
+	const struct clk_div_table *divtab)
+{
+	u8 divflags;
+
+	divflags = 0;
+	return clk_register_divider_table(NULL, name, parent_name, 0,
+					  reg, pos, len, divflags,
+					  divtab, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_gated(
+	const char *name, const char *parent_name,
+	u32 __iomem *reg, u8 pos)
+{
+	int clkflags;
+
+	clkflags = CLK_SET_RATE_PARENT;
+	return clk_register_gate(NULL, name, parent_name, clkflags,
+				 reg, pos, 0, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_muxed(const char *name,
+	const char **parent_names, int parent_count,
+	u32 __iomem *reg, u8 pos, u8 len)
+{
+	int clkflags;
+	u8 muxflags;
+
+	clkflags = CLK_SET_RATE_PARENT;
+	muxflags = 0;
+	return clk_register_mux(NULL, name,
+				parent_names, parent_count, clkflags,
+				reg, pos, len, muxflags, &clklock);
+}
+
+/* helper to isolate a bit field from a register */
+static inline int get_bit_field(uint32_t __iomem *reg, uint8_t pos, uint8_t len)
+{
+	uint32_t val;
+
+	val = in_be32(reg);
+	val >>= pos;
+	val &= (1 << len) - 1;
+	return val;
+}
+
+/* get the SPMF and translate it into the "sys pll" multiplier */
+static int get_spmf_mult(void)
+{
+	static int spmf_to_mult[] = {
+		68, 1, 12, 16, 20, 24, 28, 32,
+		36, 40, 44, 48, 52, 56, 60, 64,
+	};
+	int spmf;
+
+	spmf = get_bit_field(&clkregs->spmr, 24, 4);
+	return spmf_to_mult[spmf];
+}
+
+/*
+ * get the SYS_DIV value and translate it into a divide factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * divide ratio is fractional
+ */
+static int get_sys_div_x2(void)
+{
+	static int sysdiv_code_to_x2[] = {
+		4, 5, 6, 7, 8, 9, 10, 14,
+		12, 16, 18, 22, 20, 24, 26, 30,
+		28, 32, 34, 38, 36, 40, 42, 46,
+		44, 48, 50, 54, 52, 56, 58, 62,
+		60, 64, 66,
+	};
+	int divcode;
+
+	divcode = get_bit_field(&clkregs->scfr2, 26, 6);
+	return sysdiv_code_to_x2[divcode];
+}
+
+/*
+ * get the CPMF value and translate it into a multiplier factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * multiplier ratio is fractional
+ */
+static int get_cpmf_mult_x2(void)
+{
+	static int cpmf_to_mult[] = {
+		72, 2, 2, 3, 4, 5, 6, 7,
+	};
+	int cpmf;
+
+	cpmf = get_bit_field(&clkregs->spmr, 16, 4);
+	return cpmf_to_mult[cpmf];
+}
+
+/*
+ * some of the clock dividers do scale in a linear way, yet not all of
+ * their bit combinations are legal; use a divider table to get a
+ * resulting set of applicable divider values
+ */
+
+/* applies to the IPS_DIV, and PCI_DIV values */
+static struct clk_div_table divtab_2346[] = {
+	{ .val = 2, .div = 2, },
+	{ .val = 3, .div = 3, },
+	{ .val = 4, .div = 4, },
+	{ .val = 6, .div = 6, },
+	{ .div = 0, },
+};
+
+/* applies to the MBX_DIV, LPC_DIV, and NFC_DIV values */
+static struct clk_div_table divtab_1234[] = {
+	{ .val = 1, .div = 1, },
+	{ .val = 2, .div = 2, },
+	{ .val = 3, .div = 3, },
+	{ .val = 4, .div = 4, },
+	{ .div = 0, },
+};
+
+static int get_freq_from_dt(char *propname)
+{
+	struct device_node *np;
+	const unsigned int *prop;
+	int val;
+
+	val = 0;
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
+	if (np) {
+		prop = of_get_property(np, propname, NULL);
+		if (prop)
+			val = *prop;
+	    of_node_put(np);
+	}
+	return val;
+}
+
+static void mpc512x_clk_preset_data(void)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(clks); i++)
+		clks[i] = ERR_PTR(-ENODEV);
+}
+
+/*
+ * - receives the "bus frequency" from the caller (that's the IPS clock
+ *   rate, the historical source of clock information)
+ * - fetches the system PLL multiplier and divider values as well as the
+ *   IPS divider value from hardware
+ * - determines the REF clock rate either from the XTAL/OSC spec (if
+ *   there is a device tree node describing the oscillator) or from the
+ *   IPS bus clock (supported for backwards compatibility, such that
+ *   setups without XTAL/OSC specs keep working)
+ * - creates the "ref" clock item in the clock tree, such that
+ *   subsequent code can create the remainder of the hierarchy (REF ->
+ *   SYS -> CSB -> IPS) from the REF clock rate and the returned mul/div
+ *   values
+ */
+static void mpc512x_clk_setup_ref_clock(int bus_freq,
+	int *sys_mul, int *sys_div, int *ips_div)
+{
+	struct clk *osc_clk;
+	int calc_freq;
+
+	/* fetch mul/div factors from the hardware */
+	*sys_mul = get_spmf_mult();
+	*sys_mul *= 2;		/* compensate for the fractional divider */
+	*sys_div = get_sys_div_x2();
+	*ips_div = get_bit_field(&clkregs->scfr1, 23, 3);
+
+	/* lookup the oscillator node */
+	osc_clk = clk_get(NULL, "osc");
+	if (osc_clk) {
+		/* descend REF directly from OSC, verify the IPS rate */
+		clks[MPC512x_CLK_REF] = mpc512x_clk_factor("ref", "osc", 1, 1);
+		calc_freq = clk_get_rate(clks[MPC512x_CLK_REF]);
+		calc_freq *= *sys_mul;
+		calc_freq /= *sys_div;
+		calc_freq /= 2;
+		calc_freq /= *ips_div;
+		if (bus_freq && calc_freq != bus_freq)
+			pr_warn("calc rate %d != OF spec %d\n",
+				calc_freq, bus_freq);
+	} else {
+		/* calculate OSC rate and create REF from the freq value */
+		calc_freq = bus_freq;	/* start with IPS */
+		calc_freq *= *ips_div;	/* IPS -> CSB */
+		calc_freq *= 2;		/* CSB -> SYS */
+		calc_freq *= *sys_div;	/* SYS -> PLL out */
+		calc_freq /= *sys_mul;	/* PLL out -> REF == OSC */
+		clks[MPC512x_CLK_REF] = mpc512x_clk_fixed("ref", calc_freq);
+	}
+}
+
+/*
+ * helper code for the MCLK subtree setup
+ *
+ * the overview in section 5.2.4 of the MPC5121e Reference Manual rev4
+ * suggests that all instances of the "PSC clock generation" are equal,
+ * and that one might re-use the PSC setup for MSCAN clock generation
+ * (section 5.2.5) as well, at least the logic if not the data for
+ * description
+ *
+ * the details (starting at page 5-20) show differences in the specific
+ * inputs of the first mux stage ("can clk in", "spdif tx"), and the
+ * factual non-availability of the second mux stage (it's present yet
+ * only one input is valid)
+ *
+ * the MSCAN clock related registers (starting at page 5-35) all
+ * reference "spdif clk" at the first mux stage and don't mention any
+ * "can clk" at all, which somehow is unexpected
+ *
+ * TODO re-check the document, and clarify whether the RM is correct in
+ * the overview or in the details, and whether the difference is a
+ * clipboard induced error or results from chip revisions
+ *
+ * it turns out that the RM rev4 as of 2012-06 talks about "can" for the
+ * PSCs while RM rev3 as of 2008-10 talks about "spdif", so I guess that
+ * first a doc update is required which better reflects reality in the
+ * SoC before the implementation should follow while no questions remain
+ */
+
+/*
+ * note that this declaration raises a checkpatch warning, but
+ * it's the very data type which <linux/clk-provider.h> expects,
+ * making this declaration pass checkpatch will break compilation
+ */
+static const char *parent_names_mux0[] = {
+	"sys", "ref", "psc-mclk-in", "spdif-tx",
+};
+
+enum mclk_type {
+	MCLK_TYPE_PSC,
+	MCLK_TYPE_MSCAN,
+	MCLK_TYPE_SPDIF,
+};
+
+struct mclk_setup_data {
+	enum mclk_type type;
+	int comp_idx;
+	bool has_mclk1;
+	int bit_sccr1, bit_sccr2;
+	const char *name_mux0;
+	const char *name_en0;
+	const char *name_div0;
+	const char *parent_names_mux1[2];
+	const char *name_mux1;
+	const char *name_mclk;
+};
+
+#define MCLK_SETUP_DATA_PSC(id) { \
+	MCLK_TYPE_PSC, id, \
+	0, 27 - id, -1, \
+	"psc" #id "-mux0", \
+	"psc" #id "-en0", \
+	"psc" #id "_mclk_div", \
+	{ "psc" #id "_mclk_div", "dummy", }, \
+	"psc" #id "_mclk_out", \
+	"psc" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_MSCAN(id) { \
+	MCLK_TYPE_MSCAN, id, \
+	0, -1, 25, \
+	"mscan" #id "-mux0", \
+	"mscan" #id "-en0", \
+	"mscan" #id "_mclk_div", \
+	{ "mscan" #id "_mclk_div", "dummy", }, \
+	"mscan" #id "_mclk_out", \
+	"mscan" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_SPDIF { \
+	MCLK_TYPE_SPDIF, 0, \
+	1, -1, 23, \
+	"spdif-mux0", \
+	"spdif-en0", \
+	"spdif_mclk_div", \
+	{ "spdif_mclk_div", "spdif-rx", }, \
+	"spdif_mclk_out", \
+	"spdif_mclk", \
+}
+
+static struct mclk_setup_data mclk_psc_data[] = {
+	MCLK_SETUP_DATA_PSC(0),
+	MCLK_SETUP_DATA_PSC(1),
+	MCLK_SETUP_DATA_PSC(2),
+	MCLK_SETUP_DATA_PSC(3),
+	MCLK_SETUP_DATA_PSC(4),
+	MCLK_SETUP_DATA_PSC(5),
+	MCLK_SETUP_DATA_PSC(6),
+	MCLK_SETUP_DATA_PSC(7),
+	MCLK_SETUP_DATA_PSC(8),
+	MCLK_SETUP_DATA_PSC(9),
+	MCLK_SETUP_DATA_PSC(10),
+	MCLK_SETUP_DATA_PSC(11),
+};
+
+static struct mclk_setup_data mclk_mscan_data[] = {
+	MCLK_SETUP_DATA_MSCAN(0),
+	MCLK_SETUP_DATA_MSCAN(1),
+	MCLK_SETUP_DATA_MSCAN(2),
+	MCLK_SETUP_DATA_MSCAN(3),
+};
+
+static struct mclk_setup_data mclk_spdif_data[] = {
+	MCLK_SETUP_DATA_SPDIF,
+};
+
+/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
+static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
+{
+	size_t clks_idx_pub, clks_idx_int;
+	u32 __iomem *mccr_reg;	/* MCLK control register (mux, en, div) */
+	u32 __iomem *sccr_reg;	/* system clock control register (enable) */
+	int sccr_bit;
+	int div;
+
+	/* derive a few parameters from the component type and index */
+	switch (entry->type) {
+	case MCLK_TYPE_PSC:
+		clks_idx_pub = MPC512x_CLK_PSC0_MCLK + entry->comp_idx;
+		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+			     + (entry->comp_idx) * MCLK_MAX_IDX;
+		mccr_reg = &clkregs->psc_ccr[entry->comp_idx];
+		break;
+	case MCLK_TYPE_MSCAN:
+		clks_idx_pub = MPC512x_CLK_MSCAN0_MCLK + entry->comp_idx;
+		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+			     + (NR_PSCS + entry->comp_idx) * MCLK_MAX_IDX;
+		mccr_reg = &clkregs->mscan_ccr[entry->comp_idx];
+		break;
+	case MCLK_TYPE_SPDIF:
+		clks_idx_pub = MPC512x_CLK_SPDIF_MCLK;
+		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+			     + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
+		mccr_reg = &clkregs->spccr;
+		break;
+	default:
+		return;
+	}
+	if (entry->bit_sccr1 >= 0) {
+		sccr_reg = &clkregs->sccr1;
+		sccr_bit = entry->bit_sccr1;
+	} else if (entry->bit_sccr2 >= 0) {
+		sccr_reg = &clkregs->sccr2;
+		sccr_bit = entry->bit_sccr2;
+	} else {
+		sccr_reg = NULL;
+	}
+
+	/*
+	 * this was grabbed from the PPC_CLOCK implementation, which
+	 * enforced a specific MCLK divider while the clock was gated
+	 * during setup (that's a documented hardware requirement)
+	 *
+	 * the PPC_CLOCK implementation might even have violated the
+	 * "MCLK <= IPS" constraint, the fixed divider value of 1
+	 * results in a divider of 2 and thus MCLK = SYS/2 which equals
+	 * CSB which is greater than IPS; the serial port setup may have
+	 * adjusted the divider which the clock setup might have left in
+	 * an undesirable state
+	 *
+	 * initial setup is:
+	 * - MCLK 0 from SYS
+	 * - MCLK DIV such to not exceed the IPS clock
+	 * - MCLK 0 enabled
+	 * - MCLK 1 from MCLK DIV
+	 */
+	div = clk_get_rate(clks[MPC512x_CLK_SYS]);
+	div /= clk_get_rate(clks[MPC512x_CLK_IPS]);
+	out_be32(mccr_reg, (0 << 16));
+	out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
+	out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
+
+	/*
+	 * create the 'struct clk' items of the MCLK's clock subtree
+	 *
+	 * note that by design we always create all nodes and won't take
+	 * shortcuts here, because
+	 * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
+	 *   selectable inputs to the CFM while those who "actually use"
+	 *   the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
+	 *   for their bitrate
+	 * - in the absence of "aliases" for clocks we need to create
+	 *   individial 'struct clk' items for whatever might get
+	 *   referenced or looked up, even if several of those items are
+	 *   identical from the logical POV (their rate value)
+	 * - for easier future maintenance and for better reflection of
+	 *   the SoC's documentation, it appears appropriate to generate
+	 *   clock items even for those muxers which actually are NOPs
+	 *   (those with two inputs of which one is reserved)
+	 */
+	clks[clks_idx_int + MCLK_IDX_MUX0] = mpc512x_clk_muxed(
+			entry->name_mux0,
+			&parent_names_mux0[0], ARRAY_SIZE(parent_names_mux0),
+			mccr_reg, 14, 2);
+	clks[clks_idx_int + MCLK_IDX_EN0] = mpc512x_clk_gated(
+			entry->name_en0, entry->name_mux0,
+			mccr_reg, 16);
+	clks[clks_idx_int + MCLK_IDX_DIV0] = mpc512x_clk_divider(
+			entry->name_div0,
+			entry->name_en0, CLK_SET_RATE_GATE,
+			mccr_reg, 17, 15, 0);
+	if (entry->has_mclk1) {
+		clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_muxed(
+				entry->name_mux1,
+				&entry->parent_names_mux1[0],
+				ARRAY_SIZE(entry->parent_names_mux1),
+				mccr_reg, 7, 1);
+	} else {
+		clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_factor(
+				entry->name_mux1, entry->parent_names_mux1[0],
+				1, 1);
+	}
+	if (sccr_reg) {
+		clks[clks_idx_pub] = mpc512x_clk_gated(
+				entry->name_mclk,
+				entry->name_mux1, sccr_reg, sccr_bit);
+	} else {
+		clks[clks_idx_pub] = mpc512x_clk_factor(
+				entry->name_mclk,
+				entry->name_mux1, 1, 1);
+	}
+
+	/*
+	 * without this "clock device" registration, "simple" lookups in
+	 * the SPI master initialization and serial port setup will fail
+	 *
+	 * those drivers need to get adjusted to lookup their required
+	 * clocks from device tree specs, and device tree nodes need to
+	 * provide the clock specs, before this clkdev registration
+	 * becomes obsolete
+	 */
+	clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
+}
+
+static void mpc512x_clk_setup_mclks(struct mclk_setup_data *table, size_t count)
+{
+	while (count-- > 0)
+		mpc512x_clk_setup_mclk(table++);
+}
+
+static void mpc512x_clk_setup_clock_tree(int busfreq)
+{
+	int sys_mul, sys_div, ips_div;
+	int mul, div;
+	int freq;
+
+	/*
+	 * TODO
+	 * - consider whether to handle clocks which have both gates and
+	 *   dividers via intermediates or by means of composites
+	 * - fractional dividers appear to not map well to composites
+	 *   since they can be seen as a fixed multiplier and an
+	 *   adjustable divider, while composites can only combine at
+	 *   most one of a mux, div, and gate each into one 'struct clk'
+	 *   item
+	 * - PSC/MSCAN/SPDIF clock generation OTOH already is very
+	 *   specific and cannot get mapped to componsites (at least not
+	 *   a single one, maybe two of them, but see the comment about
+	 *   "intermediates are referenced from elsewhere, too")
+	 * - trim the list of auto-enabled clocks after drivers acquire
+	 *   them correctly as needed
+	 */
+
+	/* regardless of whether XTAL/OSC exists, have REF created */
+	mpc512x_clk_setup_ref_clock(busfreq, &sys_mul, &sys_div, &ips_div);
+
+	/* now setup the REF -> SYS -> CSB -> IPS hierarchy */
+	clks[MPC512x_CLK_SYS] = mpc512x_clk_factor("sys", "ref",
+						   sys_mul, sys_div);
+	clks[MPC512x_CLK_CSB] = mpc512x_clk_factor("csb", "sys", 1, 2);
+	clks[MPC512x_CLK_IPS] = mpc512x_clk_divtable("ips", "csb",
+						     &clkregs->scfr1, 23, 3,
+						     divtab_2346);
+
+	/* now setup anything below SYS and CSB and IPS */
+	clks[MPC512x_CLK_DDR_UG] = mpc512x_clk_factor("ddr-ug", "sys", 1, 2);
+	clks[MPC512x_CLK_SDHC_x4] = mpc512x_clk_factor("sdhc-x4", "csb", 4, 1);
+	clks[MPC512x_CLK_SDHC_UG] = mpc512x_clk_divider("sdhc-ug", "sdhc-x4", 0,
+							&clkregs->scfr2, 0, 8,
+							CLK_DIVIDER_ONE_BASED);
+	clks[MPC512x_CLK_DIU_x4] = mpc512x_clk_factor("diu-x4", "csb", 4, 1);
+	clks[MPC512x_CLK_DIU_UG] = mpc512x_clk_divider("diu-ug", "diu-x4", 0,
+						       &clkregs->scfr1, 0, 8,
+						       CLK_DIVIDER_ONE_BASED);
+
+	/*
+	 * the "power architecture PLL" was setup from data which was
+	 * sampled from the reset config word, at this point in time the
+	 * configuration can be considered fixed and read only (i.e. no
+	 * longer adjustable, or no longer in need of adjustment), which
+	 * is why we don't register a PLL here but assume fixed factors
+	 */
+	mul = get_cpmf_mult_x2();
+	div = 2;	/* compensate for the fractional factor */
+	clks[MPC512x_CLK_E300] = mpc512x_clk_factor("e300", "csb", mul, div);
+
+	clks[MPC512x_CLK_MBX_BUS_UG] = mpc512x_clk_factor("mbx-bus-ug", "csb",
+							  1, 2);
+	clks[MPC512x_CLK_MBX_UG] = mpc512x_clk_divtable("mbx-ug", "mbx-bus-ug",
+							&clkregs->scfr1, 14, 3,
+							divtab_1234);
+	clks[MPC512x_CLK_MBX_3D_UG] = mpc512x_clk_factor("mbx-3d-ug", "mbx-ug",
+							 1, 1);
+	clks[MPC512x_CLK_PCI_UG] = mpc512x_clk_divtable("pci-ug", "csb",
+							&clkregs->scfr1, 20, 3,
+							divtab_2346);
+	clks[MPC512x_CLK_NFC_UG] = mpc512x_clk_divtable("nfc-ug", "ips",
+							&clkregs->scfr1, 8, 3,
+							divtab_1234);
+	clks[MPC512x_CLK_LPC_UG] = mpc512x_clk_divtable("lpc-ug", "ips",
+							&clkregs->scfr1, 11, 3,
+							divtab_1234);
+
+	clks[MPC512x_CLK_LPC] = mpc512x_clk_gated("lpc", "lpc-ug",
+						  &clkregs->sccr1, 30);
+	clks[MPC512x_CLK_NFC] = mpc512x_clk_gated("nfc", "nfc-ug",
+						  &clkregs->sccr1, 29);
+	clks[MPC512x_CLK_PATA] = mpc512x_clk_gated("pata", "ips",
+						   &clkregs->sccr1, 28);
+	mpc512x_clk_setup_mclks(mclk_psc_data, ARRAY_SIZE(mclk_psc_data));
+	clks[MPC512x_CLK_PSC_FIFO] = mpc512x_clk_gated("psc-fifo", "ips",
+						       &clkregs->sccr1, 15);
+	clks[MPC512x_CLK_SATA] = mpc512x_clk_gated("sata", "ips",
+						   &clkregs->sccr1, 14);
+	clks[MPC512x_CLK_FEC] = mpc512x_clk_gated("fec", "ips",
+						  &clkregs->sccr1, 13);
+	clks[MPC512x_CLK_PCI] = mpc512x_clk_gated("pci", "pci-ug",
+						  &clkregs->sccr1, 11);
+	clks[MPC512x_CLK_DDR] = mpc512x_clk_gated("ddr", "ddr-ug",
+						  &clkregs->sccr1, 10);
+
+	clks[MPC512x_CLK_DIU] = mpc512x_clk_gated("diu", "diu-ug",
+						  &clkregs->sccr2, 31);
+	clks[MPC512x_CLK_AXE] = mpc512x_clk_gated("axe", "csb",
+						  &clkregs->sccr2, 30);
+	clks[MPC512x_CLK_MEM] = mpc512x_clk_gated("mem", "ips",
+						  &clkregs->sccr2, 29);
+	clks[MPC512x_CLK_USB1] = mpc512x_clk_gated("usb1", "csb",
+						   &clkregs->sccr2, 28);
+	clks[MPC512x_CLK_USB2] = mpc512x_clk_gated("usb2", "csb",
+						   &clkregs->sccr2, 27);
+	clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips",
+						  &clkregs->sccr2, 26);
+	mpc512x_clk_setup_mclks(mclk_mscan_data, ARRAY_SIZE(mclk_mscan_data));
+	clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug",
+						   &clkregs->sccr2, 24);
+	mpc512x_clk_setup_mclks(mclk_spdif_data, ARRAY_SIZE(mclk_spdif_data));
+	clks[MPC512x_CLK_MBX_BUS] = mpc512x_clk_gated("mbx-bus", "mbx-bus-ug",
+						      &clkregs->sccr2, 22);
+	clks[MPC512x_CLK_MBX] = mpc512x_clk_gated("mbx", "mbx-ug",
+						  &clkregs->sccr2, 21);
+	clks[MPC512x_CLK_MBX_3D] = mpc512x_clk_gated("mbx-3d", "mbx-3d-ug",
+						     &clkregs->sccr2, 20);
+	clks[MPC512x_CLK_IIM] = mpc512x_clk_gated("iim", "csb",
+						  &clkregs->sccr2, 19);
+	clks[MPC512x_CLK_VIU] = mpc512x_clk_gated("viu", "csb",
+						  &clkregs->sccr2, 18);
+	clks[MPC512x_CLK_SDHC_2] = mpc512x_clk_gated("sdhc-2", "sdhc-ug",
+						     &clkregs->sccr2, 17);
+
+	/*
+	 * externally provided clocks (when implemented in hardware,
+	 * device tree may specify values which otherwise were unknown)
+	 */
+	freq = get_freq_from_dt("psc_mclk_in");
+	if (!freq)
+		freq = 25000000;
+	clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq);
+	freq = get_freq_from_dt("spdif_tx_in");
+	clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_tx_in", freq);
+	freq = get_freq_from_dt("spdif_rx_in");
+	clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_rx_in", freq);
+
+	/* fixed frequency for AC97, always 24.567MHz */
+	clks[MPC512x_CLK_AC97] = mpc512x_clk_fixed("ac97", 24567000);
+
+	/* clkdev registration for compatibility reasons */
+	clk_register_clkdev(clks[MPC512x_CLK_REF], "ref_clk", NULL);
+	clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys_clk", NULL);
+	clk_register_clkdev(clks[MPC512x_CLK_VIU], "viu_clk", NULL);
+	clk_register_clkdev(clks[MPC512x_CLK_NFC], "nfc_clk", NULL);
+	clk_register_clkdev(clks[MPC512x_CLK_USB1], "usb1_clk", NULL);
+	clk_register_clkdev(clks[MPC512x_CLK_USB2], "usb2_clk", NULL);
+
+	pr_debug("clock tree setup complete\n");
+	freq = clk_get_rate(clks[MPC512x_CLK_E300]);
+	pr_debug("derived PPC freq [%d]\n", freq);
+	freq = clk_get_rate(clks[MPC512x_CLK_IPS]);
+	pr_debug("derived IPS freq [%d]\n", freq);
+	freq = clk_get_rate(clks[MPC512x_CLK_LPC]);
+	pr_debug("derived LPC freq [%d]\n", freq);
+
+	/* enable some of the clocks here unconditionally because ... */
+	pr_debug("automatically enabling some clocks\n");
+	/* some are essential yet never get claimed by any driver */
+	clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
+	clk_prepare_enable(clks[MPC512x_CLK_E300]);	/* PowerPC CPU */
+	clk_prepare_enable(clks[MPC512x_CLK_DDR]);	/* DRAM */
+	clk_prepare_enable(clks[MPC512x_CLK_MEM]);	/* SRAM */
+	clk_prepare_enable(clks[MPC512x_CLK_IPS]);	/* SoC periph */
+	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
+	/* some are required yet no dependencies were declared */
+	clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
+	/* some are not yet acquired by their respective drivers */
+	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
+	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
+	clk_prepare_enable(clks[MPC512x_CLK_DIU]);	/* display */
+	clk_prepare_enable(clks[MPC512x_CLK_I2C]);
+	/*
+	 * some have their individual clock subtree with separate clock
+	 * items and their individual enable counters, yet share a
+	 * common gate (refer to the same register location) while the
+	 * common clock driver code is not aware of the fact and the
+	 * platform's code doesn't provide specific support either
+	 *
+	 * what might happen is that e.g. enabling two MSCAN clock items
+	 * and disabling one of them will disable the common gate and
+	 * thus break the other MSCAN clock as well
+	 */
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN0_MCLK]);
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN1_MCLK]);
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN2_MCLK]);
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN3_MCLK]);
+}
+
+/*
+ * registers the set of public clocks (those listed in the dt-bindings/
+ * header file) for OF lookups, keeps the intermediates private to us
+ */
+static void mpc5121_clk_register_of_provider(struct device_node *np)
+{
+	clk_data.clks = clks;
+	clk_data.clk_num = MPC512x_CLK_LAST_PUBLIC + 1;	/* _not_ ARRAY_SIZE() */
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+int __init mpc5121_clk_init(void)
+{
+	struct device_node *clk_np;
+	int busfreq;
+
+	/* map the clock control registers */
+	clk_np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+	if (!clk_np)
+		return -ENODEV;
+	clkregs = of_iomap(clk_np, 0);
+	WARN_ON(!clkregs);
+
+	/* invalidate all not yet registered clock slots */
+	mpc512x_clk_preset_data();
+
+	/*
+	 * have the device tree scanned for "fixed-clock" nodes (which
+	 * includes the oscillator node if the board's DT provides one)
+	 */
+	of_clk_init(NULL);
+
+	/*
+	 * add a dummy clock for those situations where a clock spec is
+	 * required yet no real clock is involved
+	 */
+	clks[MPC512x_CLK_DUMMY] = mpc512x_clk_fixed("dummy", 0);
+
+	/*
+	 * have all the real nodes in the clock tree populated from REF
+	 * down to all leaves, either starting from the OSC node or from
+	 * a REF root that was created from the IPS bus clock input
+	 */
+	busfreq = get_freq_from_dt("bus-frequency");
+	mpc512x_clk_setup_clock_tree(busfreq);
+
+	/* register as an OF clock provider */
+	mpc5121_clk_register_of_provider(clk_np);
+
+	return 0;
+}
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index c4f7799..7f8fc64 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -497,6 +497,20 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
  * for improved portability across platforms
  */
 
+#if IS_ENABLED(CONFIG_PPC)
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+	return ioread32be(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+	iowrite32be(val, reg);
+}
+
+#else	/* platform dependent I/O accessors */
+
 static inline u32 clk_readl(u32 __iomem *reg)
 {
 	return readl(reg);
@@ -507,5 +521,7 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
 	writel(val, reg);
 }
 
+#endif	/* platform dependent I/O accessors */
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
-- 
1.7.10.4

[PATCH v3 18/31] dts: mpc512x: add clock specs for client lookups

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:45

this addresses the client side of device tree based clock lookups

add clock specifiers to the mbx, nfc, mscan, sdhc, i2c, axe, diu, viu,
mdio, fec, usb, pata, psc, psc fifo, and pci nodes in the shared
mpc5121.dtsi include

these specs map 'clock-names' encoded in drivers to their respective
'struct clk' items in the platform's clock driver

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/boot/dts/mpc5121.dtsi |   79 ++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
index 8f4cba0..3657ae6 100644
--- a/arch/powerpc/boot/dts/mpc5121.dtsi
+++ b/arch/powerpc/boot/dts/mpc5121.dtsi
@@ -51,6 +51,10 @@
 		compatible = "fsl,mpc5121-mbx";
 		reg = <0x20000000 0x4000>;
 		interrupts = <66 0x8>;
+		clocks = <&clks MPC512x_CLK_MBX_BUS>,
+			 <&clks MPC512x_CLK_MBX_3D>,
+			 <&clks MPC512x_CLK_MBX>;
+		clock-names = "mbx-bus", "mbx-3d", "mbx";
 	};
 
 	sram@30000000 {
@@ -64,6 +68,8 @@
 		interrupts = <6 8>;
 		#address-cells = <1>;
 		#size-cells = <1>;
+		clocks = <&clks MPC512x_CLK_NFC>;
+		clock-names = "per";
 	};
 
 	localbus@80000020 {
@@ -153,12 +159,22 @@
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x1300 0x80>;
 			interrupts = <12 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN0_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		can@1380 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x1380 0x80>;
 			interrupts = <13 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN1_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		sdhc@1500 {
@@ -167,6 +183,9 @@
 			interrupts = <8 0x8>;
 			dmas = <&dma0 30>;
 			dma-names = "rx-tx";
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SDHC>;
+			clock-names = "ipg", "per";
 		};
 
 		i2c@1700 {
@@ -175,6 +194,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1700 0x20>;
 			interrupts = <9 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2c@1720 {
@@ -183,6 +204,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1720 0x20>;
 			interrupts = <10 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2c@1740 {
@@ -191,6 +214,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1740 0x20>;
 			interrupts = <11 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2ccontrol@1760 {
@@ -202,30 +227,46 @@
 			compatible = "fsl,mpc5121-axe";
 			reg = <0x2000 0x100>;
 			interrupts = <42 0x8>;
+			clocks = <&clks MPC512x_CLK_AXE>;
+			clock-names = "per";
 		};
 
 		display@2100 {
 			compatible = "fsl,mpc5121-diu";
 			reg = <0x2100 0x100>;
 			interrupts = <64 0x8>;
+			clocks = <&clks MPC512x_CLK_DIU>;
+			clock-names = "per";
 		};
 
 		can@2300 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x2300 0x80>;
 			interrupts = <90 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN2_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		can@2380 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x2380 0x80>;
 			interrupts = <91 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN3_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		viu@2400 {
 			compatible = "fsl,mpc5121-viu";
 			reg = <0x2400 0x400>;
 			interrupts = <67 0x8>;
+			clocks = <&clks MPC512x_CLK_VIU>;
+			clock-names = "per";
 		};
 
 		mdio@2800 {
@@ -233,6 +274,8 @@
 			reg = <0x2800 0x800>;
 			#address-cells = <1>;
 			#size-cells = <0>;
+			clocks = <&clks MPC512x_CLK_FEC>;
+			clock-names = "per";
 		};
 
 		eth0: ethernet@2800 {
@@ -241,6 +284,8 @@
 			reg = <0x2800 0x800>;
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <4 0x8>;
+			clocks = <&clks MPC512x_CLK_FEC>;
+			clock-names = "per";
 		};
 
 		/* USB1 using external ULPI PHY */
@@ -252,6 +297,8 @@
 			interrupts = <43 0x8>;
 			dr_mode = "otg";
 			phy_type = "ulpi";
+			clocks = <&clks MPC512x_CLK_USB1>;
+			clock-names = "per";
 		};
 
 		/* USB0 using internal UTMI PHY */
@@ -263,6 +310,8 @@
 			interrupts = <44 0x8>;
 			dr_mode = "otg";
 			phy_type = "utmi_wide";
+			clocks = <&clks MPC512x_CLK_USB2>;
+			clock-names = "per";
 		};
 
 		/* IO control */
@@ -281,6 +330,8 @@
 			compatible = "fsl,mpc5121-pata";
 			reg = <0x10200 0x100>;
 			interrupts = <5 0x8>;
+			clocks = <&clks MPC512x_CLK_PATA>;
+			clock-names = "per";
 		};
 
 		/* 512x PSCs are not 52xx PSC compatible */
@@ -292,6 +343,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC0_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC1 */
@@ -301,6 +354,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC1_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC2 */
@@ -310,6 +365,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC2_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC3 */
@@ -319,6 +376,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC3_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC4 */
@@ -328,6 +387,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC4_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC5 */
@@ -337,6 +398,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC5_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC6 */
@@ -346,6 +409,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC6_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC7 */
@@ -355,6 +420,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC7_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC8 */
@@ -364,6 +431,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC8_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC9 */
@@ -373,6 +442,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC9_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC10 */
@@ -382,6 +453,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC10_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC11 */
@@ -391,12 +464,16 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC11_MCLK>;
+			clock-names = "mclk";
 		};
 
 		pscfifo@11f00 {
 			compatible = "fsl,mpc5121-psc-fifo";
 			reg = <0x11f00 0x100>;
 			interrupts = <40 0x8>;
+			clocks = <&clks MPC512x_CLK_PSC_FIFO>;
+			clock-names = "per";
 		};
 
 		dma0: dma@14000 {
@@ -414,6 +491,8 @@
 		#address-cells = <3>;
 		#size-cells = <2>;
 		#interrupt-cells = <1>;
+		clocks = <&clks MPC512x_CLK_PCI>;
+		clock-names = "per";
 
 		reg = <0x80008500 0x100	/* internal registers */
 		       0x80008300 0x8>;	/* config space access registers */
-- 
1.7.10.4

[PATCH v3 19/31] clk: mpc512x: don't pre-enable FEC and I2C clocks

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:46

after the device tree nodes provide clock specs for client side lookups,
peripheral drivers can attach to their clocks and the clock driver need
no longer pre-enable those clock items

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/clock-commonclk.c |    2 --
 1 file changed, 2 deletions(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index 762ee85..8b71ceb 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -713,9 +713,7 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
-	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
 	clk_prepare_enable(clks[MPC512x_CLK_DIU]);	/* display */
-	clk_prepare_enable(clks[MPC512x_CLK_I2C]);
 	/*
 	 * some have their individual clock subtree with separate clock
 	 * items and their individual enable counters, yet share a
-- 
1.7.10.4

[PATCH v3 20/31] spi: mpc512x: remove now obsolete clock lookup name

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:47

after device tree based clock lookup became available, the peripheral
driver need no longer construct clock names which include the PSC index,
remove the "psc%d_mclk" template and unconditionally use "mclk"

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/spi/spi-mpc512x-psc.c |    6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 823e5e0..1a4a983 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -474,8 +474,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 	struct spi_master *master;
 	int ret;
 	void *tempp;
-	int psc_num;
-	char clk_name[16];
 	struct clk *clk;
 
 	master = spi_alloc_master(dev, sizeof *mps);
@@ -519,9 +517,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 		goto free_master;
 	init_completion(&mps->txisrdone);
 
-	psc_num = master->bus_num;
-	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-	clk = devm_clk_get(dev, clk_name);
+	clk = devm_clk_get(dev, "mclk");
 	if (IS_ERR(clk))
 		goto free_irq;
 	ret = clk_prepare_enable(clk);
-- 
1.7.10.4

[PATCH v3 21/31] serial: mpc512x: remove now obsolete clock lookup name

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:48

after device tree based clock lookup became available, the peripheral
driver need no longer construct clock names which include the PSC index,
remove the "psc%d_mclk" template and unconditionally use "mclk"

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/tty/serial/mpc52xx_uart.c |    8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 8f16ed9..04dc564 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -623,14 +623,11 @@ static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM];
 /* called from within the .request_port() callback (allocation) */
 static int mpc512x_psc_alloc_clock(struct uart_port *port)
 {
-	int psc_num;
-	char clk_name[16];
 	struct clk *clk;
 	int err;
+	int psc_num;
 
-	psc_num = (port->mapbase & 0xf00) >> 8;
-	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-	clk = devm_clk_get(port->dev, clk_name);
+	clk = devm_clk_get(port->dev, "mclk");
 	if (IS_ERR(clk)) {
 		dev_err(port->dev, "Failed to get MCLK!\n");
 		return PTR_ERR(clk);
@@ -641,6 +638,7 @@ static int mpc512x_psc_alloc_clock(struct uart_port *port)
 		devm_clk_put(port->dev, clk);
 		return err;
 	}
+	psc_num = (port->mapbase & 0xf00) >> 8;
 	psc_mclk_clk[psc_num] = clk;
 	return 0;
 }
-- 
1.7.10.4

[PATCH v3 22/31] clk: mpc512x: remove clkdev registration (uart, spi)

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:49

after the UART and SPI peripheral drivers have switched to device tree
based clock lookup and no longer construct clock names from their PSC
component index, the "psc%d_mclk" alias names have become obsolete --
remove the corresponding clk_register_clkdev() calls

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/clock-commonclk.c |   11 -----------
 1 file changed, 11 deletions(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index 8b71ceb..a860ded 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -529,17 +529,6 @@ static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
 				entry->name_mclk,
 				entry->name_mux1, 1, 1);
 	}
-
-	/*
-	 * without this "clock device" registration, "simple" lookups in
-	 * the SPI master initialization and serial port setup will fail
-	 *
-	 * those drivers need to get adjusted to lookup their required
-	 * clocks from device tree specs, and device tree nodes need to
-	 * provide the clock specs, before this clkdev registration
-	 * becomes obsolete
-	 */
-	clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
 }
 
 static void mpc512x_clk_setup_mclks(struct mclk_setup_data *table, size_t count)
-- 
1.7.10.4

[PATCH v3 23/31] serial: mpc512x: setup the PSC FIFO clock as well

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:50

prepare and enable the FIFO clock upon PSC FIFO initialization,
check for and propagage errors when enabling the PSC FIFO clock,
disable and unprepare the FIFO clock upon PSC FIFO uninitialization,
remove the pre-enable workaround from the platform's clock driver

devm_{get,put}_clk() doesn't apply here, as the SoC provides a
single FIFO component which is shared among several PSC components,
thus the FIFO isn't associated with a device (while the PSCs are)

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/clock-commonclk.c |    2 --
 drivers/tty/serial/mpc52xx_uart.c             |   46 +++++++++++++++++++++----
 2 files changed, 40 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index a860ded..53f772b 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -698,8 +698,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	clk_prepare_enable(clks[MPC512x_CLK_MEM]);	/* SRAM */
 	clk_prepare_enable(clks[MPC512x_CLK_IPS]);	/* SoC periph */
 	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
-	/* some are required yet no dependencies were declared */
-	clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
 	clk_prepare_enable(clks[MPC512x_CLK_DIU]);	/* display */
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 04dc564..23eef91 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -421,6 +421,7 @@ struct psc_fifoc {
 
 static struct psc_fifoc __iomem *psc_fifoc;
 static unsigned int psc_fifoc_irq;
+static struct clk *psc_fifoc_clk;
 
 static void mpc512x_psc_fifo_init(struct uart_port *port)
 {
@@ -568,36 +569,69 @@ static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,
 /* Init PSC FIFO Controller */
 static int __init mpc512x_psc_fifoc_init(void)
 {
+	int err;
 	struct device_node *np;
+	struct clk *clk;
+
+	/* default error code, potentially overwritten by clock calls */
+	err = -ENODEV;
 
 	np = of_find_compatible_node(NULL, NULL,
 				     "fsl,mpc5121-psc-fifo");
 	if (!np) {
 		pr_err("%s: Can't find FIFOC node\n", __func__);
-		return -ENODEV;
+		goto out_err;
 	}
 
+	clk = of_clk_get_by_name(np, "per");
+	if (IS_ERR(clk)) {
+		pr_err("%s: Can't lookup FIFO clock\n", __func__);
+		err = PTR_ERR(clk);
+		goto out_ofnode_put;
+	}
+	if (clk_prepare_enable(clk)) {
+		pr_err("%s: Can't enable FIFO clock\n", __func__);
+		clk_put(clk);
+		goto out_ofnode_put;
+	}
+	psc_fifoc_clk = clk;
+
 	psc_fifoc = of_iomap(np, 0);
 	if (!psc_fifoc) {
 		pr_err("%s: Can't map FIFOC\n", __func__);
-		of_node_put(np);
-		return -ENODEV;
+		goto out_clk_disable;
 	}
 
 	psc_fifoc_irq = irq_of_parse_and_map(np, 0);
-	of_node_put(np);
 	if (psc_fifoc_irq == 0) {
 		pr_err("%s: Can't get FIFOC irq\n", __func__);
-		iounmap(psc_fifoc);
-		return -ENODEV;
+		goto out_unmap;
 	}
 
+	of_node_put(np);
 	return 0;
+
+out_unmap:
+	iounmap(psc_fifoc);
+out_clk_disable:
+	clk_disable_unprepare(psc_fifoc_clk);
+	clk_put(psc_fifoc_clk);
+out_ofnode_put:
+	of_node_put(np);
+out_err:
+	return err;
 }
 
 static void __exit mpc512x_psc_fifoc_uninit(void)
 {
 	iounmap(psc_fifoc);
+
+	/* disable the clock, errors are not fatal */
+	if (psc_fifoc_clk) {
+		clk_disable_unprepare(psc_fifoc_clk);
+		clk_put(psc_fifoc_clk);
+		psc_fifoc_clk = NULL;
+	}
 }
 
 /* 512x specific interrupt handler. The caller holds the port lock */
-- 
1.7.10.4

[PATCH v3 24/31] USB: fsl-mph-dr-of: remove now obsolete clock lookup name

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:51

after device tree based clock lookup became available, the peripheral
driver need no longer construct clock names which include the component
index -- remove the "usb%d_clk" template and unconditionally use "per",
remove the clock driver's clkdev registration

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/clock-commonclk.c |    2 --
 drivers/usb/host/fsl-mph-dr-of.c              |   13 +------------
 2 files changed, 1 insertion(+), 14 deletions(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index 53f772b..d0286a5 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -678,8 +678,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys_clk", NULL);
 	clk_register_clkdev(clks[MPC512x_CLK_VIU], "viu_clk", NULL);
 	clk_register_clkdev(clks[MPC512x_CLK_NFC], "nfc_clk", NULL);
-	clk_register_clkdev(clks[MPC512x_CLK_USB1], "usb1_clk", NULL);
-	clk_register_clkdev(clks[MPC512x_CLK_USB2], "usb2_clk", NULL);
 
 	pr_debug("clock tree setup complete\n");
 	freq = clk_get_rate(clks[MPC512x_CLK_E300]);
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 5e51384..49c1da8 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -261,19 +261,8 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 	struct clk *clk;
 	int err;
-	char clk_name[10];
-	int base, clk_num;
-
-	base = pdev->resource->start & 0xf000;
-	if (base == 0x3000)
-		clk_num = 1;
-	else if (base == 0x4000)
-		clk_num = 2;
-	else
-		return -ENODEV;
 
-	snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num);
-	clk = devm_clk_get(&pdev->dev, clk_name);
+	clk = devm_clk_get(&pdev->dev, "per");
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "failed to get clk\n");
 		return PTR_ERR(clk);
-- 
1.7.10.4

[PATCH v3 25/31] mtd: mpc5121_nfc: remove now obsolete clock lookup name

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:52

after device tree based clock lookup became available, the NAND flash
driver need no longer use the previous "nfc_clk" name but can switch to
the fixed "per" clock name -- adjust the peripheral driver and remove
the clock driver's clkdev registration

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/clock-commonclk.c |    1 -
 drivers/mtd/nand/mpc5121_nfc.c                |    2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index d0286a5..24e1706 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -677,7 +677,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	clk_register_clkdev(clks[MPC512x_CLK_REF], "ref_clk", NULL);
 	clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys_clk", NULL);
 	clk_register_clkdev(clks[MPC512x_CLK_VIU], "viu_clk", NULL);
-	clk_register_clkdev(clks[MPC512x_CLK_NFC], "nfc_clk", NULL);
 
 	pr_debug("clock tree setup complete\n");
 	freq = clk_get_rate(clks[MPC512x_CLK_E300]);
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
index 9c0b8fe..6a5f851 100644
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -731,7 +731,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
 	of_node_put(rootnode);
 
 	/* Enable NFC clock */
-	clk = devm_clk_get(dev, "nfc_clk");
+	clk = devm_clk_get(dev, "per");
 	if (IS_ERR(clk)) {
 		dev_err(dev, "Unable to acquire NFC clock!\n");
 		retval = PTR_ERR(clk);
-- 
1.7.10.4

[PATCH v3 26/31] [media] fsl-viu: remove now obsolete clock lookup name

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:53

after device tree based clock lookup became available, the VIU driver
need no longer use the previous "viu_clk" name but can switch to the
fixed "per" clock name -- adjust the peripheral driver and remove the
clock driver's clkdev registration

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/clock-commonclk.c |    1 -
 drivers/media/platform/fsl-viu.c              |    2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index 24e1706..f047d4c 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -676,7 +676,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	/* clkdev registration for compatibility reasons */
 	clk_register_clkdev(clks[MPC512x_CLK_REF], "ref_clk", NULL);
 	clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys_clk", NULL);
-	clk_register_clkdev(clks[MPC512x_CLK_VIU], "viu_clk", NULL);
 
 	pr_debug("clock tree setup complete\n");
 	freq = clk_get_rate(clks[MPC512x_CLK_E300]);
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
index 48fced4..8a17433 100644
--- a/drivers/media/platform/fsl-viu.c
+++ b/drivers/media/platform/fsl-viu.c
@@ -1578,7 +1578,7 @@ static int viu_of_probe(struct platform_device *op)
 	}
 
 	/* enable VIU clock */
-	clk = devm_clk_get(&op->dev, "viu_clk");
+	clk = devm_clk_get(&op->dev, "per");
 	if (IS_ERR(clk)) {
 		dev_err(&op->dev, "failed to lookup the clock!\n");
 		ret = PTR_ERR(clk);
-- 
1.7.10.4

[PATCH v3 27/31] net: can: mscan: add common clock support for mpc512x

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:54

implement a .get_clock() callback for the MPC512x platform which uses
the common clock infrastructure (eliminating direct access to the clock
control registers from within the CAN network driver), and provide the
corresponding .put_clock() callback to release resources after use

keep the previous implementation of MPC512x support in place during
migration, since common clock support is optional

this change is neutral to the MPC5200 platform

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/net/can/mscan/mpc5xxx_can.c |  169 +++++++++++++++++++++++++++++++++++
 1 file changed, 169 insertions(+)
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index e59b3a3..4897929 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -109,6 +109,167 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
+
+#if IS_ENABLED(CONFIG_COMMON_CLK)
+
+static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
+				 const char *clock_source, int *mscan_clksrc)
+{
+	struct device_node *np;
+	u32 clockdiv;
+	enum {
+		CLK_FROM_AUTO,
+		CLK_FROM_IPS,
+		CLK_FROM_SYS,
+		CLK_FROM_REF,
+	} clk_from;
+	struct clk *clk_in, *clk_can;
+	unsigned long freq_calc;
+	struct mscan_priv *priv;
+
+	/* the caller passed in the clock source spec that was read from
+	 * the device tree, get the optional clock divider as well
+	 */
+	np = ofdev->dev.of_node;
+	clockdiv = 1;
+	of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
+	dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
+		clock_source ? clock_source : "<NULL>", clockdiv);
+
+	/* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
+	 * get set, and the 'ips' clock is the input to the MSCAN
+	 * component
+	 *
+	 * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
+	 * bit needs to get cleared, an optional clock-divider may have
+	 * been specified (the default value is 1), the appropriate
+	 * MSCAN related MCLK is the input to the MSCAN component
+	 *
+	 * in the absence of a clock-source spec, first an optimal clock
+	 * gets determined based on the 'sys' clock, if that fails the
+	 * 'ref' clock is used
+	 */
+	clk_from = CLK_FROM_AUTO;
+	if (clock_source) {
+		/* interpret the device tree's spec for the clock source */
+		if (!strcmp(clock_source, "ip"))
+			clk_from = CLK_FROM_IPS;
+		else if (!strcmp(clock_source, "sys"))
+			clk_from = CLK_FROM_SYS;
+		else if (!strcmp(clock_source, "ref"))
+			clk_from = CLK_FROM_REF;
+		else
+			goto err_invalid;
+		dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, try the 'sys' clock; round to the
+		 * next MHz and see if we can get a multiple of 16MHz
+		 */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
+		clk_in = devm_clk_get(&ofdev->dev, "sys");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc +=  499999;
+		freq_calc /= 1000000;
+		freq_calc *= 1000000;
+		if ((freq_calc % 16000000) == 0) {
+			clk_from = CLK_FROM_SYS;
+			clockdiv = freq_calc / 16000000;
+			dev_dbg(&ofdev->dev,
+				"clk fit, sys[%lu] div[%d] freq[%lu]\n",
+				freq_calc, clockdiv, freq_calc / clockdiv);
+		}
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, use the 'ref' clock */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
+		clk_in = devm_clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_from = CLK_FROM_REF;
+		freq_calc = clk_get_rate(clk_in);
+		dev_dbg(&ofdev->dev,
+			"clk fit, ref[%lu] (no div) freq[%lu]\n",
+			freq_calc, freq_calc);
+	}
+
+	/* select IPS or MCLK as the MSCAN input (returned to the caller),
+	 * setup the MCLK mux source and rate if applicable, apply the
+	 * optionally specified or derived above divider, and determine
+	 * the actual resulting clock rate to return to the caller
+	 */
+	switch (clk_from) {
+	case CLK_FROM_IPS:
+		clk_can = devm_clk_get(&ofdev->dev, "ips");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		if (clk_prepare(clk_can)) {
+			devm_clk_put(&ofdev->dev, clk_can);
+			goto err_notavail;
+		}
+		priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+		priv->clk_can = clk_can;
+		freq_calc = clk_get_rate(clk_can);
+		*mscan_clksrc = MSCAN_CLKSRC_IPS;
+		dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
+			*mscan_clksrc, freq_calc);
+		break;
+	case CLK_FROM_SYS:
+	case CLK_FROM_REF:
+		clk_can = devm_clk_get(&ofdev->dev, "mclk");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		if (clk_prepare(clk_can)) {
+			devm_clk_put(&ofdev->dev, clk_can);
+			goto err_notavail;
+		}
+		priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+		priv->clk_can = clk_can;
+		if (clk_from == CLK_FROM_SYS)
+			clk_in = devm_clk_get(&ofdev->dev, "sys");
+		if (clk_from == CLK_FROM_REF)
+			clk_in = devm_clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_set_parent(clk_can, clk_in);
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc /= clockdiv;
+		clk_set_rate(clk_can, freq_calc);
+		freq_calc = clk_get_rate(clk_can);
+		*mscan_clksrc = MSCAN_CLKSRC_BUS;
+		dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n",
+			*mscan_clksrc, freq_calc);
+		break;
+	default:
+		goto err_invalid;
+	}
+
+	return freq_calc;
+
+err_invalid:
+	dev_err(&ofdev->dev, "invalid clock source specification\n");
+	return 0;
+
+err_notavail:
+	dev_err(&ofdev->dev, "cannot acquire or setup clock source\n");
+	return 0;
+}
+
+static void mpc512x_can_put_clock(struct platform_device *ofdev)
+{
+	struct mscan_priv *priv;
+
+	priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+	if (priv->clk_can) {
+		clk_unprepare(priv->clk_can);
+		devm_clk_put(&ofdev->dev, priv->clk_can);
+	}
+}
+
+#else	/* COMMON_CLK */
+
 struct mpc512x_clockctl {
 	u32 spmr;		/* System PLL Mode Reg */
 	u32 sccr[2];		/* System Clk Ctrl Reg 1 & 2 */
@@ -239,12 +400,18 @@ exit_put:
 	of_node_put(np_clock);
 	return freq;
 }
+
+#define mpc512x_can_put_clock NULL
+
+#endif	/* COMMON_CLK */
+
 #else /* !CONFIG_PPC_MPC512x */
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_name, int *mscan_clksrc)
 {
 	return 0;
 }
+#define mpc512x_can_put_clock NULL
 #endif /* CONFIG_PPC_MPC512x */
 
 static const struct of_device_id mpc5xxx_can_table[];
@@ -386,11 +553,13 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev)
 static const struct mpc5xxx_can_data mpc5200_can_data = {
 	.type = MSCAN_TYPE_MPC5200,
 	.get_clock = mpc52xx_can_get_clock,
+	/* .put_clock not applicable */
 };
 
 static const struct mpc5xxx_can_data mpc5121_can_data = {
 	.type = MSCAN_TYPE_MPC5121,
 	.get_clock = mpc512x_can_get_clock,
+	.put_clock = mpc512x_can_put_clock,
 };
 
 static const struct of_device_id mpc5xxx_can_table[] = {
-- 
1.7.10.4

[PATCH v3 28/31] powerpc/mpc512x: improve DIU related clock setup

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:55

adapt the DIU clock initialization to the COMMON_CLK approach: device
tree based clock lookup, prepare and unprepare for clocks, work with
frequencies not dividers, call the appropriate clk_*() routines and
don't access CCM registers, remove the pre-enable workaround in the
platform's clock driver

the "best clock" determination now completely relies on the platform's
clock driver to pick a frequency close to what the caller requests, and
merely checks whether the desired frequency was met (is acceptable since
it meets the tolerance of the monitor) -- this approach shall succeed
upon first try in the usual case, will test a few less desirable yet
acceptable frequencies in edge cases, and will fallback to "best effort"
if none of the previously tried frequencies pass the test

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/clock-commonclk.c |    1 -
 arch/powerpc/platforms/512x/mpc512x_shared.c  |  165 +++++++++++++------------
 2 files changed, 88 insertions(+), 78 deletions(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index f047d4c..893fbe5 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -696,7 +696,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
-	clk_prepare_enable(clks[MPC512x_CLK_DIU]);	/* display */
 	/*
 	 * some have their individual clock subtree with separate clock
 	 * items and their individual enable counters, yet share a
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index a82a41b..3381eea 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -12,6 +12,7 @@
  * (at your option) any later version.
  */
 
+#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -70,98 +71,108 @@ struct fsl_diu_shared_fb {
 	bool		in_use;
 };
 
-#define DIU_DIV_MASK	0x000000ff
+/* receives a pixel clock spec in pico seconds, adjusts the DIU clock rate */
 void mpc512x_set_pixel_clock(unsigned int pixclock)
 {
-	unsigned long bestval, bestfreq, speed, busfreq;
-	unsigned long minpixclock, maxpixclock, pixval;
-	struct mpc512x_ccm __iomem *ccm;
 	struct device_node *np;
-	u32 temp;
-	long err;
-	int i;
+	struct clk *clk_diu;
+	unsigned long epsilon, minpixclock, maxpixclock;
+	unsigned long offset, want, got, delta;
 
-	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+	/* lookup and enable the DIU clock */
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu");
 	if (!np) {
-		pr_err("Can't find clock control module.\n");
+		pr_err("Could not find DIU device tree node.\n");
 		return;
 	}
-
-	ccm = of_iomap(np, 0);
+	clk_diu = of_clk_get_by_name(np, "per");
 	of_node_put(np);
-	if (!ccm) {
-		pr_err("Can't map clock control module reg.\n");
+	if (IS_ERR(clk_diu)) {
+		pr_err("Could not lookup DIU clock.\n");
 		return;
 	}
-
-	np = of_find_node_by_type(NULL, "cpu");
-	if (np) {
-		const unsigned int *prop =
-			of_get_property(np, "bus-frequency", NULL);
-
-		of_node_put(np);
-		if (prop) {
-			busfreq = *prop;
-		} else {
-			pr_err("Can't get bus-frequency property\n");
-			return;
-		}
-	} else {
-		pr_err("Can't find 'cpu' node.\n");
+	if (clk_prepare_enable(clk_diu)) {
+		pr_err("Could not enable DIU clock.\n");
 		return;
 	}
 
-	/* Pixel Clock configuration */
-	pr_debug("DIU: Bus Frequency = %lu\n", busfreq);
-	speed = busfreq * 4; /* DIU_DIV ratio is 4 * CSB_CLK / DIU_CLK */
-
-	/* Calculate the pixel clock with the smallest error */
-	/* calculate the following in steps to avoid overflow */
-	pr_debug("DIU pixclock in ps - %d\n", pixclock);
-	temp = (1000000000 / pixclock) * 1000;
-	pixclock = temp;
-	pr_debug("DIU pixclock freq - %u\n", pixclock);
-
-	temp = temp / 20; /* pixclock * 0.05 */
-	pr_debug("deviation = %d\n", temp);
-	minpixclock = pixclock - temp;
-	maxpixclock = pixclock + temp;
-	pr_debug("DIU minpixclock - %lu\n", minpixclock);
-	pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
-	pixval = speed/pixclock;
-	pr_debug("DIU pixval = %lu\n", pixval);
-
-	err = LONG_MAX;
-	bestval = pixval;
-	pr_debug("DIU bestval = %lu\n", bestval);
-
-	bestfreq = 0;
-	for (i = -1; i <= 1; i++) {
-		temp = speed / (pixval+i);
-		pr_debug("DIU test pixval i=%d, pixval=%lu, temp freq. = %u\n",
-			i, pixval, temp);
-		if ((temp < minpixclock) || (temp > maxpixclock))
-			pr_debug("DIU exceeds monitor range (%lu to %lu)\n",
-				minpixclock, maxpixclock);
-		else if (abs(temp - pixclock) < err) {
-			pr_debug("Entered the else if block %d\n", i);
-			err = abs(temp - pixclock);
-			bestval = pixval + i;
-			bestfreq = temp;
-		}
+	/*
+	 * convert the picoseconds spec into the desired clock rate,
+	 * determine the acceptable clock range for the monitor (+/- 5%),
+	 * do the calculation in steps to avoid integer overflow
+	 */
+	pr_debug("DIU pixclock in ps - %u\n", pixclock);
+	pixclock = (1000000000 / pixclock) * 1000;
+	pr_debug("DIU pixclock freq  - %u\n", pixclock);
+	epsilon = pixclock / 20; /* pixclock * 0.05 */
+	pr_debug("DIU deviation      - %lu\n", epsilon);
+	minpixclock = pixclock - epsilon;
+	maxpixclock = pixclock + epsilon;
+	pr_debug("DIU minpixclock    - %lu\n", minpixclock);
+	pr_debug("DIU maxpixclock    - %lu\n", maxpixclock);
+
+	/*
+	 * check whether the DIU supports the desired pixel clock
+	 *
+	 * - simply request the desired clock and see what the
+	 *   platform's clock driver will make of it, assuming that it
+	 *   will setup the best approximation of the requested value
+	 * - try other candidate frequencies in the order of decreasing
+	 *   preference (i.e. with increasing distance from the desired
+	 *   pixel clock, and checking the lower frequency before the
+	 *   higher frequency to not overload the hardware) until the
+	 *   first match is found -- any potential subsequent match
+	 *   would only be as good as the former match or typically
+	 *   would be less preferrable
+	 *
+	 * the offset increment of pixelclock divided by 64 is an
+	 * arbitrary choice -- it's simple to calculate, in the typical
+	 * case we expect the first check to succeed already, in the
+	 * worst case seven frequencies get tested (the exact center and
+	 * three more values each to the left and to the right) before
+	 * the 5% tolerance window is exceeded, resulting in fast enough
+	 * execution yet high enough probability of finding a suitable
+	 * value, while the error rate will be in the order of single
+	 * percents
+	 */
+	for (offset = 0; offset <= epsilon; offset += pixclock / 64) {
+		want = pixclock - offset;
+		pr_debug("DIU checking clock - %lu\n", want);
+		clk_set_rate(clk_diu, want);
+		got = clk_get_rate(clk_diu);
+		delta = abs(pixclock - got);
+		if (delta < epsilon)
+			break;
+		if (!offset)
+			continue;
+		want = pixclock + offset;
+		pr_debug("DIU checking clock - %lu\n", want);
+		clk_set_rate(clk_diu, want);
+		got = clk_get_rate(clk_diu);
+		delta = abs(pixclock - got);
+		if (delta < epsilon)
+			break;
 	}
+	if (offset <= epsilon) {
+		pr_debug("DIU clock accepted - %lu\n", want);
+		pr_debug("DIU pixclock want %u, got %lu, delta %lu, eps %lu\n",
+			 pixclock, got, delta, epsilon);
+		return;
+	}
+	pr_warn("DIU pixclock auto search unsuccessful\n");
 
-	pr_debug("DIU chose = %lx\n", bestval);
-	pr_debug("DIU error = %ld\n NomPixClk ", err);
-	pr_debug("DIU: Best Freq = %lx\n", bestfreq);
-	/* Modify DIU_DIV in CCM SCFR1 */
-	temp = in_be32(&ccm->scfr1);
-	pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp);
-	temp &= ~DIU_DIV_MASK;
-	temp |= (bestval & DIU_DIV_MASK);
-	out_be32(&ccm->scfr1, temp);
-	pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp);
-	iounmap(ccm);
+	/*
+	 * what is the most appropriate action to take when the search
+	 * for an available pixel clock which is acceptable to the
+	 * monitor has failed?  disable the DIU (clock) or just provide
+	 * a "best effort"?  we go with the latter
+	 */
+	pr_warn("DIU pixclock best effort fallback (backend's choice)\n");
+	clk_set_rate(clk_diu, pixclock);
+	got = clk_get_rate(clk_diu);
+	delta = abs(pixclock - got);
+	pr_debug("DIU pixclock want %u, got %lu, delta %lu, eps %lu\n",
+		 pixclock, got, delta, epsilon);
 }
 
 enum fsl_diu_monitor_port
-- 
1.7.10.4

[PATCH v3 29/31] clk: mpc512x: switch to COMMON_CLK, remove PPC_CLOCK

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:56

completely switch to, i.e. unconditionally use COMMON_CLK for the
MPC512x platform, and retire the PPC_CLOCK implementation for that
platform after the transition has completed

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/Kconfig  |   14 +-
 arch/powerpc/platforms/512x/Makefile |    3 +-
 arch/powerpc/platforms/512x/clock.c  |  753 ----------------------------------
 3 files changed, 2 insertions(+), 768 deletions(-)
 delete mode 100644 arch/powerpc/platforms/512x/clock.c
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index c5fcdd0..5aa3f4b 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -1,21 +1,9 @@
-config MPC512x_COMMON_CLK
-	bool "MPC512x platform uses COMMON_CLK"
-	default y
-	depends on PPC_MPC512x
-	help
-	  This option is only here to support tests and comparison
-	  during development and migration.  This option will get
-	  removed after the COMMON_CLK support for MPC512x has become
-	  fully operational and all drivers were adjusted to explicitly
-	  acquire their required clocks.
-
 config PPC_MPC512x
 	bool "512x-based boards"
 	depends on 6xx
+	select COMMON_CLK
 	select FSL_SOC
 	select IPIC
-	select PPC_CLOCK if !MPC512x_COMMON_CLK
-	select COMMON_CLK if MPC512x_COMMON_CLK
 	select PPC_PCI_CHOICE
 	select FSL_PCI if PCI
 	select ARCH_WANT_OPTIONAL_GPIOLIB
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
index 1e05f9d..bb20116 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -1,8 +1,7 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-$(CONFIG_PPC_CLOCK)		+= clock.o
-obj-$(CONFIG_COMMON_CLK)	+= clock-commonclk.o
+obj-y				+= clock-commonclk.o
 obj-y				+= mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)	+= mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)	+= mpc512x_generic.o
diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c
deleted file mode 100644
index e504166..0000000
--- a/arch/powerpc/platforms/512x/clock.c
+++ /dev/null
@@ -1,753 +0,0 @@
-/*
- * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: John Rigby <jrigby@freescale.com>
- *
- * Implements the clk api defined in include/linux/clk.h
- *
- *    Original based on linux/arch/arm/mach-integrator/clock.c
- *
- *    Copyright (C) 2004 ARM Limited.
- *    Written by Deep Blue Solutions Limited.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/io.h>
-
-#include <linux/of_platform.h>
-#include <asm/mpc5xxx.h>
-#include <asm/mpc5121.h>
-#include <asm/clk_interface.h>
-
-#include "mpc512x.h"
-
-#undef CLK_DEBUG
-
-static int clocks_initialized;
-
-#define CLK_HAS_RATE	0x1	/* has rate in MHz */
-#define CLK_HAS_CTRL	0x2	/* has control reg and bit */
-
-struct clk {
-	struct list_head node;
-	char name[32];
-	int flags;
-	struct device *dev;
-	unsigned long rate;
-	struct module *owner;
-	void (*calc) (struct clk *);
-	struct clk *parent;
-	int reg, bit;		/* CLK_HAS_CTRL */
-	int div_shift;		/* only used by generic_div_clk_calc */
-};
-
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
-
-static struct clk *mpc5121_clk_get(struct device *dev, const char *id)
-{
-	struct clk *p, *clk = ERR_PTR(-ENOENT);
-	int dev_match;
-	int id_match;
-
-	if (dev == NULL || id == NULL)
-		return clk;
-
-	mutex_lock(&clocks_mutex);
-	list_for_each_entry(p, &clocks, node) {
-		dev_match = id_match = 0;
-
-		if (dev == p->dev)
-			dev_match++;
-		if (strcmp(id, p->name) == 0)
-			id_match++;
-		if ((dev_match || id_match) && try_module_get(p->owner)) {
-			clk = p;
-			break;
-		}
-	}
-	mutex_unlock(&clocks_mutex);
-
-	return clk;
-}
-
-#ifdef CLK_DEBUG
-static void dump_clocks(void)
-{
-	struct clk *p;
-
-	mutex_lock(&clocks_mutex);
-	printk(KERN_INFO "CLOCKS:\n");
-	list_for_each_entry(p, &clocks, node) {
-		pr_info("  %s=%ld", p->name, p->rate);
-		if (p->parent)
-			pr_cont(" %s=%ld", p->parent->name,
-			       p->parent->rate);
-		if (p->flags & CLK_HAS_CTRL)
-			pr_cont(" reg/bit=%d/%d", p->reg, p->bit);
-		pr_cont("\n");
-	}
-	mutex_unlock(&clocks_mutex);
-}
-#define	DEBUG_CLK_DUMP() dump_clocks()
-#else
-#define	DEBUG_CLK_DUMP()
-#endif
-
-
-static void mpc5121_clk_put(struct clk *clk)
-{
-	module_put(clk->owner);
-}
-
-#define NRPSC 12
-
-struct mpc512x_clockctl {
-	u32 spmr;		/* System PLL Mode Reg */
-	u32 sccr[2];		/* System Clk Ctrl Reg 1 & 2 */
-	u32 scfr1;		/* System Clk Freq Reg 1 */
-	u32 scfr2;		/* System Clk Freq Reg 2 */
-	u32 reserved;
-	u32 bcr;		/* Bread Crumb Reg */
-	u32 pccr[NRPSC];	/* PSC Clk Ctrl Reg 0-11 */
-	u32 spccr;		/* SPDIF Clk Ctrl Reg */
-	u32 cccr;		/* CFM Clk Ctrl Reg */
-	u32 dccr;		/* DIU Clk Cnfg Reg */
-};
-
-static struct mpc512x_clockctl __iomem *clockctl;
-
-static int mpc5121_clk_enable(struct clk *clk)
-{
-	unsigned int mask;
-
-	if (clk->flags & CLK_HAS_CTRL) {
-		mask = in_be32(&clockctl->sccr[clk->reg]);
-		mask |= 1 << clk->bit;
-		out_be32(&clockctl->sccr[clk->reg], mask);
-	}
-	return 0;
-}
-
-static void mpc5121_clk_disable(struct clk *clk)
-{
-	unsigned int mask;
-
-	if (clk->flags & CLK_HAS_CTRL) {
-		mask = in_be32(&clockctl->sccr[clk->reg]);
-		mask &= ~(1 << clk->bit);
-		out_be32(&clockctl->sccr[clk->reg], mask);
-	}
-}
-
-static unsigned long mpc5121_clk_get_rate(struct clk *clk)
-{
-	if (clk->flags & CLK_HAS_RATE)
-		return clk->rate;
-	else
-		return 0;
-}
-
-static long mpc5121_clk_round_rate(struct clk *clk, unsigned long rate)
-{
-	return rate;
-}
-
-static int mpc5121_clk_set_rate(struct clk *clk, unsigned long rate)
-{
-	return 0;
-}
-
-static int clk_register(struct clk *clk)
-{
-	mutex_lock(&clocks_mutex);
-	list_add(&clk->node, &clocks);
-	mutex_unlock(&clocks_mutex);
-	return 0;
-}
-
-static unsigned long spmf_mult(void)
-{
-	/*
-	 * Convert spmf to multiplier
-	 */
-	static int spmf_to_mult[] = {
-		68, 1, 12, 16,
-		20, 24, 28, 32,
-		36, 40, 44, 48,
-		52, 56, 60, 64
-	};
-	int spmf = (in_be32(&clockctl->spmr) >> 24) & 0xf;
-	return spmf_to_mult[spmf];
-}
-
-static unsigned long sysdiv_div_x_2(void)
-{
-	/*
-	 * Convert sysdiv to divisor x 2
-	 * Some divisors have fractional parts so
-	 * multiply by 2 then divide by this value
-	 */
-	static int sysdiv_to_div_x_2[] = {
-		4, 5, 6, 7,
-		8, 9, 10, 14,
-		12, 16, 18, 22,
-		20, 24, 26, 30,
-		28, 32, 34, 38,
-		36, 40, 42, 46,
-		44, 48, 50, 54,
-		52, 56, 58, 62,
-		60, 64, 66,
-	};
-	int sysdiv = (in_be32(&clockctl->scfr2) >> 26) & 0x3f;
-	return sysdiv_to_div_x_2[sysdiv];
-}
-
-static unsigned long ref_to_sys(unsigned long rate)
-{
-	rate *= spmf_mult();
-	rate *= 2;
-	rate /= sysdiv_div_x_2();
-
-	return rate;
-}
-
-static unsigned long sys_to_ref(unsigned long rate)
-{
-	rate *= sysdiv_div_x_2();
-	rate /= 2;
-	rate /= spmf_mult();
-
-	return rate;
-}
-
-static long ips_to_ref(unsigned long rate)
-{
-	int ips_div = (in_be32(&clockctl->scfr1) >> 23) & 0x7;
-
-	rate *= ips_div;	/* csb_clk = ips_clk * ips_div */
-	rate *= 2;		/* sys_clk = csb_clk * 2 */
-	return sys_to_ref(rate);
-}
-
-static unsigned long devtree_getfreq(char *clockname)
-{
-	struct device_node *np;
-	const unsigned int *prop;
-	unsigned int val = 0;
-
-	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
-	if (np) {
-		prop = of_get_property(np, clockname, NULL);
-		if (prop)
-			val = *prop;
-	    of_node_put(np);
-	}
-	return val;
-}
-
-static void ref_clk_calc(struct clk *clk)
-{
-	unsigned long rate;
-
-	rate = devtree_getfreq("bus-frequency");
-	if (rate == 0) {
-		printk(KERN_ERR "No bus-frequency in dev tree\n");
-		clk->rate = 0;
-		return;
-	}
-	clk->rate = ips_to_ref(rate);
-}
-
-static struct clk ref_clk = {
-	.name = "ref_clk",
-	.calc = ref_clk_calc,
-};
-
-
-static void sys_clk_calc(struct clk *clk)
-{
-	clk->rate = ref_to_sys(ref_clk.rate);
-}
-
-static struct clk sys_clk = {
-	.name = "sys_clk",
-	.calc = sys_clk_calc,
-};
-
-static void diu_clk_calc(struct clk *clk)
-{
-	int diudiv_x_2 = in_be32(&clockctl->scfr1) & 0xff;
-	unsigned long rate;
-
-	rate = sys_clk.rate;
-
-	rate *= 2;
-	rate /= diudiv_x_2;
-
-	clk->rate = rate;
-}
-
-static void viu_clk_calc(struct clk *clk)
-{
-	unsigned long rate;
-
-	rate = sys_clk.rate;
-	rate /= 2;
-	clk->rate = rate;
-}
-
-static void half_clk_calc(struct clk *clk)
-{
-	clk->rate = clk->parent->rate / 2;
-}
-
-static void generic_div_clk_calc(struct clk *clk)
-{
-	int div = (in_be32(&clockctl->scfr1) >> clk->div_shift) & 0x7;
-
-	clk->rate = clk->parent->rate / div;
-}
-
-static void unity_clk_calc(struct clk *clk)
-{
-	clk->rate = clk->parent->rate;
-}
-
-static struct clk csb_clk = {
-	.name = "csb_clk",
-	.calc = half_clk_calc,
-	.parent = &sys_clk,
-};
-
-static void e300_clk_calc(struct clk *clk)
-{
-	int spmf = (in_be32(&clockctl->spmr) >> 16) & 0xf;
-	int ratex2 = clk->parent->rate * spmf;
-
-	clk->rate = ratex2 / 2;
-}
-
-static struct clk e300_clk = {
-	.name = "e300_clk",
-	.calc = e300_clk_calc,
-	.parent = &csb_clk,
-};
-
-static struct clk ips_clk = {
-	.name = "ips_clk",
-	.calc = generic_div_clk_calc,
-	.parent = &csb_clk,
-	.div_shift = 23,
-};
-
-/*
- * Clocks controlled by SCCR1 (.reg = 0)
- */
-static struct clk lpc_clk = {
-	.name = "lpc_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 0,
-	.bit = 30,
-	.calc = generic_div_clk_calc,
-	.parent = &ips_clk,
-	.div_shift = 11,
-};
-
-static struct clk nfc_clk = {
-	.name = "nfc_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 0,
-	.bit = 29,
-	.calc = generic_div_clk_calc,
-	.parent = &ips_clk,
-	.div_shift = 8,
-};
-
-static struct clk pata_clk = {
-	.name = "pata_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 0,
-	.bit = 28,
-	.calc = unity_clk_calc,
-	.parent = &ips_clk,
-};
-
-/*
- * PSC clocks (bits 27 - 16)
- * are setup elsewhere
- */
-
-static struct clk sata_clk = {
-	.name = "sata_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 0,
-	.bit = 14,
-	.calc = unity_clk_calc,
-	.parent = &ips_clk,
-};
-
-static struct clk fec_clk = {
-	.name = "fec_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 0,
-	.bit = 13,
-	.calc = unity_clk_calc,
-	.parent = &ips_clk,
-};
-
-static struct clk pci_clk = {
-	.name = "pci_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 0,
-	.bit = 11,
-	.calc = generic_div_clk_calc,
-	.parent = &csb_clk,
-	.div_shift = 20,
-};
-
-/*
- * Clocks controlled by SCCR2 (.reg = 1)
- */
-static struct clk diu_clk = {
-	.name = "diu_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 31,
-	.calc = diu_clk_calc,
-};
-
-static struct clk viu_clk = {
-	.name = "viu_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 18,
-	.calc = viu_clk_calc,
-};
-
-static struct clk axe_clk = {
-	.name = "axe_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 30,
-	.calc = unity_clk_calc,
-	.parent = &csb_clk,
-};
-
-static struct clk usb1_clk = {
-	.name = "usb1_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 28,
-	.calc = unity_clk_calc,
-	.parent = &csb_clk,
-};
-
-static struct clk usb2_clk = {
-	.name = "usb2_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 27,
-	.calc = unity_clk_calc,
-	.parent = &csb_clk,
-};
-
-static struct clk i2c_clk = {
-	.name = "i2c_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 26,
-	.calc = unity_clk_calc,
-	.parent = &ips_clk,
-};
-
-static struct clk mscan_clk = {
-	.name = "mscan_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 25,
-	.calc = unity_clk_calc,
-	.parent = &ips_clk,
-};
-
-static struct clk sdhc_clk = {
-	.name = "sdhc_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 24,
-	.calc = unity_clk_calc,
-	.parent = &ips_clk,
-};
-
-static struct clk mbx_bus_clk = {
-	.name = "mbx_bus_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 22,
-	.calc = half_clk_calc,
-	.parent = &csb_clk,
-};
-
-static struct clk mbx_clk = {
-	.name = "mbx_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 21,
-	.calc = unity_clk_calc,
-	.parent = &csb_clk,
-};
-
-static struct clk mbx_3d_clk = {
-	.name = "mbx_3d_clk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 20,
-	.calc = generic_div_clk_calc,
-	.parent = &mbx_bus_clk,
-	.div_shift = 14,
-};
-
-static void psc_mclk_in_calc(struct clk *clk)
-{
-	clk->rate = devtree_getfreq("psc_mclk_in");
-	if (!clk->rate)
-		clk->rate = 25000000;
-}
-
-static struct clk psc_mclk_in = {
-	.name = "psc_mclk_in",
-	.calc = psc_mclk_in_calc,
-};
-
-static struct clk spdif_txclk = {
-	.name = "spdif_txclk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 23,
-};
-
-static struct clk spdif_rxclk = {
-	.name = "spdif_rxclk",
-	.flags = CLK_HAS_CTRL,
-	.reg = 1,
-	.bit = 23,
-};
-
-static void ac97_clk_calc(struct clk *clk)
-{
-	/* ac97 bit clock is always 24.567 MHz */
-	clk->rate = 24567000;
-}
-
-static struct clk ac97_clk = {
-	.name = "ac97_clk_in",
-	.calc = ac97_clk_calc,
-};
-
-static struct clk *rate_clks[] = {
-	&ref_clk,
-	&sys_clk,
-	&diu_clk,
-	&viu_clk,
-	&csb_clk,
-	&e300_clk,
-	&ips_clk,
-	&fec_clk,
-	&sata_clk,
-	&pata_clk,
-	&nfc_clk,
-	&lpc_clk,
-	&mbx_bus_clk,
-	&mbx_clk,
-	&mbx_3d_clk,
-	&axe_clk,
-	&usb1_clk,
-	&usb2_clk,
-	&i2c_clk,
-	&mscan_clk,
-	&sdhc_clk,
-	&pci_clk,
-	&psc_mclk_in,
-	&spdif_txclk,
-	&spdif_rxclk,
-	&ac97_clk,
-	NULL
-};
-
-static void rate_clk_init(struct clk *clk)
-{
-	if (clk->calc) {
-		clk->calc(clk);
-		clk->flags |= CLK_HAS_RATE;
-		clk_register(clk);
-	} else {
-		printk(KERN_WARNING
-		       "Could not initialize clk %s without a calc routine\n",
-		       clk->name);
-	}
-}
-
-static void rate_clks_init(void)
-{
-	struct clk **cpp, *clk;
-
-	cpp = rate_clks;
-	while ((clk = *cpp++))
-		rate_clk_init(clk);
-}
-
-/*
- * There are two clk enable registers with 32 enable bits each
- * psc clocks and device clocks are all stored in dev_clks
- */
-static struct clk dev_clks[2][32];
-
-/*
- * Given a psc number return the dev_clk
- * associated with it
- */
-static struct clk *psc_dev_clk(int pscnum)
-{
-	int reg, bit;
-	struct clk *clk;
-
-	reg = 0;
-	bit = 27 - pscnum;
-
-	clk = &dev_clks[reg][bit];
-	clk->reg = 0;
-	clk->bit = bit;
-	return clk;
-}
-
-/*
- * PSC clock rate calculation
- */
-static void psc_calc_rate(struct clk *clk, int pscnum, struct device_node *np)
-{
-	unsigned long mclk_src = sys_clk.rate;
-	unsigned long mclk_div;
-
-	/*
-	 * Can only change value of mclk divider
-	 * when the divider is disabled.
-	 *
-	 * Zero is not a valid divider so minimum
-	 * divider is 1
-	 *
-	 * disable/set divider/enable
-	 */
-	out_be32(&clockctl->pccr[pscnum], 0);
-	out_be32(&clockctl->pccr[pscnum], 0x00020000);
-	out_be32(&clockctl->pccr[pscnum], 0x00030000);
-
-	if (in_be32(&clockctl->pccr[pscnum]) & 0x80) {
-		clk->rate = spdif_rxclk.rate;
-		return;
-	}
-
-	switch ((in_be32(&clockctl->pccr[pscnum]) >> 14) & 0x3) {
-	case 0:
-		mclk_src = sys_clk.rate;
-		break;
-	case 1:
-		mclk_src = ref_clk.rate;
-		break;
-	case 2:
-		mclk_src = psc_mclk_in.rate;
-		break;
-	case 3:
-		mclk_src = spdif_txclk.rate;
-		break;
-	}
-
-	mclk_div = ((in_be32(&clockctl->pccr[pscnum]) >> 17) & 0x7fff) + 1;
-	clk->rate = mclk_src / mclk_div;
-}
-
-/*
- * Find all psc nodes in device tree and assign a clock
- * with name "psc%d_mclk" and dev pointing at the device
- * returned from of_find_device_by_node
- */
-static void psc_clks_init(void)
-{
-	struct device_node *np;
-	struct platform_device *ofdev;
-	u32 reg;
-	const char *psc_compat;
-
-	psc_compat = mpc512x_select_psc_compat();
-	if (!psc_compat)
-		return;
-
-	for_each_compatible_node(np, NULL, psc_compat) {
-		if (!of_property_read_u32(np, "reg", &reg)) {
-			int pscnum = (reg & 0xf00) >> 8;
-			struct clk *clk = psc_dev_clk(pscnum);
-
-			clk->flags = CLK_HAS_RATE | CLK_HAS_CTRL;
-			ofdev = of_find_device_by_node(np);
-			clk->dev = &ofdev->dev;
-			/*
-			 * AC97 is special rate clock does
-			 * not go through normal path
-			 */
-			if (of_device_is_compatible(np, "fsl,mpc5121-psc-ac97"))
-				clk->rate = ac97_clk.rate;
-			else
-				psc_calc_rate(clk, pscnum, np);
-			sprintf(clk->name, "psc%d_mclk", pscnum);
-			clk_register(clk);
-			clk_enable(clk);
-		}
-	}
-}
-
-static struct clk_interface mpc5121_clk_functions = {
-	.clk_get		= mpc5121_clk_get,
-	.clk_enable		= mpc5121_clk_enable,
-	.clk_disable		= mpc5121_clk_disable,
-	.clk_get_rate		= mpc5121_clk_get_rate,
-	.clk_put		= mpc5121_clk_put,
-	.clk_round_rate		= mpc5121_clk_round_rate,
-	.clk_set_rate		= mpc5121_clk_set_rate,
-	.clk_set_parent		= NULL,
-	.clk_get_parent		= NULL,
-};
-
-int __init mpc5121_clk_init(void)
-{
-	struct device_node *np;
-
-	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
-	if (np) {
-		clockctl = of_iomap(np, 0);
-		of_node_put(np);
-	}
-
-	if (!clockctl) {
-		printk(KERN_ERR "Could not map clock control registers\n");
-		return 0;
-	}
-
-	rate_clks_init();
-	psc_clks_init();
-
-	/* leave clockctl mapped forever */
-	/*iounmap(clockctl); */
-	DEBUG_CLK_DUMP();
-	clocks_initialized++;
-	clk_functions = mpc5121_clk_functions;
-	return 0;
-}
-- 
1.7.10.4

[PATCH v3 30/31] net: can: mscan: remove non-common_clock code for MPC512x

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:57

transition to the common clock framework has completed and the PPC_CLOCK
is no longer available for the MPC512x platform, remove the now obsolete
code path of the mpc5xxx mscan driver which accessed clock control
module registers directly

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/net/can/mscan/mpc5xxx_can.c |  141 -----------------------------------
 1 file changed, 141 deletions(-)
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index 4897929..dd6bdaa 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -109,9 +109,6 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
-
-#if IS_ENABLED(CONFIG_COMMON_CLK)
-
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_source, int *mscan_clksrc)
 {
@@ -267,144 +264,6 @@ static void mpc512x_can_put_clock(struct platform_device *ofdev)
 		devm_clk_put(&ofdev->dev, priv->clk_can);
 	}
 }
-
-#else	/* COMMON_CLK */
-
-struct mpc512x_clockctl {
-	u32 spmr;		/* System PLL Mode Reg */
-	u32 sccr[2];		/* System Clk Ctrl Reg 1 & 2 */
-	u32 scfr1;		/* System Clk Freq Reg 1 */
-	u32 scfr2;		/* System Clk Freq Reg 2 */
-	u32 reserved;
-	u32 bcr;		/* Bread Crumb Reg */
-	u32 pccr[12];		/* PSC Clk Ctrl Reg 0-11 */
-	u32 spccr;		/* SPDIF Clk Ctrl Reg */
-	u32 cccr;		/* CFM Clk Ctrl Reg */
-	u32 dccr;		/* DIU Clk Cnfg Reg */
-	u32 mccr[4];		/* MSCAN Clk Ctrl Reg 1-3 */
-};
-
-static struct of_device_id mpc512x_clock_ids[] = {
-	{ .compatible = "fsl,mpc5121-clock", },
-	{}
-};
-
-static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
-				 const char *clock_name, int *mscan_clksrc)
-{
-	struct mpc512x_clockctl __iomem *clockctl;
-	struct device_node *np_clock;
-	struct clk *sys_clk, *ref_clk;
-	int plen, clockidx, clocksrc = -1;
-	u32 sys_freq, val, clockdiv = 1, freq = 0;
-	const u32 *pval;
-
-	np_clock = of_find_matching_node(NULL, mpc512x_clock_ids);
-	if (!np_clock) {
-		dev_err(&ofdev->dev, "couldn't find clock node\n");
-		return 0;
-	}
-	clockctl = of_iomap(np_clock, 0);
-	if (!clockctl) {
-		dev_err(&ofdev->dev, "couldn't map clock registers\n");
-		goto exit_put;
-	}
-
-	/* Determine the MSCAN device index from the peripheral's
-	 * physical address. Register address offsets against the
-	 * IMMR base are:  0x1300, 0x1380, 0x2300, 0x2380
-	 */
-	pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
-	BUG_ON(!pval || plen < sizeof(*pval));
-	clockidx = (*pval & 0x80) ? 1 : 0;
-	if (*pval & 0x2000)
-		clockidx += 2;
-
-	/*
-	 * Clock source and divider selection: 3 different clock sources
-	 * can be selected: "ip", "ref" or "sys". For the latter two, a
-	 * clock divider can be defined as well. If the clock source is
-	 * not specified by the device tree, we first try to find an
-	 * optimal CAN source clock based on the system clock. If that
-	 * is not posslible, the reference clock will be used.
-	 */
-	if (clock_name && !strcmp(clock_name, "ip")) {
-		*mscan_clksrc = MSCAN_CLKSRC_IPS;
-		freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
-	} else {
-		*mscan_clksrc = MSCAN_CLKSRC_BUS;
-
-		pval = of_get_property(ofdev->dev.of_node,
-				       "fsl,mscan-clock-divider", &plen);
-		if (pval && plen == sizeof(*pval))
-			clockdiv = *pval;
-		if (!clockdiv)
-			clockdiv = 1;
-
-		if (!clock_name || !strcmp(clock_name, "sys")) {
-			sys_clk = devm_clk_get(&ofdev->dev, "sys_clk");
-			if (IS_ERR(sys_clk)) {
-				dev_err(&ofdev->dev, "couldn't get sys_clk\n");
-				goto exit_unmap;
-			}
-			/* Get and round up/down sys clock rate */
-			sys_freq = 1000000 *
-				((clk_get_rate(sys_clk) + 499999) / 1000000);
-
-			if (!clock_name) {
-				/* A multiple of 16 MHz would be optimal */
-				if ((sys_freq % 16000000) == 0) {
-					clocksrc = 0;
-					clockdiv = sys_freq / 16000000;
-					freq = sys_freq / clockdiv;
-				}
-			} else {
-				clocksrc = 0;
-				freq = sys_freq / clockdiv;
-			}
-		}
-
-		if (clocksrc < 0) {
-			ref_clk = devm_clk_get(&ofdev->dev, "ref_clk");
-			if (IS_ERR(ref_clk)) {
-				dev_err(&ofdev->dev, "couldn't get ref_clk\n");
-				goto exit_unmap;
-			}
-			clocksrc = 1;
-			freq = clk_get_rate(ref_clk) / clockdiv;
-		}
-	}
-
-	/* Disable clock */
-	out_be32(&clockctl->mccr[clockidx], 0x0);
-	if (clocksrc >= 0) {
-		/* Set source and divider */
-		val = (clocksrc << 14) | ((clockdiv - 1) << 17);
-		out_be32(&clockctl->mccr[clockidx], val);
-		/* Enable clock */
-		out_be32(&clockctl->mccr[clockidx], val | 0x10000);
-	}
-
-	/* Enable MSCAN clock domain */
-	val = in_be32(&clockctl->sccr[1]);
-	if (!(val & (1 << 25)))
-		out_be32(&clockctl->sccr[1], val | (1 << 25));
-
-	dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n",
-		*mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" :
-		clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
-
-exit_unmap:
-	iounmap(clockctl);
-exit_put:
-	of_node_put(np_clock);
-	return freq;
-}
-
-#define mpc512x_can_put_clock NULL
-
-#endif	/* COMMON_CLK */
-
 #else /* !CONFIG_PPC_MPC512x */
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_name, int *mscan_clksrc)
-- 
1.7.10.4

[PATCH v3 31/31] clk: mpc512x: remove clkdev registration (sys/ref, header)

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:14:58

remove the last clkdev registration call ("sys_clk" and "ref_clk"
for mscan), as well as the clkdev header inclusion and the "compat
registration" comment

all client lookups for clock items are device tree based now, no
compatibility alias names need to get provided any longer

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/clock-commonclk.c |    5 -----
 1 file changed, 5 deletions(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index 893fbe5..e9451a7 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -12,7 +12,6 @@
  */
 
 #include <linux/clk-provider.h>
-#include <linux/clkdev.h>
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/io.h>
@@ -673,10 +672,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	/* fixed frequency for AC97, always 24.567MHz */
 	clks[MPC512x_CLK_AC97] = mpc512x_clk_fixed("ac97", 24567000);
 
-	/* clkdev registration for compatibility reasons */
-	clk_register_clkdev(clks[MPC512x_CLK_REF], "ref_clk", NULL);
-	clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys_clk", NULL);
-
 	pr_debug("clock tree setup complete\n");
 	freq = clk_get_rate(clks[MPC512x_CLK_E300]);
 	pr_debug("derived PPC freq [%d]\n", freq);
-- 
1.7.10.4

Re: [PATCH v3 08/31] fs_enet: cleanup clock API use

From: Marc Kleine-Budde <mkl@pengutronix.de>
Date: 2013-07-22 12:28:36

On 07/22/2013 02:14 PM, Gerhard Sittig wrote:
make the Freescale ethernet driver get, prepare and enable the FEC clock
during probe(); disable, unprepare and put the clock upon remove(); hold
a reference to the clock over the period of use; use devm_{get,put}_clk()
There's no need for devm_clk_put(), devm will take care of this.

Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

Re: [PATCH v3 11/31] net: can: mscan: improve clock API use

From: Marc Kleine-Budde <mkl@pengutronix.de>
Date: 2013-07-22 12:31:21

On 07/22/2013 02:14 PM, Gerhard Sittig wrote:
the .get_clock() callback is run from probe() and might allocate
resources, introduce a .put_clock() callback that is run from remove()
to undo any allocation activities
looks good
use devm_get_clk() upon lookup (for SYS and REF) to have the clocks put
upon driver unload
fine
assume that resources get prepared but not necessarily enabled in the
setup phase, make the open() and close() callbacks of the CAN network
device enable and disable a previously acquired and prepared clock
I think you should call prepare_enable and disable_unprepare in the
open/close functions.

Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

[PATCH v3 00/31] add COMMON_CLK support for PowerPC MPC512x

From: Gerhard Sittig <hidden>
Date: 2013-07-22 12:33:24

[ manually added devicetree at vger now ]

On Mon, Jul 22, 2013 at 14:14 +0200, Gerhard Sittig wrote:
this series
- fixes several drivers that are used in the MPC512x platform (UART,
  SPI, ethernet, PCI, USB, CAN, NAND flash, video capture) in how they
  handle clocks (appropriately acquire and setup them, hold references
  during use, release clocks after use)
- introduces support for the common clock framework (CCF, COMMON_CLK
  Kconfig option) in the PowerPC based MPC512x platform, which brings
  device tree based clock lookup as well
Haven't noticed before that the ozlabs device tree list started
actively rejecting reception.  And the scope of the series has
widened to include clock related fixes in many more drivers while
the initial submission only introduced CCF for MPC512x.

Shall I resend (with vger devicetree included and more subsystems
lists added)?  Which other lists to include without spamming too
many channels?  Poor moderators have to ACK messages for lists
that I'm not subscribed to.


virtually yours
Gerhard Sittig
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

Re: [PATCH v3 27/31] net: can: mscan: add common clock support for mpc512x

From: Marc Kleine-Budde <mkl@pengutronix.de>
Date: 2013-07-22 13:04:52

On 07/22/2013 02:14 PM, Gerhard Sittig wrote:
quoted hunk
implement a .get_clock() callback for the MPC512x platform which uses
the common clock infrastructure (eliminating direct access to the clock
control registers from within the CAN network driver), and provide the
corresponding .put_clock() callback to release resources after use

keep the previous implementation of MPC512x support in place during
migration, since common clock support is optional

this change is neutral to the MPC5200 platform

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/net/can/mscan/mpc5xxx_can.c |  169 +++++++++++++++++++++++++++++++++++
 1 file changed, 169 insertions(+)
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index e59b3a3..4897929 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -109,6 +109,167 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
+
+#if IS_ENABLED(CONFIG_COMMON_CLK)
+
+static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
+				 const char *clock_source, int *mscan_clksrc)
+{
+	struct device_node *np;
+	u32 clockdiv;
+	enum {
+		CLK_FROM_AUTO,
+		CLK_FROM_IPS,
+		CLK_FROM_SYS,
+		CLK_FROM_REF,
+	} clk_from;
+	struct clk *clk_in, *clk_can;
+	unsigned long freq_calc;
+	struct mscan_priv *priv;
+
+	/* the caller passed in the clock source spec that was read from
+	 * the device tree, get the optional clock divider as well
+	 */
+	np = ofdev->dev.of_node;
+	clockdiv = 1;
+	of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
+	dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
+		clock_source ? clock_source : "<NULL>", clockdiv);
+
+	/* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
+	 * get set, and the 'ips' clock is the input to the MSCAN
+	 * component
+	 *
+	 * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
+	 * bit needs to get cleared, an optional clock-divider may have
+	 * been specified (the default value is 1), the appropriate
+	 * MSCAN related MCLK is the input to the MSCAN component
+	 *
+	 * in the absence of a clock-source spec, first an optimal clock
+	 * gets determined based on the 'sys' clock, if that fails the
+	 * 'ref' clock is used
+	 */
+	clk_from = CLK_FROM_AUTO;
+	if (clock_source) {
+		/* interpret the device tree's spec for the clock source */
+		if (!strcmp(clock_source, "ip"))
+			clk_from = CLK_FROM_IPS;
+		else if (!strcmp(clock_source, "sys"))
+			clk_from = CLK_FROM_SYS;
+		else if (!strcmp(clock_source, "ref"))
+			clk_from = CLK_FROM_REF;
+		else
+			goto err_invalid;
+		dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, try the 'sys' clock; round to the
+		 * next MHz and see if we can get a multiple of 16MHz
+		 */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
+		clk_in = devm_clk_get(&ofdev->dev, "sys");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc +=  499999;
+		freq_calc /= 1000000;
+		freq_calc *= 1000000;
+		if ((freq_calc % 16000000) == 0) {
+			clk_from = CLK_FROM_SYS;
+			clockdiv = freq_calc / 16000000;
+			dev_dbg(&ofdev->dev,
+				"clk fit, sys[%lu] div[%d] freq[%lu]\n",
+				freq_calc, clockdiv, freq_calc / clockdiv);
+		}
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, use the 'ref' clock */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
+		clk_in = devm_clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_from = CLK_FROM_REF;
+		freq_calc = clk_get_rate(clk_in);
+		dev_dbg(&ofdev->dev,
+			"clk fit, ref[%lu] (no div) freq[%lu]\n",
+			freq_calc, freq_calc);
+	}
+
+	/* select IPS or MCLK as the MSCAN input (returned to the caller),
+	 * setup the MCLK mux source and rate if applicable, apply the
+	 * optionally specified or derived above divider, and determine
+	 * the actual resulting clock rate to return to the caller
+	 */
+	switch (clk_from) {
+	case CLK_FROM_IPS:
+		clk_can = devm_clk_get(&ofdev->dev, "ips");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		if (clk_prepare(clk_can)) {
I would just call prepare_enable in the main mscan driver, then we don't
need a special "clock is prepared but not enabled" contract.
+			devm_clk_put(&ofdev->dev, clk_can);
not needed, as this driver instance will fail, doesn't it?
+			goto err_notavail;
+		}
+		priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+		priv->clk_can = clk_can;
+		freq_calc = clk_get_rate(clk_can);
+		*mscan_clksrc = MSCAN_CLKSRC_IPS;
+		dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
+			*mscan_clksrc, freq_calc);
+		break;
+	case CLK_FROM_SYS:
+	case CLK_FROM_REF:
+		clk_can = devm_clk_get(&ofdev->dev, "mclk");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		if (clk_prepare(clk_can)) {
+			devm_clk_put(&ofdev->dev, clk_can);
same here
+			goto err_notavail;
+		}
+		priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+		priv->clk_can = clk_can;
+		if (clk_from == CLK_FROM_SYS)
+			clk_in = devm_clk_get(&ofdev->dev, "sys");
+		if (clk_from == CLK_FROM_REF)
+			clk_in = devm_clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_set_parent(clk_can, clk_in);
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc /= clockdiv;
+		clk_set_rate(clk_can, freq_calc);
+		freq_calc = clk_get_rate(clk_can);
+		*mscan_clksrc = MSCAN_CLKSRC_BUS;
+		dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n",
+			*mscan_clksrc, freq_calc);
+		break;
+	default:
+		goto err_invalid;
+	}
+
+	return freq_calc;
+
+err_invalid:
+	dev_err(&ofdev->dev, "invalid clock source specification\n");
+	return 0;
return 0 in case of error? Please add a comment what this 0 means here.
+
+err_notavail:
+	dev_err(&ofdev->dev, "cannot acquire or setup clock source\n");
+	return 0;
+}
+
+static void mpc512x_can_put_clock(struct platform_device *ofdev)
+{
+	struct mscan_priv *priv;
+
+	priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+	if (priv->clk_can) {
+		clk_unprepare(priv->clk_can);
+		devm_clk_put(&ofdev->dev, priv->clk_can);
devm_clk_put can be removed, it's called automatically.
quoted hunk
+	}
+}
+
+#else	/* COMMON_CLK */
+
 struct mpc512x_clockctl {
 	u32 spmr;		/* System PLL Mode Reg */
 	u32 sccr[2];		/* System Clk Ctrl Reg 1 & 2 */
@@ -239,12 +400,18 @@ exit_put:
 	of_node_put(np_clock);
 	return freq;
 }
+
+#define mpc512x_can_put_clock NULL
+
+#endif	/* COMMON_CLK */
+
 #else /* !CONFIG_PPC_MPC512x */
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_name, int *mscan_clksrc)
 {
 	return 0;
 }
+#define mpc512x_can_put_clock NULL
 #endif /* CONFIG_PPC_MPC512x */
 
 static const struct of_device_id mpc5xxx_can_table[];
@@ -386,11 +553,13 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev)
 static const struct mpc5xxx_can_data mpc5200_can_data = {
 	.type = MSCAN_TYPE_MPC5200,
 	.get_clock = mpc52xx_can_get_clock,
+	/* .put_clock not applicable */
 };
 
 static const struct mpc5xxx_can_data mpc5121_can_data = {
 	.type = MSCAN_TYPE_MPC5121,
 	.get_clock = mpc512x_can_get_clock,
+	.put_clock = mpc512x_can_put_clock,
 };
 
 static const struct of_device_id mpc5xxx_can_table[] = {
Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

Re: [PATCH v3 01/31] spi: mpc512x: cleanup clock API use

From: Mark Brown <broonie@kernel.org>
Date: 2013-07-22 14:09:04

On Mon, Jul 22, 2013 at 02:14:28PM +0200, Gerhard Sittig wrote:
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		devm_clk_put(dev, clk);
+		goto free_irq;
The main point of the devm_ APIs is to avoid the need for explicit
freeing so you should just remove these puts.

Re: [PATCH v3 11/31] net: can: mscan: improve clock API use

From: Gerhard Sittig <hidden>
Date: 2013-07-23 11:53:48

On Mon, Jul 22, 2013 at 14:31 +0200, Marc Kleine-Budde wrote:
On 07/22/2013 02:14 PM, Gerhard Sittig wrote:
quoted
the .get_clock() callback is run from probe() and might allocate
resources, introduce a .put_clock() callback that is run from remove()
to undo any allocation activities
looks good
quoted
use devm_get_clk() upon lookup (for SYS and REF) to have the clocks put
upon driver unload
fine
quoted
assume that resources get prepared but not necessarily enabled in the
setup phase, make the open() and close() callbacks of the CAN network
device enable and disable a previously acquired and prepared clock
I think you should call prepare_enable and disable_unprepare in the
open/close functions.
After more local research, which totally eliminated the need to
pre-enable the CAN related clocks, but might need more discussion
as it touches the common gate support, I've learned something
more:

The CAN clock needs to get enabled during probe() already, since
registers get accessed between probe() for the driver and open()
for the network device -- while access to peripheral registers
crashes the kernel when clocks still are disabled (other hardware
may just hang or provide fake data, neither of this is OK).

But I see the point in your suggestion to prepare _and_ enable
the clock during open() as well -- to have open() cope with
whatever probe() did, after all the driver is shared among
platforms, which may differ in what they do during probe().

So I will:
- make open() of the network device prepare _and_ enable the
  clock for the peripheral (if acquired during probe())
- adjust open() because ATM it leaves the clock enabled when the
  network device operation fails (the error path is incomplete in
  v3)
- make the MPC512x specific probe() time .get_clock() routine not
  just prepare but enable the clock as well
- and of course address all the shutdown counter parts of the
  above setup paths

This results in:
- specific chip drivers only need to balance their private get
  and put clock routines which are called from probe and remove,
  common paths DTRT for all of them
- correct operation for MPC512x, where common clock is used
- still everything is neutral for MPC5200 where common clock
  isn't used, behaviour is identical to before the change
- no assumptions are made about what occurs or doesn't occur
  during probe(), when the network device is used then the clock
  is fully setup and operational
- when the CAN network device isn't setup (because device tree
  doesn't describe it, or disables that node), then its clock
  remains idle (neither gets setup nor enabled)
- complete preparation for future improvement wrt power
  consumption, where potential changes remain isolated to the
  specific chip (probe() time setup, get_clock() routine) while
  the ndo part need not get touched any more

So this is the most appropriate approach I can come up with.


Removing unnecessary devm_put_clk() calls is orthogonal to that.
Putting these in isn't totally wrong (they won't harm, and they
do signal "visual balance" more clearly such that the next person
won't stop and wonder), but it's true that they are redundant.
"Trained persons" will wonder as much about their presence as
untrained persons wonder about their absence. :)  Apparently I'm
not well trained yet.

I thought that being explicit and cautious would be good, but the
feedback I got suggests that encoding unnecessary instructions
isn't desirable.  So I will remove those devm_put_clk() in v4.

To save us one more iteration, shall I remove those calls only
from error paths during setup?  Or shall I remove them from
regular shutdown paths as well?  How much pain does the community
feel with harmless yet unnecessary instructions? :)


virtually yours
Gerhard Sittig
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

[PATCH v3 01/31] spi: mpc512x: cleanup clock API use

From: Gerhard Sittig <hidden>
Date: 2013-07-23 11:58:12

[ devicetree@vger adjusted ]

On Mon, Jul 22, 2013 at 15:09 +0100, Mark Brown wrote:
On Mon, Jul 22, 2013 at 02:14:28PM +0200, Gerhard Sittig wrote:
quoted
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		devm_clk_put(dev, clk);
+		goto free_irq;
The main point of the devm_ APIs is to avoid the need for explicit
freeing so you should just remove these puts.
OK, will do in v4.

Shall these get removed everywhere including regular shutdown
paths, or just from error paths during setup?

[ the same topic came up for the CAN patch, might answer there ]


virtually yours
Gerhard Sittig
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

[PATCH v3 27/31] net: can: mscan: add common clock support for mpc512x

From: Gerhard Sittig <hidden>
Date: 2013-07-23 12:07:33

[ adjusted devtree to use the vger address ]

On Mon, Jul 22, 2013 at 15:04 +0200, Marc Kleine-Budde wrote:
On 07/22/2013 02:14 PM, Gerhard Sittig wrote:
quoted
implement a .get_clock() callback for the MPC512x platform which uses
the common clock infrastructure (eliminating direct access to the clock
control registers from within the CAN network driver), and provide the
corresponding .put_clock() callback to release resources after use

keep the previous implementation of MPC512x support in place during
migration, since common clock support is optional

this change is neutral to the MPC5200 platform

Signed-off-by: Gerhard Sittig <redacted>
---
 drivers/net/can/mscan/mpc5xxx_can.c |  169 +++++++++++++++++++++++++++++++++++
 1 file changed, 169 insertions(+)
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index e59b3a3..4897929 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -109,6 +109,167 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
+
+#if IS_ENABLED(CONFIG_COMMON_CLK)
+
+static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
+				 const char *clock_source, int *mscan_clksrc)
+{
+	struct device_node *np;
+	u32 clockdiv;
+	enum {
+		CLK_FROM_AUTO,
+		CLK_FROM_IPS,
+		CLK_FROM_SYS,
+		CLK_FROM_REF,
+	} clk_from;
+	struct clk *clk_in, *clk_can;
+	unsigned long freq_calc;
+	struct mscan_priv *priv;
+
+	/* the caller passed in the clock source spec that was read from
+	 * the device tree, get the optional clock divider as well
+	 */
+	np = ofdev->dev.of_node;
+	clockdiv = 1;
+	of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
+	dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
+		clock_source ? clock_source : "<NULL>", clockdiv);
+
+	/* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
+	 * get set, and the 'ips' clock is the input to the MSCAN
+	 * component
+	 *
+	 * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
+	 * bit needs to get cleared, an optional clock-divider may have
+	 * been specified (the default value is 1), the appropriate
+	 * MSCAN related MCLK is the input to the MSCAN component
+	 *
+	 * in the absence of a clock-source spec, first an optimal clock
+	 * gets determined based on the 'sys' clock, if that fails the
+	 * 'ref' clock is used
+	 */
+	clk_from = CLK_FROM_AUTO;
+	if (clock_source) {
+		/* interpret the device tree's spec for the clock source */
+		if (!strcmp(clock_source, "ip"))
+			clk_from = CLK_FROM_IPS;
+		else if (!strcmp(clock_source, "sys"))
+			clk_from = CLK_FROM_SYS;
+		else if (!strcmp(clock_source, "ref"))
+			clk_from = CLK_FROM_REF;
+		else
+			goto err_invalid;
+		dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, try the 'sys' clock; round to the
+		 * next MHz and see if we can get a multiple of 16MHz
+		 */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
+		clk_in = devm_clk_get(&ofdev->dev, "sys");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc +=  499999;
+		freq_calc /= 1000000;
+		freq_calc *= 1000000;
+		if ((freq_calc % 16000000) == 0) {
+			clk_from = CLK_FROM_SYS;
+			clockdiv = freq_calc / 16000000;
+			dev_dbg(&ofdev->dev,
+				"clk fit, sys[%lu] div[%d] freq[%lu]\n",
+				freq_calc, clockdiv, freq_calc / clockdiv);
+		}
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, use the 'ref' clock */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
+		clk_in = devm_clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_from = CLK_FROM_REF;
+		freq_calc = clk_get_rate(clk_in);
+		dev_dbg(&ofdev->dev,
+			"clk fit, ref[%lu] (no div) freq[%lu]\n",
+			freq_calc, freq_calc);
+	}
+
+	/* select IPS or MCLK as the MSCAN input (returned to the caller),
+	 * setup the MCLK mux source and rate if applicable, apply the
+	 * optionally specified or derived above divider, and determine
+	 * the actual resulting clock rate to return to the caller
+	 */
+	switch (clk_from) {
+	case CLK_FROM_IPS:
+		clk_can = devm_clk_get(&ofdev->dev, "ips");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		if (clk_prepare(clk_can)) {
I would just call prepare_enable in the main mscan driver, then we don't
need a special "clock is prepared but not enabled" contract.
Yes, I addressed this concern (although differently after
learning more from a local test setup), see the other reply for
the CAN driver adjustment for clock API use.
quoted
+			devm_clk_put(&ofdev->dev, clk_can);
not needed, as this driver instance will fail, doesn't it?
This is discussed in the other subthread as well.  The only
remaining question is how many of them to remove, before I'll
update the series.
quoted
+			goto err_notavail;
+		}
+		priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+		priv->clk_can = clk_can;
+		freq_calc = clk_get_rate(clk_can);
+		*mscan_clksrc = MSCAN_CLKSRC_IPS;
+		dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
+			*mscan_clksrc, freq_calc);
+		break;
+	case CLK_FROM_SYS:
+	case CLK_FROM_REF:
+		clk_can = devm_clk_get(&ofdev->dev, "mclk");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		if (clk_prepare(clk_can)) {
+			devm_clk_put(&ofdev->dev, clk_can);
same here
quoted
+			goto err_notavail;
+		}
+		priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+		priv->clk_can = clk_can;
+		if (clk_from == CLK_FROM_SYS)
+			clk_in = devm_clk_get(&ofdev->dev, "sys");
+		if (clk_from == CLK_FROM_REF)
+			clk_in = devm_clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_set_parent(clk_can, clk_in);
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc /= clockdiv;
+		clk_set_rate(clk_can, freq_calc);
+		freq_calc = clk_get_rate(clk_can);
+		*mscan_clksrc = MSCAN_CLKSRC_BUS;
+		dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n",
+			*mscan_clksrc, freq_calc);
+		break;
+	default:
+		goto err_invalid;
+	}
+
+	return freq_calc;
+
+err_invalid:
+	dev_err(&ofdev->dev, "invalid clock source specification\n");
+	return 0;
return 0 in case of error? Please add a comment what this 0 means here.
The .get_clock() callback is supposed to return the resulting
rate after the clock source was determined and the clock subtree
was setup.  It wasn't (explicitly) documented before (in the
non-common-clock case), so I did not bother to comment it in the
parallel common-clock case.

But it's true that returning zero in the error case may be
unexpected, and I will add a comment in v4 (in all the
.get_clock() implementations).
quoted
+
+err_notavail:
+	dev_err(&ofdev->dev, "cannot acquire or setup clock source\n");
+	return 0;
+}
+
+static void mpc512x_can_put_clock(struct platform_device *ofdev)
+{
+	struct mscan_priv *priv;
+
+	priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+	if (priv->clk_can) {
+		clk_unprepare(priv->clk_can);
+		devm_clk_put(&ofdev->dev, priv->clk_can);
devm_clk_put can be removed, it's called automatically.
quoted
+	}
+}
+
+#else	/* COMMON_CLK */
+
 struct mpc512x_clockctl {
 	u32 spmr;		/* System PLL Mode Reg */
 	u32 sccr[2];		/* System Clk Ctrl Reg 1 & 2 */
@@ -239,12 +400,18 @@ exit_put:
 	of_node_put(np_clock);
 	return freq;
 }
+
+#define mpc512x_can_put_clock NULL
+
+#endif	/* COMMON_CLK */
+
 #else /* !CONFIG_PPC_MPC512x */
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_name, int *mscan_clksrc)
 {
 	return 0;
 }
+#define mpc512x_can_put_clock NULL
 #endif /* CONFIG_PPC_MPC512x */
 
 static const struct of_device_id mpc5xxx_can_table[];
@@ -386,11 +553,13 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev)
 static const struct mpc5xxx_can_data mpc5200_can_data = {
 	.type = MSCAN_TYPE_MPC5200,
 	.get_clock = mpc52xx_can_get_clock,
+	/* .put_clock not applicable */
 };
 
 static const struct mpc5xxx_can_data mpc5121_can_data = {
 	.type = MSCAN_TYPE_MPC5121,
 	.get_clock = mpc512x_can_get_clock,
+	.put_clock = mpc512x_can_put_clock,
 };
 
 static const struct of_device_id mpc5xxx_can_table[] = {
Marc
Thank you for the fast and detailled review.  It's very much
appreciated.


virtually yours
Gerhard Sittig
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

Re: [PATCH v3 11/31] net: can: mscan: improve clock API use

From: Marc Kleine-Budde <mkl@pengutronix.de>
Date: 2013-07-23 12:33:00

On 07/23/2013 01:53 PM, Gerhard Sittig wrote:
On Mon, Jul 22, 2013 at 14:31 +0200, Marc Kleine-Budde wrote:
quoted
On 07/22/2013 02:14 PM, Gerhard Sittig wrote:
quoted
the .get_clock() callback is run from probe() and might allocate
resources, introduce a .put_clock() callback that is run from remove()
to undo any allocation activities
looks good
quoted
use devm_get_clk() upon lookup (for SYS and REF) to have the clocks put
upon driver unload
fine
quoted
assume that resources get prepared but not necessarily enabled in the
setup phase, make the open() and close() callbacks of the CAN network
device enable and disable a previously acquired and prepared clock
I think you should call prepare_enable and disable_unprepare in the
open/close functions.
After more local research, which totally eliminated the need to
pre-enable the CAN related clocks, but might need more discussion
as it touches the common gate support, I've learned something
more:

The CAN clock needs to get enabled during probe() already, since
registers get accessed between probe() for the driver and open()
for the network device -- while access to peripheral registers
crashes the kernel when clocks still are disabled (other hardware
may just hang or provide fake data, neither of this is OK).
Then call prepare_enable(); before and disable_unprepare(); after
accessing the registers. Have a look at the flexcan driver.
But I see the point in your suggestion to prepare _and_ enable
the clock during open() as well -- to have open() cope with
whatever probe() did, after all the driver is shared among
platforms, which may differ in what they do during probe().
If you enable a clock to access the registers before open() (and disable
it afterwards), it should not harm any architecture that doesn't need
this clock enabled.
So I will:
- make open() of the network device prepare _and_ enable the
  clock for the peripheral (if acquired during probe())
good
- adjust open() because ATM it leaves the clock enabled when the
  network device operation fails (the error path is incomplete in
  v3)
yes, clock should be disabled if open() fails.
- make the MPC512x specific probe() time .get_clock() routine not
  just prepare but enable the clock as well
If needed enable the clock, but disable after probe() has finished.
- and of course address all the shutdown counter parts of the
  above setup paths
This results in:
- specific chip drivers only need to balance their private get
  and put clock routines which are called from probe and remove,
  common paths DTRT for all of them
Yes, but clock should not stay enabled between probe() and open().

[...]
Removing unnecessary devm_put_clk() calls is orthogonal to that.
Putting these in isn't totally wrong (they won't harm, and they
do signal "visual balance" more clearly such that the next person
won't stop and wonder), but it's true that they are redundant.
"Trained persons" will wonder as much about their presence as
untrained persons wonder about their absence. :)  Apparently I'm
not well trained yet.
The whole point about devm_* is to get rid of auto manually tear down
functions. So please remove all devm_put_clk() calls, as it will be
called automatically if a driver instance is removed.

Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

[PATCH v3 27/31] net: can: mscan: add common clock support for mpc512x

From: mkl@pengutronix.de (Marc Kleine-Budde)
Date: 2013-07-23 12:37:29

On 07/23/2013 02:07 PM, Gerhard Sittig wrote:
[...]
quoted
quoted
+	return freq_calc;
+
+err_invalid:
+	dev_err(&ofdev->dev, "invalid clock source specification\n");
+	return 0;
return 0 in case of error? Please add a comment what this 0 means here.
The .get_clock() callback is supposed to return the resulting
rate after the clock source was determined and the clock subtree
was setup.  It wasn't (explicitly) documented before (in the
non-common-clock case), so I did not bother to comment it in the
parallel common-clock case.
Yes, but returning 0 in case of error should be documented, as it's very
uncommon.
But it's true that returning zero in the error case may be
unexpected, and I will add a comment in v4 (in all the
.get_clock() implementations).
I think a one liner stating that the return value is the clock rate and
"0" indicates is an invalid clock rate, this meaning an error here, is
enough.

Marc
-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

[PATCH v3 17/31] clk: mpc512x: introduce COMMON_CLK for MPC512x

From: Gerhard Sittig <hidden>
Date: 2013-07-23 13:14:06

[ summary: "shared gate" support desirable? approach acceptable? ]

On Mon, Jul 22, 2013 at 14:14 +0200, Gerhard Sittig wrote:
this change implements a clock driver for the MPC512x PowerPC platform
which follows the COMMON_CLK approach and uses common clock drivers
shared with other platforms

[ ... ]

some of the clock items get pre-enabled in the clock driver to not have
them automatically disabled by the underlying clock subsystem because of
their being unused -- this approach is desirable because
[ ... ]
- some help introduce support for and migrate to the common
  infrastructure, while more appropriate support for specific hardware
  constraints isn't available yet (remaining changes are strictly
  internal to the clock driver and won't affect peripheral drivers)
This remark was related to the CAN clocks of the MPC512x SoC.

The clock subtrees which are involved in generating CAN bitrates
include one path from the XTAL to an internal MCLK (this is part
of the CCF support for the platform), and another path from the
MCLK or yet another IP bus clock to the actual bitrate on the
wire (this is taken care of within the mscan(4) driver).

The MCLK generation for CAN is documented in the MPC5121e
Reference Manual, chapter 5, section 5.2.5 "MSCAN Clock
Generation".  SYS, REF (both internal), PSC_MCLK_IN, and SPDIF_TX
(both external) are muxed, gated, and divided.  The result is
muxed with IP.  The result is fed into the MSCAN component and
gets muxed with IP again (can't tell why, maybe for backwards
compatibility).

In parallel to this MCLK block there is SCCR2[25], the "BDLC and
MSCAN clock enable", documented in section 5.3.1.3 "System Clock
Control Register 2".  So there is a gate that "somehow needs to
get setup" yet isn't part of the visible MCLK chain.

The series up to and including v3 approaches the problem by
- adding a gate after the second MCLK mux, which gets exported
  for client lookups and is the MCLK input for the mscan(4)
  driver
- creating that gate for each of the four MSCAN clocks of the
  SoC, all of them referencing the single "enable" bit in the
  SCCR2 register
- pre-enabling the MSCAN clocks from within the clock driver, and
  thus avoid having the clock disabled from the common
  infrastructure, because disabling one of these clocks had
  closed the shared gate and thus had broken all other clock uses
clkdev registration provides "alias names" for few clock items
[ ... ]
[ ... ]
+
+/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
+static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
+{
+	size_t clks_idx_pub, clks_idx_int;
+	u32 __iomem *mccr_reg;	/* MCLK control register (mux, en, div) */
+	u32 __iomem *sccr_reg;	/* system clock control register (enable) */
+	int sccr_bit;
+	int div;
+
+	/* derive a few parameters from the component type and index */
+	switch (entry->type) {
+	case MCLK_TYPE_PSC:
+		clks_idx_pub = MPC512x_CLK_PSC0_MCLK + entry->comp_idx;
+		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+			     + (entry->comp_idx) * MCLK_MAX_IDX;
+		mccr_reg = &clkregs->psc_ccr[entry->comp_idx];
+		break;
+	case MCLK_TYPE_MSCAN:
+		clks_idx_pub = MPC512x_CLK_MSCAN0_MCLK + entry->comp_idx;
+		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+			     + (NR_PSCS + entry->comp_idx) * MCLK_MAX_IDX;
+		mccr_reg = &clkregs->mscan_ccr[entry->comp_idx];
+		break;
+	case MCLK_TYPE_SPDIF:
+		clks_idx_pub = MPC512x_CLK_SPDIF_MCLK;
+		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+			     + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
+		mccr_reg = &clkregs->spccr;
+		break;
+	default:
+		return;
+	}
+	if (entry->bit_sccr1 >= 0) {
+		sccr_reg = &clkregs->sccr1;
+		sccr_bit = entry->bit_sccr1;
+	} else if (entry->bit_sccr2 >= 0) {
+		sccr_reg = &clkregs->sccr2;
+		sccr_bit = entry->bit_sccr2;
+	} else {
+		sccr_reg = NULL;
+	}
+
+	/*
+	 * this was grabbed from the PPC_CLOCK implementation, which
+	 * enforced a specific MCLK divider while the clock was gated
+	 * during setup (that's a documented hardware requirement)
+	 *
+	 * the PPC_CLOCK implementation might even have violated the
+	 * "MCLK <= IPS" constraint, the fixed divider value of 1
+	 * results in a divider of 2 and thus MCLK = SYS/2 which equals
+	 * CSB which is greater than IPS; the serial port setup may have
+	 * adjusted the divider which the clock setup might have left in
+	 * an undesirable state
+	 *
+	 * initial setup is:
+	 * - MCLK 0 from SYS
+	 * - MCLK DIV such to not exceed the IPS clock
+	 * - MCLK 0 enabled
+	 * - MCLK 1 from MCLK DIV
+	 */
+	div = clk_get_rate(clks[MPC512x_CLK_SYS]);
+	div /= clk_get_rate(clks[MPC512x_CLK_IPS]);
+	out_be32(mccr_reg, (0 << 16));
+	out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
+	out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
+
+	/*
+	 * create the 'struct clk' items of the MCLK's clock subtree
+	 *
+	 * note that by design we always create all nodes and won't take
+	 * shortcuts here, because
+	 * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
+	 *   selectable inputs to the CFM while those who "actually use"
+	 *   the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
+	 *   for their bitrate
+	 * - in the absence of "aliases" for clocks we need to create
+	 *   individial 'struct clk' items for whatever might get
+	 *   referenced or looked up, even if several of those items are
+	 *   identical from the logical POV (their rate value)
+	 * - for easier future maintenance and for better reflection of
+	 *   the SoC's documentation, it appears appropriate to generate
+	 *   clock items even for those muxers which actually are NOPs
+	 *   (those with two inputs of which one is reserved)
+	 */
+	clks[clks_idx_int + MCLK_IDX_MUX0] = mpc512x_clk_muxed(
+			entry->name_mux0,
+			&parent_names_mux0[0], ARRAY_SIZE(parent_names_mux0),
+			mccr_reg, 14, 2);
+	clks[clks_idx_int + MCLK_IDX_EN0] = mpc512x_clk_gated(
+			entry->name_en0, entry->name_mux0,
+			mccr_reg, 16);
+	clks[clks_idx_int + MCLK_IDX_DIV0] = mpc512x_clk_divider(
+			entry->name_div0,
+			entry->name_en0, CLK_SET_RATE_GATE,
+			mccr_reg, 17, 15, 0);
+	if (entry->has_mclk1) {
+		clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_muxed(
+				entry->name_mux1,
+				&entry->parent_names_mux1[0],
+				ARRAY_SIZE(entry->parent_names_mux1),
+				mccr_reg, 7, 1);
+	} else {
+		clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_factor(
+				entry->name_mux1, entry->parent_names_mux1[0],
+				1, 1);
+	}
+	if (sccr_reg) {
+		clks[clks_idx_pub] = mpc512x_clk_gated(
+				entry->name_mclk,
+				entry->name_mux1, sccr_reg, sccr_bit);
+	} else {
+		clks[clks_idx_pub] = mpc512x_clk_factor(
+				entry->name_mclk,
+				entry->name_mux1, 1, 1);
+	}
+
+	/*
+	 * without this "clock device" registration, "simple" lookups in
+	 * the SPI master initialization and serial port setup will fail
+	 *
+	 * those drivers need to get adjusted to lookup their required
+	 * clocks from device tree specs, and device tree nodes need to
+	 * provide the clock specs, before this clkdev registration
+	 * becomes obsolete
+	 */
+	clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
+}
[ ... ]
This was the routine which sets up _one_ MCLK block, note the
assignment at the routine's end to the "published" clock item
that's the gate's output after the second mux stage.
[ ... ]
+	clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips",
+						  &clkregs->sccr2, 26);
+	mpc512x_clk_setup_mclks(mclk_mscan_data, ARRAY_SIZE(mclk_mscan_data));
+	clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug",
+						   &clkregs->sccr2, 24);
+	mpc512x_clk_setup_mclks(mclk_spdif_data, ARRAY_SIZE(mclk_spdif_data));
[ ... ]
This is the invocation of the routine which sets up four MCLK
blocks for the MSCAN components, while all of them refer to bit
25 of SCCR2.
[ ... ]
+
+	/* enable some of the clocks here unconditionally because ... */
+	pr_debug("automatically enabling some clocks\n");
+	/* some are essential yet never get claimed by any driver */
+	clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
+	clk_prepare_enable(clks[MPC512x_CLK_E300]);	/* PowerPC CPU */
+	clk_prepare_enable(clks[MPC512x_CLK_DDR]);	/* DRAM */
+	clk_prepare_enable(clks[MPC512x_CLK_MEM]);	/* SRAM */
+	clk_prepare_enable(clks[MPC512x_CLK_IPS]);	/* SoC periph */
+	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
+	/* some are required yet no dependencies were declared */
+	clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
+	/* some are not yet acquired by their respective drivers */
+	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
+	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
+	clk_prepare_enable(clks[MPC512x_CLK_DIU]);	/* display */
+	clk_prepare_enable(clks[MPC512x_CLK_I2C]);
+	/*
+	 * some have their individual clock subtree with separate clock
+	 * items and their individual enable counters, yet share a
+	 * common gate (refer to the same register location) while the
+	 * common clock driver code is not aware of the fact and the
+	 * platform's code doesn't provide specific support either
+	 *
+	 * what might happen is that e.g. enabling two MSCAN clock items
+	 * and disabling one of them will disable the common gate and
+	 * thus break the other MSCAN clock as well
+	 */
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN0_MCLK]);
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN1_MCLK]);
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN2_MCLK]);
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN3_MCLK]);
+}
This is the pre-enable workaround for the MSCAN0 to MSCAN3 clock
items.

The above approach does work in that it introduces complete
support for common clock on the MPC512x platform, with the CAN
component being operational, and the clock driver using shared
logic across platforms.

The remaining issue is that regardless of whether CAN is used,
the (chip internal) clock is enabled.  This may not be a problem
when bitrates aren't generated and the wire isn't driven.


The question now is how to correctly support the situation where
a gate is shared between subtrees yet isn't really part of any
path within the subtrees.  I really cannot find a single spot
where to introduce the gate such that it's not duplicated.

The appropriate solution would not be to pre-enable those clocks,
but to either introduce another gate clock type which supports a
shared reference, or to add support for the shared reference to
the existing gate code.


I'd rather not duplicate most or all of the code of clk-gate.c,
instead I looked into how to add "shared gate" support to the
existing driver.

My question is whether the approach is acceptable.  It adds
minimal overhead and shall be OK for the enable/disable path from
a technical POV.  And it doesn't feel like too much of a stretch.
But there may be non-technical reasons to reject the approach.
I'd like to learn whether to follow that path before preparing
another version of the patch series.

The diffs were taken with the '-w -b' options to demonstrate
their essence and not drown it in whitespace changes.  The
implementation assumes that the caller which registers the gate
(the platform's clock driver) provides both the counter cell and
the lock.  And that all gates with a "shared use counter" use the
same lock (which is satisfied as they all get registered from the
same spot in the platform's clock driver).

The CLK_IGNORE_UNUSED flag addresses a different problem.  The
SoC has four MSCAN components, while two of them are enabled in
the device tree (the other two are present but disabled).  So
during probe two of the clocks get enabled.  After probe all
unused clocks automatically get disabled (that's another two).
So the "shared use counter" drops to zero although components are
in use, because "disable, it's unused" isn't told from "disable
after enable, regular use".  The flag would become obsolete if
the common gate logic would implement a separate disable_unused()
routine, but I guess this isn't necessary and the use of the flag
is appropriate.

That the example use creates a field for just one counter is to
better demonstrate the use and potential extension as need
arises.  Reducing this to a mere integer variable would be a
micro optimization.


The extension of the existing clk_gate implementation:
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -46,6 +46,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 	struct clk_gate *gate = to_clk_gate(hw);
 	int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
 	unsigned long flags = 0;
+	int need_reg_access;
 	u32 reg;
 
 	set ^= enable;
@@ -53,6 +54,20 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 	if (gate->lock)
 		spin_lock_irqsave(gate->lock, flags);
 
+	/*
+	 * if a "shared use counter" was specified, keep track of enable
+	 * and disable calls and only access hardware registers upon the
+	 * very first enable or very last disable call
+	 */
+	if (!gate->share_count) {
+		need_reg_access = 1;
+	} else if (enable) {
+		need_reg_access = (*gate->share_count)++ == 0;
+	} else {
+		need_reg_access = --(*gate->share_count) == 0;
+	}
+
+	if (need_reg_access) {
 		if (gate->flags & CLK_GATE_HIWORD_MASK) {
 			reg = BIT(gate->bit_idx + 16);
 			if (set)
@@ -67,6 +82,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 		}
 
 		clk_writel(reg, gate->reg);
+	}
 
 	if (gate->lock)
 		spin_unlock_irqrestore(gate->lock, flags);
@@ -118,10 +134,11 @@ EXPORT_SYMBOL_GPL(clk_gate_ops);
  * @clk_gate_flags: gate-specific flags for this clock
  * @lock: shared register lock for this clock
  */
-struct clk *clk_register_gate(struct device *dev, const char *name,
+struct clk *clk_register_gate_shared(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 bit_idx,
-		u8 clk_gate_flags, spinlock_t *lock)
+		u8 clk_gate_flags, spinlock_t *lock,
+		int *share_count)
 {
 	struct clk_gate *gate;
 	struct clk *clk;
@@ -152,6 +169,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 	gate->bit_idx = bit_idx;
 	gate->flags = clk_gate_flags;
 	gate->lock = lock;
+	gate->share_count = share_count;
 	gate->hw.init = &init;
 
 	clk = clk_register(dev, &gate->hw);
@@ -161,3 +179,14 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 
 	return clk;
 }
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock)
+{
+
+	return clk_register_gate_shared(dev, name, parent_name, flags,
+					reg, bit_idx, clk_gate_flags,
+					lock, NULL);
+}
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -222,6 +222,7 @@ struct clk_gate {
 	u8		bit_idx;
 	u8		flags;
 	spinlock_t	*lock;
+	int		*share_count;
 };
 
 #define CLK_GATE_SET_TO_DISABLE		BIT(0)
@@ -232,6 +233,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 bit_idx,
 		u8 clk_gate_flags, spinlock_t *lock);
+struct clk *clk_register_gate_shared(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock,
+		int *share_count);
 
 struct clk_div_table {
 	unsigned int	val;

How to use these shared gates:
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -123,6 +123,39 @@ static inline struct clk *mpc512x_clk_gated(
				 reg, pos, 0, &clklock);
 }
 
+enum mpc512x_clk_shared_gate_id_t {
+	MPC512x_CLK_SHARED_GATE_MSCAN,
+	MPC512x_CLK_SHARED_GATE_MAX,
+};
+
+static int mpc512x_clk_gate_counters[MPC512x_CLK_SHARED_GATE_MAX];
+
+/*
+ * implementor's note:  since clk_gate items don't implement a separate
+ * .disable_unused() callback, their .disable() routine gets called and
+ * "disable the clock as we can't see it's in use" cannot be told from
+ * "regular disable, count these events please"
+ *
+ * passing the CLK_IGNORE_UNUSED flag upon clock creation will suppress
+ * the "disable, unused" call, so use counts won't get unbalanced, the
+ * clock either never got enabled and thus need not get disabled, or
+ * part of the hardware got enabled while disabling the other part isn't
+ * wanted
+ */
+static inline struct clk *mpc512x_clk_gated_shared(
+	const char *name, const char *parent_name,
+	u32 __iomem *reg, u8 pos,
+	enum mpc512x_clk_shared_gate_id_t share_id)
+{
+	int clkflags;
+
+	clkflags = CLK_SET_RATE_PARENT;
+	clkflags |= CLK_IGNORE_UNUSED;
+	return clk_register_gate_shared(NULL, name, parent_name, clkflags,
+					reg, pos, 0, &clklock,
+					&mpc512x_clk_gate_counters[share_id]);
+}
+
 static inline struct clk *mpc512x_clk_muxed(const char *name,
	const char **parent_names, int parent_count,
	u32 __iomem *reg, u8 pos, u8 len)
@@ -520,9 +553,16 @@ static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
				1, 1);
	}
	if (sccr_reg) {
+		if (entry->type == MCLK_TYPE_MSCAN) {
+			clks[clks_idx_pub] = mpc512x_clk_gated_shared(
+					entry->name_mclk,
+					entry->name_mux1, sccr_reg, sccr_bit,
+					MPC512x_CLK_SHARED_GATE_MSCAN);
+		} else {
			clks[clks_idx_pub] = mpc512x_clk_gated(
					entry->name_mclk,
					entry->name_mux1, sccr_reg, sccr_bit);
+		}
	} else {
		clks[clks_idx_pub] = mpc512x_clk_factor(
				entry->name_mclk,

Local tests have shown that the extension solves the problem of
how to satisfy the SoC's constraints on the MPC512x platform.
The MSCAN clocks no longer need to get pre-enabled, instead they
get setup and enabled only as the mscan(4) driver probes devices
according to how it was instructed (device tree nodes).

What do you think?  Is the "shared gate" support in the common
logic appropriate?  I'd rather not duplicate all of this code
just to introduce the specific gate I need, while most of the
logic is identical to the existing gate implementation.  The
desire isn't to override the gate's operations, but to wrap them
and to consult a counter in addition, while the register access
still applies.



virtually yours
Gerhard Sittig
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

Re: [PATCH v3 13/31] clk: wrap I/O access for improved portability

From: Mike Turquette <hidden>
Date: 2013-08-02 22:30:00

Quoting Gerhard Sittig (2013-07-22 05:14:40)
the common clock drivers were motivated/initiated by ARM development
and apparently assume little endian peripherals
=
wrap register/peripherals access in the common code (div, gate, mux)
in preparation of adding COMMON_CLK support for other platforms
=
Signed-off-by: Gerhard Sittig <redacted>
I've taken this into clk-next for testing. regmap deserves investigation
but I don't think your series should be blocked on that. We can always
overhaul the basic clock primitives with regmap support later on if that
makes sense.

Regards,
Mike
---
 drivers/clk/clk-divider.c    |    6 +++---
 drivers/clk/clk-gate.c       |    6 +++---
 drivers/clk/clk-mux.c        |    6 +++---
 include/linux/clk-provider.h |   17 +++++++++++++++++
 4 files changed, 26 insertions(+), 9 deletions(-)
=
quoted hunk
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 6d55eb2..2c07061 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct c=
lk_hw *hw,
        struct clk_divider *divider =3D to_clk_divider(hw);
        unsigned int div, val;
 =
-       val =3D readl(divider->reg) >> divider->shift;
+       val =3D clk_readl(divider->reg) >> divider->shift;
        val &=3D div_mask(divider);
 =
quoted hunk
        div =3D _get_div(divider, val);
@@ -230,11 +230,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, =
unsigned long rate,
        if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
                val =3D div_mask(divider) << (divider->shift + 16);
        } else {
-               val =3D readl(divider->reg);
+               val =3D clk_readl(divider->reg);
                val &=3D ~(div_mask(divider) << divider->shift);
        }
        val |=3D value << divider->shift;
-       writel(val, divider->reg);
+       clk_writel(val, divider->reg);
 =
quoted hunk
        if (divider->lock)
                spin_unlock_irqrestore(divider->lock, flags);
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 790306e..b7fbd96 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -58,7 +58,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int e=
nable)
                if (set)
                        reg |=3D BIT(gate->bit_idx);
        } else {
-               reg =3D readl(gate->reg);
+               reg =3D clk_readl(gate->reg);
 =
quoted hunk
                if (set)
                        reg |=3D BIT(gate->bit_idx);
@@ -66,7 +66,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int e=
nable)
                        reg &=3D ~BIT(gate->bit_idx);
        }
 =
-       writel(reg, gate->reg);
+       clk_writel(reg, gate->reg);
 =
quoted hunk
        if (gate->lock)
                spin_unlock_irqrestore(gate->lock, flags);
@@ -89,7 +89,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
        u32 reg;
        struct clk_gate *gate =3D to_clk_gate(hw);
 =
-       reg =3D readl(gate->reg);
+       reg =3D clk_readl(gate->reg);
 =
quoted hunk
        /* if a set bit disables this clk, flip it before masking */
        if (gate->flags & CLK_GATE_SET_TO_DISABLE)
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 614444c..02ef506 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -42,7 +42,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
         * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock,=
 so
         * val =3D 0x4 really means "bit 2, index starts at bit 0"
         */
-       val =3D readl(mux->reg) >> mux->shift;
+       val =3D clk_readl(mux->reg) >> mux->shift;
        val &=3D mux->mask;
 =
quoted hunk
        if (mux->table) {
@@ -89,11 +89,11 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 i=
ndex)
        if (mux->flags & CLK_MUX_HIWORD_MASK) {
                val =3D mux->mask << (mux->shift + 16);
        } else {
-               val =3D readl(mux->reg);
+               val =3D clk_readl(mux->reg);
                val &=3D ~(mux->mask << mux->shift);
        }
        val |=3D index << mux->shift;
-       writel(val, mux->reg);
+       clk_writel(val, mux->reg);
 =
quoted hunk
        if (mux->lock)
                spin_unlock_irqrestore(mux->lock, flags);
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 1ec14a7..c4f7799 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -12,6 +12,7 @@
 #define __LINUX_CLK_PROVIDER_H
 =
 #include <linux/clk.h>
+#include <linux/io.h>
 =
 #ifdef CONFIG_COMMON_CLK
 =
quoted hunk
@@ -490,5 +491,21 @@ static inline const char *of_clk_get_parent_name(str=
uct device_node *np,
 #define of_clk_init(matches) \
        { while (0); }
 #endif /* CONFIG_OF */
+
+/*
+ * wrap access to peripherals in accessor routines
+ * for improved portability across platforms
+ */
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+       return readl(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+       writel(val, reg);
+}
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
-- =
1.7.10.4

Re: [PATCH v3 15/31] dts: mpc512x: introduce dt-bindings/clock/ header

From: Mike Turquette <hidden>
Date: 2013-08-02 22:43:08

Quoting Gerhard Sittig (2013-07-22 05:14:42)
introduce a dt-bindings/ header file for MPC512x clocks,
providing symbolic identifiers for those SoC clocks which
clients will reference from their device tree nodes
=
Signed-off-by: Gerhard Sittig <redacted>
---
 include/dt-bindings/clock/mpc512x-clock.h |   59 +++++++++++++++++++++++=
++++++
 1 file changed, 59 insertions(+)
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h
=
quoted hunk
diff --git a/include/dt-bindings/clock/mpc512x-clock.h b/include/dt-bindi=
ngs/clock/mpc512x-clock.h
quoted hunk
new file mode 100644
index 0000000..46c560e
--- /dev/null
+++ b/include/dt-bindings/clock/mpc512x-clock.h
@@ -0,0 +1,59 @@
+/*
+ * This header provides constants for MPC512x clock specs in DT bindings.
+ *
+ * Unfortunately the clock number declaration cannot be an enum but
+ * needs to be a list of #define directives since when referenced from
+ * within DTS files they need to get resolved "at compile time".
Above comment is not really necessary. Otherwise,

Reviewed-by: Mike Turquette <redacted>
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+
+#define MPC512x_CLK_DUMMY              0
+#define MPC512x_CLK_REF                        1
+#define MPC512x_CLK_SYS                        2
+#define MPC512x_CLK_DIU                        3
+#define MPC512x_CLK_VIU                        4
+#define MPC512x_CLK_CSB                        5
+#define MPC512x_CLK_E300               6
+#define MPC512x_CLK_IPS                        7
+#define MPC512x_CLK_FEC                        8
+#define MPC512x_CLK_SATA               9
+#define MPC512x_CLK_PATA               10
+#define MPC512x_CLK_NFC                        11
+#define MPC512x_CLK_LPC                        12
+#define MPC512x_CLK_MBX_BUS            13
+#define MPC512x_CLK_MBX                        14
+#define MPC512x_CLK_MBX_3D             15
+#define MPC512x_CLK_AXE                        16
+#define MPC512x_CLK_USB1               17
+#define MPC512x_CLK_USB2               18
+#define MPC512x_CLK_I2C                        19
+#define MPC512x_CLK_MSCAN0_MCLK                20
+#define MPC512x_CLK_MSCAN1_MCLK                21
+#define MPC512x_CLK_MSCAN2_MCLK                22
+#define MPC512x_CLK_MSCAN3_MCLK                23
+#define MPC512x_CLK_SDHC               24
+#define MPC512x_CLK_PCI                        25
+#define MPC512x_CLK_PSC_MCLK_IN                26
+#define MPC512x_CLK_SPDIF_TX           27
+#define MPC512x_CLK_SPDIF_RX           28
+#define MPC512x_CLK_SPDIF_MCLK         29
+#define MPC512x_CLK_AC97               30
+#define MPC512x_CLK_PSC0_MCLK          31
+#define MPC512x_CLK_PSC1_MCLK          32
+#define MPC512x_CLK_PSC2_MCLK          33
+#define MPC512x_CLK_PSC3_MCLK          34
+#define MPC512x_CLK_PSC4_MCLK          35
+#define MPC512x_CLK_PSC5_MCLK          36
+#define MPC512x_CLK_PSC6_MCLK          37
+#define MPC512x_CLK_PSC7_MCLK          38
+#define MPC512x_CLK_PSC8_MCLK          39
+#define MPC512x_CLK_PSC9_MCLK          40
+#define MPC512x_CLK_PSC10_MCLK         41
+#define MPC512x_CLK_PSC11_MCLK         42
+#define MPC512x_CLK_PSC_FIFO           43
+
+#define MPC512x_CLK_LAST_PUBLIC                43
+
+#endif
-- =
1.7.10.4

Re: [PATCH v3 16/31] dts: mpc512x: add clock related device tree specs

From: Mike Turquette <hidden>
Date: 2013-08-02 22:46:13

Quoting Gerhard Sittig (2013-07-22 05:14:43)
this addresses the clock driver aka provider's side of clocks
- prepare for future '<&clks ID>' phandle references for device tree
  based clock lookup in client drivers
- introduce a 'clocks' subtree with an 'osc' node for the crystal
  or oscillator SoC input (fixed frequency)
- provide default values with 33MHz oscillator frequency in the
  common include (the 66MHz IPS bus already was there), add
  override values for the ifm AC14xx board which deviates from
  the reference design (25MHz xtal, 80MHz IPS bus)
=
Signed-off-by: Gerhard Sittig <redacted>
Reviewed-by: Mike Turquette <redacted>
---
 arch/powerpc/boot/dts/ac14xx.dts   |    7 +++++++
 arch/powerpc/boot/dts/mpc5121.dtsi |   15 ++++++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)
=
quoted hunk
diff --git a/arch/powerpc/boot/dts/ac14xx.dts b/arch/powerpc/boot/dts/ac1=
4xx.dts
quoted hunk
index a543c40..a1b8837 100644
--- a/arch/powerpc/boot/dts/ac14xx.dts
+++ b/arch/powerpc/boot/dts/ac14xx.dts
@@ -139,7 +139,14 @@
                };
        };
 =
+       clocks {
+               osc {
+                       clock-frequency =3D <25000000>;
+               };
+       };
+
        soc@80000000 {
+               bus-frequency =3D <80000000>;     /* 80 MHz ips bus */
 =
                clock@f00 {
                        compatible =3D "fsl,mpc5121rev2-clock", "fsl,mpc5=
121-clock";
quoted hunk
diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/m=
pc5121.dtsi
quoted hunk
index bd14c00..8f4cba0 100644
--- a/arch/powerpc/boot/dts/mpc5121.dtsi
+++ b/arch/powerpc/boot/dts/mpc5121.dtsi
@@ -9,6 +9,8 @@
  * option) any later version.
  */
 =
+#include <dt-bindings/clock/mpc512x-clock.h>
+
 /dts-v1/;
 =
quoted hunk
 / {
@@ -73,6 +75,16 @@
                ranges =3D <0x0 0x0 0xfc000000 0x04000000>;
        };
 =
quoted hunk
+       clocks {
+               #address-cells =3D <1>;
+               #size-cells =3D <0>;
+
+               osc {
+                       compatible =3D "fsl,mpc512x-osc", "fixed-clock";
+                       clock-frequency =3D <33000000>;
+               };
+       };
+
        soc@80000000 {
                compatible =3D "fsl,mpc5121-immr";
                #address-cells =3D <1>;
@@ -118,9 +130,10 @@
                };
 =
                /* Clock control */
-               clock@f00 {
+               clks: clock@f00 {
                        compatible =3D "fsl,mpc5121-clock";
                        reg =3D <0xf00 0x100>;
+                       #clock-cells =3D <1>;
                };
 =
                /* Power Management Controller */
-- =
1.7.10.4

[PATCH v3 17/31] clk: mpc512x: introduce COMMON_CLK for MPC512x

From: Mike Turquette <hidden>
Date: 2013-08-02 23:30:09

Quoting Gerhard Sittig (2013-07-23 06:14:06)
[ summary: "shared gate" support desirable? approach acceptable? ]
=
On Mon, Jul 22, 2013 at 14:14 +0200, Gerhard Sittig wrote:
quoted
=
quoted
this change implements a clock driver for the MPC512x PowerPC platform
which follows the COMMON_CLK approach and uses common clock drivers
shared with other platforms
=
quoted
[ ... ]
=
quoted
some of the clock items get pre-enabled in the clock driver to not have
them automatically disabled by the underlying clock subsystem because of
their being unused -- this approach is desirable because
[ ... ]
- some help introduce support for and migrate to the common
  infrastructure, while more appropriate support for specific hardware
  constraints isn't available yet (remaining changes are strictly
  internal to the clock driver and won't affect peripheral drivers)
=
This remark was related to the CAN clocks of the MPC512x SoC.
Gerhard,

Thanks for the patch (way far down below here). I'll check into it to
see if that implementation looks OK. It would be helpful if another
platform with shared gates could weigh in on whether the implementation
works for them.

Still, a shared gate solution is not a prerequisite for this series,
correct?

Regards,
Mike
=
The clock subtrees which are involved in generating CAN bitrates
include one path from the XTAL to an internal MCLK (this is part
of the CCF support for the platform), and another path from the
MCLK or yet another IP bus clock to the actual bitrate on the
wire (this is taken care of within the mscan(4) driver).
=
The MCLK generation for CAN is documented in the MPC5121e
Reference Manual, chapter 5, section 5.2.5 "MSCAN Clock
Generation".  SYS, REF (both internal), PSC_MCLK_IN, and SPDIF_TX
(both external) are muxed, gated, and divided.  The result is
muxed with IP.  The result is fed into the MSCAN component and
gets muxed with IP again (can't tell why, maybe for backwards
compatibility).
=
In parallel to this MCLK block there is SCCR2[25], the "BDLC and
MSCAN clock enable", documented in section 5.3.1.3 "System Clock
Control Register 2".  So there is a gate that "somehow needs to
get setup" yet isn't part of the visible MCLK chain.
=
The series up to and including v3 approaches the problem by
- adding a gate after the second MCLK mux, which gets exported
  for client lookups and is the MCLK input for the mscan(4)
  driver
- creating that gate for each of the four MSCAN clocks of the
  SoC, all of them referencing the single "enable" bit in the
  SCCR2 register
- pre-enabling the MSCAN clocks from within the clock driver, and
  thus avoid having the clock disabled from the common
  infrastructure, because disabling one of these clocks had
  closed the shared gate and thus had broken all other clock uses
=
quoted
clkdev registration provides "alias names" for few clock items
[ ... ]
=
[ ... ]
quoted
+
+/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
+static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
+{
+     size_t clks_idx_pub, clks_idx_int;
+     u32 __iomem *mccr_reg;  /* MCLK control register (mux, en, div) */
+     u32 __iomem *sccr_reg;  /* system clock control register (enable)=
 */
quoted
+     int sccr_bit;
+     int div;
+
+     /* derive a few parameters from the component type and index */
+     switch (entry->type) {
+     case MCLK_TYPE_PSC:
+             clks_idx_pub =3D MPC512x_CLK_PSC0_MCLK + entry->comp_idx;
+             clks_idx_int =3D MPC512x_CLK_MCLKS_FIRST
+                          + (entry->comp_idx) * MCLK_MAX_IDX;
+             mccr_reg =3D &clkregs->psc_ccr[entry->comp_idx];
+             break;
+     case MCLK_TYPE_MSCAN:
+             clks_idx_pub =3D MPC512x_CLK_MSCAN0_MCLK + entry->comp_id=
x;
quoted
+             clks_idx_int =3D MPC512x_CLK_MCLKS_FIRST
+                          + (NR_PSCS + entry->comp_idx) * MCLK_MAX_IDX;
+             mccr_reg =3D &clkregs->mscan_ccr[entry->comp_idx];
+             break;
+     case MCLK_TYPE_SPDIF:
+             clks_idx_pub =3D MPC512x_CLK_SPDIF_MCLK;
+             clks_idx_int =3D MPC512x_CLK_MCLKS_FIRST
+                          + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
+             mccr_reg =3D &clkregs->spccr;
+             break;
+     default:
+             return;
+     }
+     if (entry->bit_sccr1 >=3D 0) {
+             sccr_reg =3D &clkregs->sccr1;
+             sccr_bit =3D entry->bit_sccr1;
+     } else if (entry->bit_sccr2 >=3D 0) {
+             sccr_reg =3D &clkregs->sccr2;
+             sccr_bit =3D entry->bit_sccr2;
+     } else {
+             sccr_reg =3D NULL;
+     }
+
+     /*
+      * this was grabbed from the PPC_CLOCK implementation, which
+      * enforced a specific MCLK divider while the clock was gated
+      * during setup (that's a documented hardware requirement)
+      *
+      * the PPC_CLOCK implementation might even have violated the
+      * "MCLK <=3D IPS" constraint, the fixed divider value of 1
+      * results in a divider of 2 and thus MCLK =3D SYS/2 which equals
+      * CSB which is greater than IPS; the serial port setup may have
+      * adjusted the divider which the clock setup might have left in
+      * an undesirable state
+      *
+      * initial setup is:
+      * - MCLK 0 from SYS
+      * - MCLK DIV such to not exceed the IPS clock
+      * - MCLK 0 enabled
+      * - MCLK 1 from MCLK DIV
+      */
+     div =3D clk_get_rate(clks[MPC512x_CLK_SYS]);
+     div /=3D clk_get_rate(clks[MPC512x_CLK_IPS]);
+     out_be32(mccr_reg, (0 << 16));
+     out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
+     out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
+
+     /*
+      * create the 'struct clk' items of the MCLK's clock subtree
+      *
+      * note that by design we always create all nodes and won't take
+      * shortcuts here, because
+      * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
+      *   selectable inputs to the CFM while those who "actually use"
+      *   the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
+      *   for their bitrate
+      * - in the absence of "aliases" for clocks we need to create
+      *   individial 'struct clk' items for whatever might get
+      *   referenced or looked up, even if several of those items are
+      *   identical from the logical POV (their rate value)
+      * - for easier future maintenance and for better reflection of
+      *   the SoC's documentation, it appears appropriate to generate
+      *   clock items even for those muxers which actually are NOPs
+      *   (those with two inputs of which one is reserved)
+      */
+     clks[clks_idx_int + MCLK_IDX_MUX0] =3D mpc512x_clk_muxed(
+                     entry->name_mux0,
+                     &parent_names_mux0[0], ARRAY_SIZE(parent_names_mu=
x0),
quoted
+                     mccr_reg, 14, 2);
+     clks[clks_idx_int + MCLK_IDX_EN0] =3D mpc512x_clk_gated(
+                     entry->name_en0, entry->name_mux0,
+                     mccr_reg, 16);
+     clks[clks_idx_int + MCLK_IDX_DIV0] =3D mpc512x_clk_divider(
+                     entry->name_div0,
+                     entry->name_en0, CLK_SET_RATE_GATE,
+                     mccr_reg, 17, 15, 0);
+     if (entry->has_mclk1) {
+             clks[clks_idx_int + MCLK_IDX_MUX1] =3D mpc512x_clk_muxed(
+                             entry->name_mux1,
+                             &entry->parent_names_mux1[0],
+                             ARRAY_SIZE(entry->parent_names_mux1),
+                             mccr_reg, 7, 1);
+     } else {
+             clks[clks_idx_int + MCLK_IDX_MUX1] =3D mpc512x_clk_factor(
+                             entry->name_mux1, entry->parent_names_mux=
1[0],
quoted
+                             1, 1);
+     }
+     if (sccr_reg) {
+             clks[clks_idx_pub] =3D mpc512x_clk_gated(
+                             entry->name_mclk,
+                             entry->name_mux1, sccr_reg, sccr_bit);
+     } else {
+             clks[clks_idx_pub] =3D mpc512x_clk_factor(
+                             entry->name_mclk,
+                             entry->name_mux1, 1, 1);
+     }
+
+     /*
+      * without this "clock device" registration, "simple" lookups in
+      * the SPI master initialization and serial port setup will fail
+      *
+      * those drivers need to get adjusted to lookup their required
+      * clocks from device tree specs, and device tree nodes need to
+      * provide the clock specs, before this clkdev registration
+      * becomes obsolete
+      */
+     clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
+}
[ ... ]
=
This was the routine which sets up _one_ MCLK block, note the
assignment at the routine's end to the "published" clock item
that's the gate's output after the second mux stage.
=
quoted
[ ... ]
+     clks[MPC512x_CLK_I2C] =3D mpc512x_clk_gated("i2c", "ips",
+                                               &clkregs->sccr2, 26);
+     mpc512x_clk_setup_mclks(mclk_mscan_data, ARRAY_SIZE(mclk_mscan_da=
ta));
quoted
+     clks[MPC512x_CLK_SDHC] =3D mpc512x_clk_gated("sdhc", "sdhc-ug",
+                                                &clkregs->sccr2, 24);
+     mpc512x_clk_setup_mclks(mclk_spdif_data, ARRAY_SIZE(mclk_spdif_da=
ta));
quoted
[ ... ]
=
This is the invocation of the routine which sets up four MCLK
blocks for the MSCAN components, while all of them refer to bit
25 of SCCR2.
=
quoted
[ ... ]
+
+     /* enable some of the clocks here unconditionally because ... */
+     pr_debug("automatically enabling some clocks\n");
+     /* some are essential yet never get claimed by any driver */
+     clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
+     clk_prepare_enable(clks[MPC512x_CLK_E300]);     /* PowerPC CPU */
+     clk_prepare_enable(clks[MPC512x_CLK_DDR]);      /* DRAM */
+     clk_prepare_enable(clks[MPC512x_CLK_MEM]);      /* SRAM */
+     clk_prepare_enable(clks[MPC512x_CLK_IPS]);      /* SoC periph */
+     clk_prepare_enable(clks[MPC512x_CLK_LPC]);      /* boot media */
+     /* some are required yet no dependencies were declared */
+     clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
+     /* some are not yet acquired by their respective drivers */
+     clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console=
 */
quoted
+     clk_prepare_enable(clks[MPC512x_CLK_FEC]);      /* network, NFS */
+     clk_prepare_enable(clks[MPC512x_CLK_DIU]);      /* display */
+     clk_prepare_enable(clks[MPC512x_CLK_I2C]);
+     /*
+      * some have their individual clock subtree with separate clock
+      * items and their individual enable counters, yet share a
+      * common gate (refer to the same register location) while the
+      * common clock driver code is not aware of the fact and the
+      * platform's code doesn't provide specific support either
+      *
+      * what might happen is that e.g. enabling two MSCAN clock items
+      * and disabling one of them will disable the common gate and
+      * thus break the other MSCAN clock as well
+      */
+     clk_prepare_enable(clks[MPC512x_CLK_MSCAN0_MCLK]);
+     clk_prepare_enable(clks[MPC512x_CLK_MSCAN1_MCLK]);
+     clk_prepare_enable(clks[MPC512x_CLK_MSCAN2_MCLK]);
+     clk_prepare_enable(clks[MPC512x_CLK_MSCAN3_MCLK]);
+}
=
This is the pre-enable workaround for the MSCAN0 to MSCAN3 clock
items.
=
The above approach does work in that it introduces complete
support for common clock on the MPC512x platform, with the CAN
component being operational, and the clock driver using shared
logic across platforms.
=
The remaining issue is that regardless of whether CAN is used,
the (chip internal) clock is enabled.  This may not be a problem
when bitrates aren't generated and the wire isn't driven.
=
=
The question now is how to correctly support the situation where
a gate is shared between subtrees yet isn't really part of any
path within the subtrees.  I really cannot find a single spot
where to introduce the gate such that it's not duplicated.
=
The appropriate solution would not be to pre-enable those clocks,
but to either introduce another gate clock type which supports a
shared reference, or to add support for the shared reference to
the existing gate code.
=
=
I'd rather not duplicate most or all of the code of clk-gate.c,
instead I looked into how to add "shared gate" support to the
existing driver.
=
My question is whether the approach is acceptable.  It adds
minimal overhead and shall be OK for the enable/disable path from
a technical POV.  And it doesn't feel like too much of a stretch.
But there may be non-technical reasons to reject the approach.
I'd like to learn whether to follow that path before preparing
another version of the patch series.
=
The diffs were taken with the '-w -b' options to demonstrate
their essence and not drown it in whitespace changes.  The
implementation assumes that the caller which registers the gate
(the platform's clock driver) provides both the counter cell and
the lock.  And that all gates with a "shared use counter" use the
same lock (which is satisfied as they all get registered from the
same spot in the platform's clock driver).
=
The CLK_IGNORE_UNUSED flag addresses a different problem.  The
SoC has four MSCAN components, while two of them are enabled in
the device tree (the other two are present but disabled).  So
during probe two of the clocks get enabled.  After probe all
unused clocks automatically get disabled (that's another two).
So the "shared use counter" drops to zero although components are
in use, because "disable, it's unused" isn't told from "disable
after enable, regular use".  The flag would become obsolete if
the common gate logic would implement a separate disable_unused()
routine, but I guess this isn't necessary and the use of the flag
is appropriate.
=
That the example use creates a field for just one counter is to
better demonstrate the use and potential extension as need
arises.  Reducing this to a mere integer variable would be a
micro optimization.
=
=
The extension of the existing clk_gate implementation:
=
quoted hunk
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -46,6 +46,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int e=
nable)
        struct clk_gate *gate =3D to_clk_gate(hw);
        int set =3D gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
        unsigned long flags =3D 0;
+       int need_reg_access;
        u32 reg;
 =
quoted hunk
        set ^=3D enable;
@@ -53,6 +54,20 @@ static void clk_gate_endisable(struct clk_hw *hw, int =
enable)
        if (gate->lock)
                spin_lock_irqsave(gate->lock, flags);
 =
quoted hunk
+       /*
+        * if a "shared use counter" was specified, keep track of enable
+        * and disable calls and only access hardware registers upon the
+        * very first enable or very last disable call
+        */
+       if (!gate->share_count) {
+               need_reg_access =3D 1;
+       } else if (enable) {
+               need_reg_access =3D (*gate->share_count)++ =3D=3D 0;
+       } else {
+               need_reg_access =3D --(*gate->share_count) =3D=3D 0;
+       }
+
+       if (need_reg_access) {
                if (gate->flags & CLK_GATE_HIWORD_MASK) {
                        reg =3D BIT(gate->bit_idx + 16);
                        if (set)
@@ -67,6 +82,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int e=
nable)
                }
 =
                clk_writel(reg, gate->reg);
+       }
 =
quoted hunk
        if (gate->lock)
                spin_unlock_irqrestore(gate->lock, flags);
@@ -118,10 +134,11 @@ EXPORT_SYMBOL_GPL(clk_gate_ops);
  * @clk_gate_flags: gate-specific flags for this clock
  * @lock: shared register lock for this clock
  */
-struct clk *clk_register_gate(struct device *dev, const char *name,
+struct clk *clk_register_gate_shared(struct device *dev, const char *nam=
e,
quoted hunk
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
-               u8 clk_gate_flags, spinlock_t *lock)
+               u8 clk_gate_flags, spinlock_t *lock,
+               int *share_count)
 {
        struct clk_gate *gate;
        struct clk *clk;
@@ -152,6 +169,7 @@ struct clk *clk_register_gate(struct device *dev, con=
st char *name,
        gate->bit_idx =3D bit_idx;
        gate->flags =3D clk_gate_flags;
        gate->lock =3D lock;
+       gate->share_count =3D share_count;
        gate->hw.init =3D &init;
 =
quoted hunk
        clk =3D clk_register(dev, &gate->hw);
@@ -161,3 +179,14 @@ struct clk *clk_register_gate(struct device *dev, co=
nst char *name,
 =
quoted hunk
        return clk;
 }
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 bit_idx,
+               u8 clk_gate_flags, spinlock_t *lock)
+{
+
+       return clk_register_gate_shared(dev, name, parent_name, flags,
+                                       reg, bit_idx, clk_gate_flags,
+                                       lock, NULL);
+}
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -222,6 +222,7 @@ struct clk_gate {
        u8              bit_idx;
        u8              flags;
        spinlock_t      *lock;
+       int             *share_count;
 };
 =
quoted hunk
 #define CLK_GATE_SET_TO_DISABLE                BIT(0)
@@ -232,6 +233,11 @@ struct clk *clk_register_gate(struct device *dev, co=
nst char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
                u8 clk_gate_flags, spinlock_t *lock);
+struct clk *clk_register_gate_shared(struct device *dev, const char *nam=
e,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 bit_idx,
+               u8 clk_gate_flags, spinlock_t *lock,
+               int *share_count);
 =
 struct clk_div_table {
        unsigned int    val;
=
=
How to use these shared gates:
=
quoted hunk
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -123,6 +123,39 @@ static inline struct clk *mpc512x_clk_gated(
                                 reg, pos, 0, &clklock);
 }
 =
+enum mpc512x_clk_shared_gate_id_t {
+       MPC512x_CLK_SHARED_GATE_MSCAN,
+       MPC512x_CLK_SHARED_GATE_MAX,
+};
+
+static int mpc512x_clk_gate_counters[MPC512x_CLK_SHARED_GATE_MAX];
+
+/*
+ * implementor's note:  since clk_gate items don't implement a separate
+ * .disable_unused() callback, their .disable() routine gets called and
+ * "disable the clock as we can't see it's in use" cannot be told from
+ * "regular disable, count these events please"
+ *
+ * passing the CLK_IGNORE_UNUSED flag upon clock creation will suppress
+ * the "disable, unused" call, so use counts won't get unbalanced, the
+ * clock either never got enabled and thus need not get disabled, or
+ * part of the hardware got enabled while disabling the other part isn't
+ * wanted
+ */
+static inline struct clk *mpc512x_clk_gated_shared(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos,
+       enum mpc512x_clk_shared_gate_id_t share_id)
+{
+       int clkflags;
+
+       clkflags =3D CLK_SET_RATE_PARENT;
+       clkflags |=3D CLK_IGNORE_UNUSED;
+       return clk_register_gate_shared(NULL, name, parent_name, clkflags,
+                                       reg, pos, 0, &clklock,
+                                       &mpc512x_clk_gate_counters[share_=
id]);
quoted hunk
+}
+
 static inline struct clk *mpc512x_clk_muxed(const char *name,
        const char **parent_names, int parent_count,
        u32 __iomem *reg, u8 pos, u8 len)
@@ -520,9 +553,16 @@ static void mpc512x_clk_setup_mclk(struct mclk_setup=
_data *entry)
                                1, 1);
        }
        if (sccr_reg) {
+               if (entry->type =3D=3D MCLK_TYPE_MSCAN) {
+                       clks[clks_idx_pub] =3D mpc512x_clk_gated_shared(
+                                       entry->name_mclk,
+                                       entry->name_mux1, sccr_reg, sccr_=
bit,
+                                       MPC512x_CLK_SHARED_GATE_MSCAN);
+               } else {
                        clks[clks_idx_pub] =3D mpc512x_clk_gated(
                                        entry->name_mclk,
                                        entry->name_mux1, sccr_reg, sccr_=
bit);
+               }
        } else {
                clks[clks_idx_pub] =3D mpc512x_clk_factor(
                                entry->name_mclk,
=
Local tests have shown that the extension solves the problem of
how to satisfy the SoC's constraints on the MPC512x platform.
The MSCAN clocks no longer need to get pre-enabled, instead they
get setup and enabled only as the mscan(4) driver probes devices
according to how it was instructed (device tree nodes).
=
What do you think?  Is the "shared gate" support in the common
logic appropriate?  I'd rather not duplicate all of this code
just to introduce the specific gate I need, while most of the
logic is identical to the existing gate implementation.  The
desire isn't to override the gate's operations, but to wrap them
and to consult a counter in addition, while the register access
still applies.
=
=
=
virtually yours
Gerhard Sittig
-- =
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

Re: [PATCH v3 18/31] dts: mpc512x: add clock specs for client lookups

From: Mike Turquette <hidden>
Date: 2013-08-02 23:41:20

Quoting Gerhard Sittig (2013-07-22 05:14:45)
this addresses the client side of device tree based clock lookups
=
add clock specifiers to the mbx, nfc, mscan, sdhc, i2c, axe, diu, viu,
mdio, fec, usb, pata, psc, psc fifo, and pci nodes in the shared
mpc5121.dtsi include
=
these specs map 'clock-names' encoded in drivers to their respective
'struct clk' items in the platform's clock driver
=
Signed-off-by: Gerhard Sittig <redacted>
Reviewed-by: Mike Turquette <redacted>
---
 arch/powerpc/boot/dts/mpc5121.dtsi |   79 ++++++++++++++++++++++++++++++=
++++++
 1 file changed, 79 insertions(+)
=
quoted hunk
diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/m=
pc5121.dtsi
quoted hunk
index 8f4cba0..3657ae6 100644
--- a/arch/powerpc/boot/dts/mpc5121.dtsi
+++ b/arch/powerpc/boot/dts/mpc5121.dtsi
@@ -51,6 +51,10 @@
                compatible =3D "fsl,mpc5121-mbx";
                reg =3D <0x20000000 0x4000>;
                interrupts =3D <66 0x8>;
+               clocks =3D <&clks MPC512x_CLK_MBX_BUS>,
+                        <&clks MPC512x_CLK_MBX_3D>,
+                        <&clks MPC512x_CLK_MBX>;
+               clock-names =3D "mbx-bus", "mbx-3d", "mbx";
        };
 =
quoted hunk
        sram@30000000 {
@@ -64,6 +68,8 @@
                interrupts =3D <6 8>;
                #address-cells =3D <1>;
                #size-cells =3D <1>;
+               clocks =3D <&clks MPC512x_CLK_NFC>;
+               clock-names =3D "per";
        };
 =
quoted hunk
        localbus@80000020 {
@@ -153,12 +159,22 @@
                        compatible =3D "fsl,mpc5121-mscan";
                        reg =3D <0x1300 0x80>;
                        interrupts =3D <12 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN0_MCLK>;
+                       clock-names =3D "ips", "sys", "ref", "mclk";
                };
 =
                can@1380 {
                        compatible =3D "fsl,mpc5121-mscan";
                        reg =3D <0x1380 0x80>;
                        interrupts =3D <13 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN1_MCLK>;
+                       clock-names =3D "ips", "sys", "ref", "mclk";
                };
 =
quoted hunk
                sdhc@1500 {
@@ -167,6 +183,9 @@
                        interrupts =3D <8 0x8>;
                        dmas =3D <&dma0 30>;
                        dma-names =3D "rx-tx";
+                       clocks =3D <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SDHC>;
+                       clock-names =3D "ipg", "per";
                };
 =
quoted hunk
                i2c@1700 {
@@ -175,6 +194,8 @@
                        compatible =3D "fsl,mpc5121-i2c", "fsl-i2c";
                        reg =3D <0x1700 0x20>;
                        interrupts =3D <9 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_I2C>;
+                       clock-names =3D "per";
                };
 =
quoted hunk
                i2c@1720 {
@@ -183,6 +204,8 @@
                        compatible =3D "fsl,mpc5121-i2c", "fsl-i2c";
                        reg =3D <0x1720 0x20>;
                        interrupts =3D <10 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_I2C>;
+                       clock-names =3D "per";
                };
 =
quoted hunk
                i2c@1740 {
@@ -191,6 +214,8 @@
                        compatible =3D "fsl,mpc5121-i2c", "fsl-i2c";
                        reg =3D <0x1740 0x20>;
                        interrupts =3D <11 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_I2C>;
+                       clock-names =3D "per";
                };
 =
quoted hunk
                i2ccontrol@1760 {
@@ -202,30 +227,46 @@
                        compatible =3D "fsl,mpc5121-axe";
                        reg =3D <0x2000 0x100>;
                        interrupts =3D <42 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_AXE>;
+                       clock-names =3D "per";
                };
 =
                display@2100 {
                        compatible =3D "fsl,mpc5121-diu";
                        reg =3D <0x2100 0x100>;
                        interrupts =3D <64 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_DIU>;
+                       clock-names =3D "per";
                };
 =
                can@2300 {
                        compatible =3D "fsl,mpc5121-mscan";
                        reg =3D <0x2300 0x80>;
                        interrupts =3D <90 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN2_MCLK>;
+                       clock-names =3D "ips", "sys", "ref", "mclk";
                };
 =
                can@2380 {
                        compatible =3D "fsl,mpc5121-mscan";
                        reg =3D <0x2380 0x80>;
                        interrupts =3D <91 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN3_MCLK>;
+                       clock-names =3D "ips", "sys", "ref", "mclk";
                };
 =
                viu@2400 {
                        compatible =3D "fsl,mpc5121-viu";
                        reg =3D <0x2400 0x400>;
                        interrupts =3D <67 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_VIU>;
+                       clock-names =3D "per";
                };
 =
quoted hunk
                mdio@2800 {
@@ -233,6 +274,8 @@
                        reg =3D <0x2800 0x800>;
                        #address-cells =3D <1>;
                        #size-cells =3D <0>;
+                       clocks =3D <&clks MPC512x_CLK_FEC>;
+                       clock-names =3D "per";
                };
 =
quoted hunk
                eth0: ethernet@2800 {
@@ -241,6 +284,8 @@
                        reg =3D <0x2800 0x800>;
                        local-mac-address =3D [ 00 00 00 00 00 00 ];
                        interrupts =3D <4 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_FEC>;
+                       clock-names =3D "per";
                };
 =
quoted hunk
                /* USB1 using external ULPI PHY */
@@ -252,6 +297,8 @@
                        interrupts =3D <43 0x8>;
                        dr_mode =3D "otg";
                        phy_type =3D "ulpi";
+                       clocks =3D <&clks MPC512x_CLK_USB1>;
+                       clock-names =3D "per";
                };
 =
quoted hunk
                /* USB0 using internal UTMI PHY */
@@ -263,6 +310,8 @@
                        interrupts =3D <44 0x8>;
                        dr_mode =3D "otg";
                        phy_type =3D "utmi_wide";
+                       clocks =3D <&clks MPC512x_CLK_USB2>;
+                       clock-names =3D "per";
                };
 =
quoted hunk
                /* IO control */
@@ -281,6 +330,8 @@
                        compatible =3D "fsl,mpc5121-pata";
                        reg =3D <0x10200 0x100>;
                        interrupts =3D <5 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_PATA>;
+                       clock-names =3D "per";
                };
 =
quoted hunk
                /* 512x PSCs are not 52xx PSC compatible */
@@ -292,6 +343,8 @@
                        interrupts =3D <40 0x8>;
                        fsl,rx-fifo-size =3D <16>;
                        fsl,tx-fifo-size =3D <16>;
+                       clocks =3D <&clks MPC512x_CLK_PSC0_MCLK>;
+                       clock-names =3D "mclk";
                };
 =
quoted hunk
                /* PSC1 */
@@ -301,6 +354,8 @@
                        interrupts =3D <40 0x8>;
                        fsl,rx-fifo-size =3D <16>;
                        fsl,tx-fifo-size =3D <16>;
+                       clocks =3D <&clks MPC512x_CLK_PSC1_MCLK>;
+                       clock-names =3D "mclk";
                };
 =
quoted hunk
                /* PSC2 */
@@ -310,6 +365,8 @@
                        interrupts =3D <40 0x8>;
                        fsl,rx-fifo-size =3D <16>;
                        fsl,tx-fifo-size =3D <16>;
+                       clocks =3D <&clks MPC512x_CLK_PSC2_MCLK>;
+                       clock-names =3D "mclk";
                };
 =
quoted hunk
                /* PSC3 */
@@ -319,6 +376,8 @@
                        interrupts =3D <40 0x8>;
                        fsl,rx-fifo-size =3D <16>;
                        fsl,tx-fifo-size =3D <16>;
+                       clocks =3D <&clks MPC512x_CLK_PSC3_MCLK>;
+                       clock-names =3D "mclk";
                };
 =
quoted hunk
                /* PSC4 */
@@ -328,6 +387,8 @@
                        interrupts =3D <40 0x8>;
                        fsl,rx-fifo-size =3D <16>;
                        fsl,tx-fifo-size =3D <16>;
+                       clocks =3D <&clks MPC512x_CLK_PSC4_MCLK>;
+                       clock-names =3D "mclk";
                };
 =
quoted hunk
                /* PSC5 */
@@ -337,6 +398,8 @@
                        interrupts =3D <40 0x8>;
                        fsl,rx-fifo-size =3D <16>;
                        fsl,tx-fifo-size =3D <16>;
+                       clocks =3D <&clks MPC512x_CLK_PSC5_MCLK>;
+                       clock-names =3D "mclk";
                };
 =
quoted hunk
                /* PSC6 */
@@ -346,6 +409,8 @@
                        interrupts =3D <40 0x8>;
                        fsl,rx-fifo-size =3D <16>;
                        fsl,tx-fifo-size =3D <16>;
+                       clocks =3D <&clks MPC512x_CLK_PSC6_MCLK>;
+                       clock-names =3D "mclk";
                };
 =
quoted hunk
                /* PSC7 */
@@ -355,6 +420,8 @@
                        interrupts =3D <40 0x8>;
                        fsl,rx-fifo-size =3D <16>;
                        fsl,tx-fifo-size =3D <16>;
+                       clocks =3D <&clks MPC512x_CLK_PSC7_MCLK>;
+                       clock-names =3D "mclk";
                };
 =
quoted hunk
                /* PSC8 */
@@ -364,6 +431,8 @@
                        interrupts =3D <40 0x8>;
                        fsl,rx-fifo-size =3D <16>;
                        fsl,tx-fifo-size =3D <16>;
+                       clocks =3D <&clks MPC512x_CLK_PSC8_MCLK>;
+                       clock-names =3D "mclk";
                };
 =
quoted hunk
                /* PSC9 */
@@ -373,6 +442,8 @@
                        interrupts =3D <40 0x8>;
                        fsl,rx-fifo-size =3D <16>;
                        fsl,tx-fifo-size =3D <16>;
+                       clocks =3D <&clks MPC512x_CLK_PSC9_MCLK>;
+                       clock-names =3D "mclk";
                };
 =
quoted hunk
                /* PSC10 */
@@ -382,6 +453,8 @@
                        interrupts =3D <40 0x8>;
                        fsl,rx-fifo-size =3D <16>;
                        fsl,tx-fifo-size =3D <16>;
+                       clocks =3D <&clks MPC512x_CLK_PSC10_MCLK>;
+                       clock-names =3D "mclk";
                };
 =
quoted hunk
                /* PSC11 */
@@ -391,12 +464,16 @@
                        interrupts =3D <40 0x8>;
                        fsl,rx-fifo-size =3D <16>;
                        fsl,tx-fifo-size =3D <16>;
+                       clocks =3D <&clks MPC512x_CLK_PSC11_MCLK>;
+                       clock-names =3D "mclk";
                };
 =
                pscfifo@11f00 {
                        compatible =3D "fsl,mpc5121-psc-fifo";
                        reg =3D <0x11f00 0x100>;
                        interrupts =3D <40 0x8>;
+                       clocks =3D <&clks MPC512x_CLK_PSC_FIFO>;
+                       clock-names =3D "per";
                };
 =
quoted hunk
                dma0: dma@14000 {
@@ -414,6 +491,8 @@
                #address-cells =3D <3>;
                #size-cells =3D <2>;
                #interrupt-cells =3D <1>;
+               clocks =3D <&clks MPC512x_CLK_PCI>;
+               clock-names =3D "per";
 =
                reg =3D <0x80008500 0x100 /* internal registers */
                       0x80008300 0x8>; /* config space access registers =
*/
-- =
1.7.10.4

Re: [PATCH v3 17/31] clk: mpc512x: introduce COMMON_CLK for MPC512x

From: Mike Turquette <hidden>
Date: 2013-08-02 23:41:43

Quoting Gerhard Sittig (2013-07-22 05:14:44)
this change implements a clock driver for the MPC512x PowerPC platform
which follows the COMMON_CLK approach and uses common clock drivers
shared with other platforms
=
this driver implements the publicly announced set of clocks (which can
get referenced by means of symbolic identifiers from the dt-bindings
header file), as well as generates additional 'struct clk' items where
the SoC hardware cannot easily get mapped to the common primitives of
the clock API, or requires "intermediate" clock nodes to represent
clocks that have both gates and dividers
=
the previous PPC_CLOCK implementation is kept in place and remains in
parallel to the common clock implementation for test and comparison
during migration, a compile time option picks one of the two
alternatives (Kconfig switch, common clock used by default)
=
some of the clock items get pre-enabled in the clock driver to not have
them automatically disabled by the underlying clock subsystem because of
their being unused -- this approach is desirable because
- some of the clocks are useful to have for diagnostics and information
  despite their not getting claimed by any drivers (CPU, internal and
  external RAM, internal busses, boot media)
- some of the clocks aren't claimed by their peripheral drivers yet,
  either because of missing driver support or because device tree specs
  aren't available yet (but the workarounds will get removed as the
  drivers get adjusted and the device tree provides the clock specs)
- some help introduce support for and migrate to the common
  infrastructure, while more appropriate support for specific hardware
  constraints isn't available yet (remaining changes are strictly
  internal to the clock driver and won't affect peripheral drivers)
=
clkdev registration provides "alias names" for few clock items
- to not break those peripheral drivers which encode their component
  index into the name that is used for clock lookup (UART, SPI, USB)
- to not break those drivers which use names for the clock lookup which
  were encoded in the previous PPC_CLOCK implementation (NFC, VIU, CAN)
this workaround will get removed as these drivers get adjusted after
device tree based clock lookup has become available
=
Signed-off-by: Gerhard Sittig <redacted>
Hi Gerhard,

This looks OK to me. Do you want me to take it or will you keep the
series together? Note that I took "clk: wrap I/O access for improved
portability" into the clk tree already.

Regards,
Mike
---
 arch/powerpc/platforms/512x/Kconfig           |   14 +-
 arch/powerpc/platforms/512x/Makefile          |    4 +-
 arch/powerpc/platforms/512x/clock-commonclk.c |  786 +++++++++++++++++++=
++++++
 include/linux/clk-provider.h                  |   16 +
 4 files changed, 818 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
=
quoted hunk
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms=
/512x/Kconfig
quoted hunk
index fc9c1cb..c5fcdd0 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -1,9 +1,21 @@
+config MPC512x_COMMON_CLK
+       bool "MPC512x platform uses COMMON_CLK"
+       default y
+       depends on PPC_MPC512x
+       help
+         This option is only here to support tests and comparison
+         during development and migration.  This option will get
+         removed after the COMMON_CLK support for MPC512x has become
+         fully operational and all drivers were adjusted to explicitly
+         acquire their required clocks.
+
 config PPC_MPC512x
        bool "512x-based boards"
        depends on 6xx
        select FSL_SOC
        select IPIC
-       select PPC_CLOCK
+       select PPC_CLOCK if !MPC512x_COMMON_CLK
+       select COMMON_CLK if MPC512x_COMMON_CLK
        select PPC_PCI_CHOICE
        select FSL_PCI if PCI
        select ARCH_WANT_OPTIONAL_GPIOLIB
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platform=
s/512x/Makefile
quoted hunk
index 72fb934..1e05f9d 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -1,7 +1,9 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-y                          +=3D clock.o mpc512x_shared.o
+obj-$(CONFIG_PPC_CLOCK)                +=3D clock.o
+obj-$(CONFIG_COMMON_CLK)       +=3D clock-commonclk.o
+obj-y                          +=3D mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)      +=3D mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)  +=3D mpc512x_generic.o
 obj-$(CONFIG_PDM360NG)         +=3D pdm360ng.o
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc=
/platforms/512x/clock-commonclk.c
quoted hunk
new file mode 100644
index 0000000..762ee85
--- /dev/null
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -0,0 +1,786 @@
+/*
+ * Copyright (C) 2013 DENX Software Engineering
+ *
+ * Gerhard Sittig, <gsi@denx.de>
+ *
+ * common clock driver support for the MPC512x platform
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <asm/mpc5121.h>
+#include <dt-bindings/clock/mpc512x-clock.h>
+
+#include "mpc512x.h"           /* our public mpc5121_clk_init() API */
+
+/* helpers to keep the MCLK intermediates "somewhere" in our table */
+enum {
+       MCLK_IDX_MUX0,
+       MCLK_IDX_EN0,
+       MCLK_IDX_DIV0,
+       MCLK_IDX_MUX1,
+       MCLK_MAX_IDX,
+};
+
+#define NR_PSCS                        12
+#define NR_MSCANS              4
+#define NR_SPDIFS              1
+#define NR_MCLKS               (NR_PSCS + NR_MSCANS + NR_SPDIFS)
+
+/* extend the public set of clocks by adding internal slots for manageme=
nt */
+enum {
+       /* arrange for adjacent numbers after the public set */
+       MPC512x_CLK_START_PRIVATE =3D MPC512x_CLK_LAST_PUBLIC,
+       /* clocks which aren't announced to the public */
+       MPC512x_CLK_DDR,
+       MPC512x_CLK_MEM,
+       MPC512x_CLK_IIM,
+       MPC512x_CLK_SDHC_2,
+       /* intermediates in div+gate combos or fractional dividers */
+       MPC512x_CLK_DDR_UG,
+       MPC512x_CLK_SDHC_x4,
+       MPC512x_CLK_SDHC_UG,
+       MPC512x_CLK_DIU_x4,
+       MPC512x_CLK_DIU_UG,
+       MPC512x_CLK_MBX_BUS_UG,
+       MPC512x_CLK_MBX_UG,
+       MPC512x_CLK_MBX_3D_UG,
+       MPC512x_CLK_PCI_UG,
+       MPC512x_CLK_NFC_UG,
+       MPC512x_CLK_LPC_UG,
+       MPC512x_CLK_SPDIF_TX_IN,
+       /* intermediates for the mux+gate+div+mux MCLK generation */
+       MPC512x_CLK_MCLKS_FIRST,
+       MPC512x_CLK_MCLKS_LAST =3D MPC512x_CLK_MCLKS_FIRST
+                               + NR_MCLKS * MCLK_MAX_IDX,
+       /* internal, symbolic spec for the number of slots */
+       MPC512x_CLK_LAST_PRIVATE,
+};
+
+/* data required for the OF clock provider registration */
+static struct clk *clks[MPC512x_CLK_LAST_PRIVATE];
+static struct clk_onecell_data clk_data;
+
+/* CCM register access */
+static struct mpc512x_ccm __iomem *clkregs;
+static DEFINE_SPINLOCK(clklock);
+
+/* convenience wrappers around the common clk API */
+static inline struct clk *mpc512x_clk_fixed(const char *name, int rate)
+{
+       return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rat=
e);
+}
+
+static inline struct clk *mpc512x_clk_factor(
+       const char *name, const char *parent_name,
+       int mul, int div)
+{
+       int clkflags;
+
+       clkflags =3D CLK_SET_RATE_PARENT;
+       return clk_register_fixed_factor(NULL, name, parent_name, clkflag=
s,
+                                        mul, div);
+}
+
+static inline struct clk *mpc512x_clk_divider(
+       const char *name, const char *parent_name, u8 clkflags,
+       u32 __iomem *reg, u8 pos, u8 len, int divflags)
+{
+       return clk_register_divider(NULL, name, parent_name, clkflags,
+                                   reg, pos, len, divflags, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_divtable(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos, u8 len,
+       const struct clk_div_table *divtab)
+{
+       u8 divflags;
+
+       divflags =3D 0;
+       return clk_register_divider_table(NULL, name, parent_name, 0,
+                                         reg, pos, len, divflags,
+                                         divtab, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_gated(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos)
+{
+       int clkflags;
+
+       clkflags =3D CLK_SET_RATE_PARENT;
+       return clk_register_gate(NULL, name, parent_name, clkflags,
+                                reg, pos, 0, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_muxed(const char *name,
+       const char **parent_names, int parent_count,
+       u32 __iomem *reg, u8 pos, u8 len)
+{
+       int clkflags;
+       u8 muxflags;
+
+       clkflags =3D CLK_SET_RATE_PARENT;
+       muxflags =3D 0;
+       return clk_register_mux(NULL, name,
+                               parent_names, parent_count, clkflags,
+                               reg, pos, len, muxflags, &clklock);
+}
+
+/* helper to isolate a bit field from a register */
+static inline int get_bit_field(uint32_t __iomem *reg, uint8_t pos, uint=
8_t len)
+{
+       uint32_t val;
+
+       val =3D in_be32(reg);
+       val >>=3D pos;
+       val &=3D (1 << len) - 1;
+       return val;
+}
+
+/* get the SPMF and translate it into the "sys pll" multiplier */
+static int get_spmf_mult(void)
+{
+       static int spmf_to_mult[] =3D {
+               68, 1, 12, 16, 20, 24, 28, 32,
+               36, 40, 44, 48, 52, 56, 60, 64,
+       };
+       int spmf;
+
+       spmf =3D get_bit_field(&clkregs->spmr, 24, 4);
+       return spmf_to_mult[spmf];
+}
+
+/*
+ * get the SYS_DIV value and translate it into a divide factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * divide ratio is fractional
+ */
+static int get_sys_div_x2(void)
+{
+       static int sysdiv_code_to_x2[] =3D {
+               4, 5, 6, 7, 8, 9, 10, 14,
+               12, 16, 18, 22, 20, 24, 26, 30,
+               28, 32, 34, 38, 36, 40, 42, 46,
+               44, 48, 50, 54, 52, 56, 58, 62,
+               60, 64, 66,
+       };
+       int divcode;
+
+       divcode =3D get_bit_field(&clkregs->scfr2, 26, 6);
+       return sysdiv_code_to_x2[divcode];
+}
+
+/*
+ * get the CPMF value and translate it into a multiplier factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * multiplier ratio is fractional
+ */
+static int get_cpmf_mult_x2(void)
+{
+       static int cpmf_to_mult[] =3D {
+               72, 2, 2, 3, 4, 5, 6, 7,
+       };
+       int cpmf;
+
+       cpmf =3D get_bit_field(&clkregs->spmr, 16, 4);
+       return cpmf_to_mult[cpmf];
+}
+
+/*
+ * some of the clock dividers do scale in a linear way, yet not all of
+ * their bit combinations are legal; use a divider table to get a
+ * resulting set of applicable divider values
+ */
+
+/* applies to the IPS_DIV, and PCI_DIV values */
+static struct clk_div_table divtab_2346[] =3D {
+       { .val =3D 2, .div =3D 2, },
+       { .val =3D 3, .div =3D 3, },
+       { .val =3D 4, .div =3D 4, },
+       { .val =3D 6, .div =3D 6, },
+       { .div =3D 0, },
+};
+
+/* applies to the MBX_DIV, LPC_DIV, and NFC_DIV values */
+static struct clk_div_table divtab_1234[] =3D {
+       { .val =3D 1, .div =3D 1, },
+       { .val =3D 2, .div =3D 2, },
+       { .val =3D 3, .div =3D 3, },
+       { .val =3D 4, .div =3D 4, },
+       { .div =3D 0, },
+};
+
+static int get_freq_from_dt(char *propname)
+{
+       struct device_node *np;
+       const unsigned int *prop;
+       int val;
+
+       val =3D 0;
+       np =3D of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
+       if (np) {
+               prop =3D of_get_property(np, propname, NULL);
+               if (prop)
+                       val =3D *prop;
+           of_node_put(np);
+       }
+       return val;
+}
+
+static void mpc512x_clk_preset_data(void)
+{
+       size_t i;
+
+       for (i =3D 0; i < ARRAY_SIZE(clks); i++)
+               clks[i] =3D ERR_PTR(-ENODEV);
+}
+
+/*
+ * - receives the "bus frequency" from the caller (that's the IPS clock
+ *   rate, the historical source of clock information)
+ * - fetches the system PLL multiplier and divider values as well as the
+ *   IPS divider value from hardware
+ * - determines the REF clock rate either from the XTAL/OSC spec (if
+ *   there is a device tree node describing the oscillator) or from the
+ *   IPS bus clock (supported for backwards compatibility, such that
+ *   setups without XTAL/OSC specs keep working)
+ * - creates the "ref" clock item in the clock tree, such that
+ *   subsequent code can create the remainder of the hierarchy (REF ->
+ *   SYS -> CSB -> IPS) from the REF clock rate and the returned mul/div
+ *   values
+ */
+static void mpc512x_clk_setup_ref_clock(int bus_freq,
+       int *sys_mul, int *sys_div, int *ips_div)
+{
+       struct clk *osc_clk;
+       int calc_freq;
+
+       /* fetch mul/div factors from the hardware */
+       *sys_mul =3D get_spmf_mult();
+       *sys_mul *=3D 2;          /* compensate for the fractional divide=
r */
+       *sys_div =3D get_sys_div_x2();
+       *ips_div =3D get_bit_field(&clkregs->scfr1, 23, 3);
+
+       /* lookup the oscillator node */
+       osc_clk =3D clk_get(NULL, "osc");
+       if (osc_clk) {
+               /* descend REF directly from OSC, verify the IPS rate */
+               clks[MPC512x_CLK_REF] =3D mpc512x_clk_factor("ref", "osc"=
, 1, 1);
+               calc_freq =3D clk_get_rate(clks[MPC512x_CLK_REF]);
+               calc_freq *=3D *sys_mul;
+               calc_freq /=3D *sys_div;
+               calc_freq /=3D 2;
+               calc_freq /=3D *ips_div;
+               if (bus_freq && calc_freq !=3D bus_freq)
+                       pr_warn("calc rate %d !=3D OF spec %d\n",
+                               calc_freq, bus_freq);
+       } else {
+               /* calculate OSC rate and create REF from the freq value =
*/
+               calc_freq =3D bus_freq;   /* start with IPS */
+               calc_freq *=3D *ips_div;  /* IPS -> CSB */
+               calc_freq *=3D 2;         /* CSB -> SYS */
+               calc_freq *=3D *sys_div;  /* SYS -> PLL out */
+               calc_freq /=3D *sys_mul;  /* PLL out -> REF =3D=3D OSC */
+               clks[MPC512x_CLK_REF] =3D mpc512x_clk_fixed("ref", calc_f=
req);
+       }
+}
+
+/*
+ * helper code for the MCLK subtree setup
+ *
+ * the overview in section 5.2.4 of the MPC5121e Reference Manual rev4
+ * suggests that all instances of the "PSC clock generation" are equal,
+ * and that one might re-use the PSC setup for MSCAN clock generation
+ * (section 5.2.5) as well, at least the logic if not the data for
+ * description
+ *
+ * the details (starting at page 5-20) show differences in the specific
+ * inputs of the first mux stage ("can clk in", "spdif tx"), and the
+ * factual non-availability of the second mux stage (it's present yet
+ * only one input is valid)
+ *
+ * the MSCAN clock related registers (starting at page 5-35) all
+ * reference "spdif clk" at the first mux stage and don't mention any
+ * "can clk" at all, which somehow is unexpected
+ *
+ * TODO re-check the document, and clarify whether the RM is correct in
+ * the overview or in the details, and whether the difference is a
+ * clipboard induced error or results from chip revisions
+ *
+ * it turns out that the RM rev4 as of 2012-06 talks about "can" for the
+ * PSCs while RM rev3 as of 2008-10 talks about "spdif", so I guess that
+ * first a doc update is required which better reflects reality in the
+ * SoC before the implementation should follow while no questions remain
+ */
+
+/*
+ * note that this declaration raises a checkpatch warning, but
+ * it's the very data type which <linux/clk-provider.h> expects,
+ * making this declaration pass checkpatch will break compilation
+ */
+static const char *parent_names_mux0[] =3D {
+       "sys", "ref", "psc-mclk-in", "spdif-tx",
+};
+
+enum mclk_type {
+       MCLK_TYPE_PSC,
+       MCLK_TYPE_MSCAN,
+       MCLK_TYPE_SPDIF,
+};
+
+struct mclk_setup_data {
+       enum mclk_type type;
+       int comp_idx;
+       bool has_mclk1;
+       int bit_sccr1, bit_sccr2;
+       const char *name_mux0;
+       const char *name_en0;
+       const char *name_div0;
+       const char *parent_names_mux1[2];
+       const char *name_mux1;
+       const char *name_mclk;
+};
+
+#define MCLK_SETUP_DATA_PSC(id) { \
+       MCLK_TYPE_PSC, id, \
+       0, 27 - id, -1, \
+       "psc" #id "-mux0", \
+       "psc" #id "-en0", \
+       "psc" #id "_mclk_div", \
+       { "psc" #id "_mclk_div", "dummy", }, \
+       "psc" #id "_mclk_out", \
+       "psc" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_MSCAN(id) { \
+       MCLK_TYPE_MSCAN, id, \
+       0, -1, 25, \
+       "mscan" #id "-mux0", \
+       "mscan" #id "-en0", \
+       "mscan" #id "_mclk_div", \
+       { "mscan" #id "_mclk_div", "dummy", }, \
+       "mscan" #id "_mclk_out", \
+       "mscan" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_SPDIF { \
+       MCLK_TYPE_SPDIF, 0, \
+       1, -1, 23, \
+       "spdif-mux0", \
+       "spdif-en0", \
+       "spdif_mclk_div", \
+       { "spdif_mclk_div", "spdif-rx", }, \
+       "spdif_mclk_out", \
+       "spdif_mclk", \
+}
+
+static struct mclk_setup_data mclk_psc_data[] =3D {
+       MCLK_SETUP_DATA_PSC(0),
+       MCLK_SETUP_DATA_PSC(1),
+       MCLK_SETUP_DATA_PSC(2),
+       MCLK_SETUP_DATA_PSC(3),
+       MCLK_SETUP_DATA_PSC(4),
+       MCLK_SETUP_DATA_PSC(5),
+       MCLK_SETUP_DATA_PSC(6),
+       MCLK_SETUP_DATA_PSC(7),
+       MCLK_SETUP_DATA_PSC(8),
+       MCLK_SETUP_DATA_PSC(9),
+       MCLK_SETUP_DATA_PSC(10),
+       MCLK_SETUP_DATA_PSC(11),
+};
+
+static struct mclk_setup_data mclk_mscan_data[] =3D {
+       MCLK_SETUP_DATA_MSCAN(0),
+       MCLK_SETUP_DATA_MSCAN(1),
+       MCLK_SETUP_DATA_MSCAN(2),
+       MCLK_SETUP_DATA_MSCAN(3),
+};
+
+static struct mclk_setup_data mclk_spdif_data[] =3D {
+       MCLK_SETUP_DATA_SPDIF,
+};
+
+/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
+static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
+{
+       size_t clks_idx_pub, clks_idx_int;
+       u32 __iomem *mccr_reg;  /* MCLK control register (mux, en, div) */
+       u32 __iomem *sccr_reg;  /* system clock control register (enable)=
 */
+       int sccr_bit;
+       int div;
+
+       /* derive a few parameters from the component type and index */
+       switch (entry->type) {
+       case MCLK_TYPE_PSC:
+               clks_idx_pub =3D MPC512x_CLK_PSC0_MCLK + entry->comp_idx;
+               clks_idx_int =3D MPC512x_CLK_MCLKS_FIRST
+                            + (entry->comp_idx) * MCLK_MAX_IDX;
+               mccr_reg =3D &clkregs->psc_ccr[entry->comp_idx];
+               break;
+       case MCLK_TYPE_MSCAN:
+               clks_idx_pub =3D MPC512x_CLK_MSCAN0_MCLK + entry->comp_id=
x;
+               clks_idx_int =3D MPC512x_CLK_MCLKS_FIRST
+                            + (NR_PSCS + entry->comp_idx) * MCLK_MAX_IDX;
+               mccr_reg =3D &clkregs->mscan_ccr[entry->comp_idx];
+               break;
+       case MCLK_TYPE_SPDIF:
+               clks_idx_pub =3D MPC512x_CLK_SPDIF_MCLK;
+               clks_idx_int =3D MPC512x_CLK_MCLKS_FIRST
+                            + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
+               mccr_reg =3D &clkregs->spccr;
+               break;
+       default:
+               return;
+       }
+       if (entry->bit_sccr1 >=3D 0) {
+               sccr_reg =3D &clkregs->sccr1;
+               sccr_bit =3D entry->bit_sccr1;
+       } else if (entry->bit_sccr2 >=3D 0) {
+               sccr_reg =3D &clkregs->sccr2;
+               sccr_bit =3D entry->bit_sccr2;
+       } else {
+               sccr_reg =3D NULL;
+       }
+
+       /*
+        * this was grabbed from the PPC_CLOCK implementation, which
+        * enforced a specific MCLK divider while the clock was gated
+        * during setup (that's a documented hardware requirement)
+        *
+        * the PPC_CLOCK implementation might even have violated the
+        * "MCLK <=3D IPS" constraint, the fixed divider value of 1
+        * results in a divider of 2 and thus MCLK =3D SYS/2 which equals
+        * CSB which is greater than IPS; the serial port setup may have
+        * adjusted the divider which the clock setup might have left in
+        * an undesirable state
+        *
+        * initial setup is:
+        * - MCLK 0 from SYS
+        * - MCLK DIV such to not exceed the IPS clock
+        * - MCLK 0 enabled
+        * - MCLK 1 from MCLK DIV
+        */
+       div =3D clk_get_rate(clks[MPC512x_CLK_SYS]);
+       div /=3D clk_get_rate(clks[MPC512x_CLK_IPS]);
+       out_be32(mccr_reg, (0 << 16));
+       out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
+       out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
+
+       /*
+        * create the 'struct clk' items of the MCLK's clock subtree
+        *
+        * note that by design we always create all nodes and won't take
+        * shortcuts here, because
+        * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
+        *   selectable inputs to the CFM while those who "actually use"
+        *   the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
+        *   for their bitrate
+        * - in the absence of "aliases" for clocks we need to create
+        *   individial 'struct clk' items for whatever might get
+        *   referenced or looked up, even if several of those items are
+        *   identical from the logical POV (their rate value)
+        * - for easier future maintenance and for better reflection of
+        *   the SoC's documentation, it appears appropriate to generate
+        *   clock items even for those muxers which actually are NOPs
+        *   (those with two inputs of which one is reserved)
+        */
+       clks[clks_idx_int + MCLK_IDX_MUX0] =3D mpc512x_clk_muxed(
+                       entry->name_mux0,
+                       &parent_names_mux0[0], ARRAY_SIZE(parent_names_mu=
x0),
+                       mccr_reg, 14, 2);
+       clks[clks_idx_int + MCLK_IDX_EN0] =3D mpc512x_clk_gated(
+                       entry->name_en0, entry->name_mux0,
+                       mccr_reg, 16);
+       clks[clks_idx_int + MCLK_IDX_DIV0] =3D mpc512x_clk_divider(
+                       entry->name_div0,
+                       entry->name_en0, CLK_SET_RATE_GATE,
+                       mccr_reg, 17, 15, 0);
+       if (entry->has_mclk1) {
+               clks[clks_idx_int + MCLK_IDX_MUX1] =3D mpc512x_clk_muxed(
+                               entry->name_mux1,
+                               &entry->parent_names_mux1[0],
+                               ARRAY_SIZE(entry->parent_names_mux1),
+                               mccr_reg, 7, 1);
+       } else {
+               clks[clks_idx_int + MCLK_IDX_MUX1] =3D mpc512x_clk_factor(
+                               entry->name_mux1, entry->parent_names_mux=
1[0],
+                               1, 1);
+       }
+       if (sccr_reg) {
+               clks[clks_idx_pub] =3D mpc512x_clk_gated(
+                               entry->name_mclk,
+                               entry->name_mux1, sccr_reg, sccr_bit);
+       } else {
+               clks[clks_idx_pub] =3D mpc512x_clk_factor(
+                               entry->name_mclk,
+                               entry->name_mux1, 1, 1);
+       }
+
+       /*
+        * without this "clock device" registration, "simple" lookups in
+        * the SPI master initialization and serial port setup will fail
+        *
+        * those drivers need to get adjusted to lookup their required
+        * clocks from device tree specs, and device tree nodes need to
+        * provide the clock specs, before this clkdev registration
+        * becomes obsolete
+        */
+       clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
+}
+
+static void mpc512x_clk_setup_mclks(struct mclk_setup_data *table, size_=
t count)
+{
+       while (count-- > 0)
+               mpc512x_clk_setup_mclk(table++);
+}
+
+static void mpc512x_clk_setup_clock_tree(int busfreq)
+{
+       int sys_mul, sys_div, ips_div;
+       int mul, div;
+       int freq;
+
+       /*
+        * TODO
+        * - consider whether to handle clocks which have both gates and
+        *   dividers via intermediates or by means of composites
+        * - fractional dividers appear to not map well to composites
+        *   since they can be seen as a fixed multiplier and an
+        *   adjustable divider, while composites can only combine at
+        *   most one of a mux, div, and gate each into one 'struct clk'
+        *   item
+        * - PSC/MSCAN/SPDIF clock generation OTOH already is very
+        *   specific and cannot get mapped to componsites (at least not
+        *   a single one, maybe two of them, but see the comment about
+        *   "intermediates are referenced from elsewhere, too")
+        * - trim the list of auto-enabled clocks after drivers acquire
+        *   them correctly as needed
+        */
+
+       /* regardless of whether XTAL/OSC exists, have REF created */
+       mpc512x_clk_setup_ref_clock(busfreq, &sys_mul, &sys_div, &ips_div=
);
+
+       /* now setup the REF -> SYS -> CSB -> IPS hierarchy */
+       clks[MPC512x_CLK_SYS] =3D mpc512x_clk_factor("sys", "ref",
+                                                  sys_mul, sys_div);
+       clks[MPC512x_CLK_CSB] =3D mpc512x_clk_factor("csb", "sys", 1, 2);
+       clks[MPC512x_CLK_IPS] =3D mpc512x_clk_divtable("ips", "csb",
+                                                    &clkregs->scfr1, 23,=
 3,
+                                                    divtab_2346);
+
+       /* now setup anything below SYS and CSB and IPS */
+       clks[MPC512x_CLK_DDR_UG] =3D mpc512x_clk_factor("ddr-ug", "sys", =
1, 2);
+       clks[MPC512x_CLK_SDHC_x4] =3D mpc512x_clk_factor("sdhc-x4", "csb"=
, 4, 1);
+       clks[MPC512x_CLK_SDHC_UG] =3D mpc512x_clk_divider("sdhc-ug", "sdh=
c-x4", 0,
+                                                       &clkregs->scfr2, =
0, 8,
+                                                       CLK_DIVIDER_ONE_B=
ASED);
+       clks[MPC512x_CLK_DIU_x4] =3D mpc512x_clk_factor("diu-x4", "csb", =
4, 1);
+       clks[MPC512x_CLK_DIU_UG] =3D mpc512x_clk_divider("diu-ug", "diu-x=
4", 0,
+                                                      &clkregs->scfr1, 0=
, 8,
+                                                      CLK_DIVIDER_ONE_BA=
SED);
+
+       /*
+        * the "power architecture PLL" was setup from data which was
+        * sampled from the reset config word, at this point in time the
+        * configuration can be considered fixed and read only (i.e. no
+        * longer adjustable, or no longer in need of adjustment), which
+        * is why we don't register a PLL here but assume fixed factors
+        */
+       mul =3D get_cpmf_mult_x2();
+       div =3D 2;        /* compensate for the fractional factor */
+       clks[MPC512x_CLK_E300] =3D mpc512x_clk_factor("e300", "csb", mul,=
 div);
+
+       clks[MPC512x_CLK_MBX_BUS_UG] =3D mpc512x_clk_factor("mbx-bus-ug",=
 "csb",
+                                                         1, 2);
+       clks[MPC512x_CLK_MBX_UG] =3D mpc512x_clk_divtable("mbx-ug", "mbx-=
bus-ug",
+                                                       &clkregs->scfr1, =
14, 3,
+                                                       divtab_1234);
+       clks[MPC512x_CLK_MBX_3D_UG] =3D mpc512x_clk_factor("mbx-3d-ug", "=
mbx-ug",
+                                                        1, 1);
+       clks[MPC512x_CLK_PCI_UG] =3D mpc512x_clk_divtable("pci-ug", "csb",
+                                                       &clkregs->scfr1, =
20, 3,
+                                                       divtab_2346);
+       clks[MPC512x_CLK_NFC_UG] =3D mpc512x_clk_divtable("nfc-ug", "ips",
+                                                       &clkregs->scfr1, =
8, 3,
+                                                       divtab_1234);
+       clks[MPC512x_CLK_LPC_UG] =3D mpc512x_clk_divtable("lpc-ug", "ips",
+                                                       &clkregs->scfr1, =
11, 3,
+                                                       divtab_1234);
+
+       clks[MPC512x_CLK_LPC] =3D mpc512x_clk_gated("lpc", "lpc-ug",
+                                                 &clkregs->sccr1, 30);
+       clks[MPC512x_CLK_NFC] =3D mpc512x_clk_gated("nfc", "nfc-ug",
+                                                 &clkregs->sccr1, 29);
+       clks[MPC512x_CLK_PATA] =3D mpc512x_clk_gated("pata", "ips",
+                                                  &clkregs->sccr1, 28);
+       mpc512x_clk_setup_mclks(mclk_psc_data, ARRAY_SIZE(mclk_psc_data));
+       clks[MPC512x_CLK_PSC_FIFO] =3D mpc512x_clk_gated("psc-fifo", "ips=
",
+                                                      &clkregs->sccr1, 1=
5);
+       clks[MPC512x_CLK_SATA] =3D mpc512x_clk_gated("sata", "ips",
+                                                  &clkregs->sccr1, 14);
+       clks[MPC512x_CLK_FEC] =3D mpc512x_clk_gated("fec", "ips",
+                                                 &clkregs->sccr1, 13);
+       clks[MPC512x_CLK_PCI] =3D mpc512x_clk_gated("pci", "pci-ug",
+                                                 &clkregs->sccr1, 11);
+       clks[MPC512x_CLK_DDR] =3D mpc512x_clk_gated("ddr", "ddr-ug",
+                                                 &clkregs->sccr1, 10);
+
+       clks[MPC512x_CLK_DIU] =3D mpc512x_clk_gated("diu", "diu-ug",
+                                                 &clkregs->sccr2, 31);
+       clks[MPC512x_CLK_AXE] =3D mpc512x_clk_gated("axe", "csb",
+                                                 &clkregs->sccr2, 30);
+       clks[MPC512x_CLK_MEM] =3D mpc512x_clk_gated("mem", "ips",
+                                                 &clkregs->sccr2, 29);
+       clks[MPC512x_CLK_USB1] =3D mpc512x_clk_gated("usb1", "csb",
+                                                  &clkregs->sccr2, 28);
+       clks[MPC512x_CLK_USB2] =3D mpc512x_clk_gated("usb2", "csb",
+                                                  &clkregs->sccr2, 27);
+       clks[MPC512x_CLK_I2C] =3D mpc512x_clk_gated("i2c", "ips",
+                                                 &clkregs->sccr2, 26);
+       mpc512x_clk_setup_mclks(mclk_mscan_data, ARRAY_SIZE(mclk_mscan_da=
ta));
+       clks[MPC512x_CLK_SDHC] =3D mpc512x_clk_gated("sdhc", "sdhc-ug",
+                                                  &clkregs->sccr2, 24);
+       mpc512x_clk_setup_mclks(mclk_spdif_data, ARRAY_SIZE(mclk_spdif_da=
ta));
+       clks[MPC512x_CLK_MBX_BUS] =3D mpc512x_clk_gated("mbx-bus", "mbx-b=
us-ug",
+                                                     &clkregs->sccr2, 22=
);
+       clks[MPC512x_CLK_MBX] =3D mpc512x_clk_gated("mbx", "mbx-ug",
+                                                 &clkregs->sccr2, 21);
+       clks[MPC512x_CLK_MBX_3D] =3D mpc512x_clk_gated("mbx-3d", "mbx-3d-=
ug",
+                                                    &clkregs->sccr2, 20);
+       clks[MPC512x_CLK_IIM] =3D mpc512x_clk_gated("iim", "csb",
+                                                 &clkregs->sccr2, 19);
+       clks[MPC512x_CLK_VIU] =3D mpc512x_clk_gated("viu", "csb",
+                                                 &clkregs->sccr2, 18);
+       clks[MPC512x_CLK_SDHC_2] =3D mpc512x_clk_gated("sdhc-2", "sdhc-ug=
",
+                                                    &clkregs->sccr2, 17);
+
+       /*
+        * externally provided clocks (when implemented in hardware,
+        * device tree may specify values which otherwise were unknown)
+        */
+       freq =3D get_freq_from_dt("psc_mclk_in");
+       if (!freq)
+               freq =3D 25000000;
+       clks[MPC512x_CLK_PSC_MCLK_IN] =3D mpc512x_clk_fixed("psc_mclk_in"=
, freq);
+       freq =3D get_freq_from_dt("spdif_tx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] =3D mpc512x_clk_fixed("spdif_tx_in"=
, freq);
+       freq =3D get_freq_from_dt("spdif_rx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] =3D mpc512x_clk_fixed("spdif_rx_in"=
, freq);
+
+       /* fixed frequency for AC97, always 24.567MHz */
+       clks[MPC512x_CLK_AC97] =3D mpc512x_clk_fixed("ac97", 24567000);
+
+       /* clkdev registration for compatibility reasons */
+       clk_register_clkdev(clks[MPC512x_CLK_REF], "ref_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_VIU], "viu_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_NFC], "nfc_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_USB1], "usb1_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_USB2], "usb2_clk", NULL);
+
+       pr_debug("clock tree setup complete\n");
+       freq =3D clk_get_rate(clks[MPC512x_CLK_E300]);
+       pr_debug("derived PPC freq [%d]\n", freq);
+       freq =3D clk_get_rate(clks[MPC512x_CLK_IPS]);
+       pr_debug("derived IPS freq [%d]\n", freq);
+       freq =3D clk_get_rate(clks[MPC512x_CLK_LPC]);
+       pr_debug("derived LPC freq [%d]\n", freq);
+
+       /* enable some of the clocks here unconditionally because ... */
+       pr_debug("automatically enabling some clocks\n");
+       /* some are essential yet never get claimed by any driver */
+       clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
+       clk_prepare_enable(clks[MPC512x_CLK_E300]);     /* PowerPC CPU */
+       clk_prepare_enable(clks[MPC512x_CLK_DDR]);      /* DRAM */
+       clk_prepare_enable(clks[MPC512x_CLK_MEM]);      /* SRAM */
+       clk_prepare_enable(clks[MPC512x_CLK_IPS]);      /* SoC periph */
+       clk_prepare_enable(clks[MPC512x_CLK_LPC]);      /* boot media */
+       /* some are required yet no dependencies were declared */
+       clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
+       /* some are not yet acquired by their respective drivers */
+       clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console=
 */
+       clk_prepare_enable(clks[MPC512x_CLK_FEC]);      /* network, NFS */
+       clk_prepare_enable(clks[MPC512x_CLK_DIU]);      /* display */
+       clk_prepare_enable(clks[MPC512x_CLK_I2C]);
+       /*
+        * some have their individual clock subtree with separate clock
+        * items and their individual enable counters, yet share a
+        * common gate (refer to the same register location) while the
+        * common clock driver code is not aware of the fact and the
+        * platform's code doesn't provide specific support either
+        *
+        * what might happen is that e.g. enabling two MSCAN clock items
+        * and disabling one of them will disable the common gate and
+        * thus break the other MSCAN clock as well
+        */
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN0_MCLK]);
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN1_MCLK]);
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN2_MCLK]);
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN3_MCLK]);
+}
+
+/*
+ * registers the set of public clocks (those listed in the dt-bindings/
+ * header file) for OF lookups, keeps the intermediates private to us
+ */
+static void mpc5121_clk_register_of_provider(struct device_node *np)
+{
+       clk_data.clks =3D clks;
+       clk_data.clk_num =3D MPC512x_CLK_LAST_PUBLIC + 1; /* _not_ ARRAY_=
SIZE() */
+       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+int __init mpc5121_clk_init(void)
+{
+       struct device_node *clk_np;
+       int busfreq;
+
+       /* map the clock control registers */
+       clk_np =3D of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock=
");
quoted hunk
+       if (!clk_np)
+               return -ENODEV;
+       clkregs =3D of_iomap(clk_np, 0);
+       WARN_ON(!clkregs);
+
+       /* invalidate all not yet registered clock slots */
+       mpc512x_clk_preset_data();
+
+       /*
+        * have the device tree scanned for "fixed-clock" nodes (which
+        * includes the oscillator node if the board's DT provides one)
+        */
+       of_clk_init(NULL);
+
+       /*
+        * add a dummy clock for those situations where a clock spec is
+        * required yet no real clock is involved
+        */
+       clks[MPC512x_CLK_DUMMY] =3D mpc512x_clk_fixed("dummy", 0);
+
+       /*
+        * have all the real nodes in the clock tree populated from REF
+        * down to all leaves, either starting from the OSC node or from
+        * a REF root that was created from the IPS bus clock input
+        */
+       busfreq =3D get_freq_from_dt("bus-frequency");
+       mpc512x_clk_setup_clock_tree(busfreq);
+
+       /* register as an OF clock provider */
+       mpc5121_clk_register_of_provider(clk_np);
+
+       return 0;
+}
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index c4f7799..7f8fc64 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -497,6 +497,20 @@ static inline const char *of_clk_get_parent_name(str=
uct device_node *np,
  * for improved portability across platforms
  */
 =
quoted hunk
+#if IS_ENABLED(CONFIG_PPC)
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+       return ioread32be(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+       iowrite32be(val, reg);
+}
+
+#else  /* platform dependent I/O accessors */
+
 static inline u32 clk_readl(u32 __iomem *reg)
 {
        return readl(reg);
@@ -507,5 +521,7 @@ static inline void clk_writel(u32 val, u32 __iomem *r=
eg)
        writel(val, reg);
 }
 =
+#endif /* platform dependent I/O accessors */
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
-- =
1.7.10.4

[PATCH v3 13/31] clk: wrap I/O access for improved portability

From: Gerhard Sittig <hidden>
Date: 2013-08-03 14:08:46

[ trimming the CC: list for this strictly clock related and
  source code adjusting change, to not spam the device tree ML or
  other subsystem maintainers, just keeping ARM (for clock) and
  PPC lists and people in the loop ]

On Fri, Aug 02, 2013 at 15:30 -0700, Mike Turquette wrote:
Quoting Gerhard Sittig (2013-07-22 05:14:40)
quoted
the common clock drivers were motivated/initiated by ARM development
and apparently assume little endian peripherals

wrap register/peripherals access in the common code (div, gate, mux)
in preparation of adding COMMON_CLK support for other platforms

Signed-off-by: Gerhard Sittig <redacted>
I've taken this into clk-next for testing. regmap deserves investigation
but I don't think your series should be blocked on that. We can always
overhaul the basic clock primitives with regmap support later on if that
makes sense.

Regards,
Mike
That's fine.  Though I will re-post this change when updating the
series, but this should not harm (won't conflict) as this
specific patch is stable and won't change any longer.  Keeping
this one patch in the series keeps the series applicable on top
of v3.11-rcN as well as clk-next.

Note that this patch only changes those parts of the code under
drivers/clk/ which get shared among platforms (div, gate, mux).
It doesn't touch non-shared and platform specific drivers.  I
felt this was the most appropriate thing to do.

quoted
---
 drivers/clk/clk-divider.c    |    6 +++---
 drivers/clk/clk-gate.c       |    6 +++---
 drivers/clk/clk-mux.c        |    6 +++---
 include/linux/clk-provider.h |   17 +++++++++++++++++
 4 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 6d55eb2..2c07061 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
        struct clk_divider *divider = to_clk_divider(hw);
        unsigned int div, val;
 
-       val = readl(divider->reg) >> divider->shift;
+       val = clk_readl(divider->reg) >> divider->shift;
        val &= div_mask(divider);
 
        div = _get_div(divider, val);
@@ -230,11 +230,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
        if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
                val = div_mask(divider) << (divider->shift + 16);
        } else {
-               val = readl(divider->reg);
+               val = clk_readl(divider->reg);
                val &= ~(div_mask(divider) << divider->shift);
        }
        val |= value << divider->shift;
-       writel(val, divider->reg);
+       clk_writel(val, divider->reg);
 
        if (divider->lock)
                spin_unlock_irqrestore(divider->lock, flags);
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 790306e..b7fbd96 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -58,7 +58,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
                if (set)
                        reg |= BIT(gate->bit_idx);
        } else {
-               reg = readl(gate->reg);
+               reg = clk_readl(gate->reg);
 
                if (set)
                        reg |= BIT(gate->bit_idx);
@@ -66,7 +66,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
                        reg &= ~BIT(gate->bit_idx);
        }
 
-       writel(reg, gate->reg);
+       clk_writel(reg, gate->reg);
 
        if (gate->lock)
                spin_unlock_irqrestore(gate->lock, flags);
@@ -89,7 +89,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
        u32 reg;
        struct clk_gate *gate = to_clk_gate(hw);
 
-       reg = readl(gate->reg);
+       reg = clk_readl(gate->reg);
 
        /* if a set bit disables this clk, flip it before masking */
        if (gate->flags & CLK_GATE_SET_TO_DISABLE)
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 614444c..02ef506 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -42,7 +42,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
         * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
         * val = 0x4 really means "bit 2, index starts at bit 0"
         */
-       val = readl(mux->reg) >> mux->shift;
+       val = clk_readl(mux->reg) >> mux->shift;
        val &= mux->mask;
 
        if (mux->table) {
@@ -89,11 +89,11 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
        if (mux->flags & CLK_MUX_HIWORD_MASK) {
                val = mux->mask << (mux->shift + 16);
        } else {
-               val = readl(mux->reg);
+               val = clk_readl(mux->reg);
                val &= ~(mux->mask << mux->shift);
        }
        val |= index << mux->shift;
-       writel(val, mux->reg);
+       clk_writel(val, mux->reg);
 
        if (mux->lock)
                spin_unlock_irqrestore(mux->lock, flags);
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 1ec14a7..c4f7799 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -12,6 +12,7 @@
 #define __LINUX_CLK_PROVIDER_H
 
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #ifdef CONFIG_COMMON_CLK
 
@@ -490,5 +491,21 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
 #define of_clk_init(matches) \
        { while (0); }
 #endif /* CONFIG_OF */
+
+/*
+ * wrap access to peripherals in accessor routines
+ * for improved portability across platforms
+ */
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+       return readl(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+       writel(val, reg);
+}
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
-- 
1.7.10.4

virtually yours
Gerhard Sittig
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

[PATCH v3 15/31] dts: mpc512x: introduce dt-bindings/clock/ header

From: Gerhard Sittig <hidden>
Date: 2013-08-03 14:19:54

On Fri, Aug 02, 2013 at 15:43 -0700, Mike Turquette wrote:
Quoting Gerhard Sittig (2013-07-22 05:14:42)
quoted
introduce a dt-bindings/ header file for MPC512x clocks,
providing symbolic identifiers for those SoC clocks which
clients will reference from their device tree nodes

Signed-off-by: Gerhard Sittig <redacted>
---
 include/dt-bindings/clock/mpc512x-clock.h |   59 +++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h
diff --git a/include/dt-bindings/clock/mpc512x-clock.h b/include/dt-bindings/clock/mpc512x-clock.h
new file mode 100644
index 0000000..46c560e
--- /dev/null
+++ b/include/dt-bindings/clock/mpc512x-clock.h
@@ -0,0 +1,59 @@
+/*
+ * This header provides constants for MPC512x clock specs in DT bindings.
+ *
+ * Unfortunately the clock number declaration cannot be an enum but
+ * needs to be a list of #define directives since when referenced from
+ * within DTS files they need to get resolved "at compile time".
Above comment is not really necessary. Otherwise,

Reviewed-by: Mike Turquette <redacted>
OK, the next update of the series will remove this comment.

quoted
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+
+#define MPC512x_CLK_DUMMY              0
+#define MPC512x_CLK_REF                        1
+#define MPC512x_CLK_SYS                        2
+#define MPC512x_CLK_DIU                        3
+#define MPC512x_CLK_VIU                        4
+#define MPC512x_CLK_CSB                        5
+#define MPC512x_CLK_E300               6
+#define MPC512x_CLK_IPS                        7
+#define MPC512x_CLK_FEC                        8
+#define MPC512x_CLK_SATA               9
+#define MPC512x_CLK_PATA               10
+#define MPC512x_CLK_NFC                        11
+#define MPC512x_CLK_LPC                        12
+#define MPC512x_CLK_MBX_BUS            13
+#define MPC512x_CLK_MBX                        14
+#define MPC512x_CLK_MBX_3D             15
+#define MPC512x_CLK_AXE                        16
+#define MPC512x_CLK_USB1               17
+#define MPC512x_CLK_USB2               18
+#define MPC512x_CLK_I2C                        19
+#define MPC512x_CLK_MSCAN0_MCLK                20
+#define MPC512x_CLK_MSCAN1_MCLK                21
+#define MPC512x_CLK_MSCAN2_MCLK                22
+#define MPC512x_CLK_MSCAN3_MCLK                23
+#define MPC512x_CLK_SDHC               24
+#define MPC512x_CLK_PCI                        25
+#define MPC512x_CLK_PSC_MCLK_IN                26
+#define MPC512x_CLK_SPDIF_TX           27
+#define MPC512x_CLK_SPDIF_RX           28
+#define MPC512x_CLK_SPDIF_MCLK         29
+#define MPC512x_CLK_AC97               30
+#define MPC512x_CLK_PSC0_MCLK          31
+#define MPC512x_CLK_PSC1_MCLK          32
+#define MPC512x_CLK_PSC2_MCLK          33
+#define MPC512x_CLK_PSC3_MCLK          34
+#define MPC512x_CLK_PSC4_MCLK          35
+#define MPC512x_CLK_PSC5_MCLK          36
+#define MPC512x_CLK_PSC6_MCLK          37
+#define MPC512x_CLK_PSC7_MCLK          38
+#define MPC512x_CLK_PSC8_MCLK          39
+#define MPC512x_CLK_PSC9_MCLK          40
+#define MPC512x_CLK_PSC10_MCLK         41
+#define MPC512x_CLK_PSC11_MCLK         42
+#define MPC512x_CLK_PSC_FIFO           43
+
+#define MPC512x_CLK_LAST_PUBLIC                43
+
+#endif
-- 
1.7.10.4

virtually yours
Gerhard Sittig
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

[PATCH v3 17/31] clk: mpc512x: introduce COMMON_CLK for MPC512x

From: Gerhard Sittig <hidden>
Date: 2013-08-03 14:39:56

[ we are strictly talking about clocks and source code again,
  I have trimmed the CC: list to not spam the device tree ML or
  subsystem maintainers ]

On Fri, Aug 02, 2013 at 16:30 -0700, Mike Turquette wrote:
Quoting Gerhard Sittig (2013-07-23 06:14:06)
quoted
[ summary: "shared gate" support desirable? approach acceptable? ]

On Mon, Jul 22, 2013 at 14:14 +0200, Gerhard Sittig wrote:
quoted
this change implements a clock driver for the MPC512x PowerPC platform
which follows the COMMON_CLK approach and uses common clock drivers
shared with other platforms

[ ... ]

some of the clock items get pre-enabled in the clock driver to not have
them automatically disabled by the underlying clock subsystem because of
their being unused -- this approach is desirable because
[ ... ]
- some help introduce support for and migrate to the common
  infrastructure, while more appropriate support for specific hardware
  constraints isn't available yet (remaining changes are strictly
  internal to the clock driver and won't affect peripheral drivers)
This remark was related to the CAN clocks of the MPC512x SoC.
Gerhard,

Thanks for the patch (way far down below here). I'll check into it to
see if that implementation looks OK. It would be helpful if another
platform with shared gates could weigh in on whether the implementation
works for them.

Still, a shared gate solution is not a prerequisite for this series,
correct?
Well, the recent CAN driver related discussion suggested that I
had a mental misconception there.  The need for "shared gates"
was felt because of mixing up unrelated paths in the clock tree.
But the MCLK subtree is for bitrate generation, while the BDLC
gate is for register access into the peripheral controller.

Currently I'm investigating how I can cleanly tell those
individual aspects apart.  Telling the gate for register access
(in ARM speak often referred to as 'ipg') from the bitrate
generation (the 'per' clock, or 'mclk' here) seems so much more
appropriate.

After clean separation, and more testing to make sure nothing
gets broken throughout the series, there will be v4.


So "shared gate" support might have become obsolete for the
MPC512x platform.  But if others need it, the outlined approach
(patch below) may be viable.  The change to the common code is
minimal.  The use in the platform's clock driver was kind of
overengineered for the case of exactly one such gate, but this
immediately makes it a working approach for several gates, if
others need it.

I'll trim the motivation and just leave the suggested approach
for "shared gates" here.  Feel free to drop it or to only
resurrect it as the need may re-arise later.  So far nobody
appears to have felt the need up to now ...
quoted
[ ... ]

The question now is how to correctly support the situation where
a gate is shared between subtrees yet isn't really part of any
path within the subtrees.  I really cannot find a single spot
where to introduce the gate such that it's not duplicated.

The appropriate solution would not be to pre-enable those clocks,
but to either introduce another gate clock type which supports a
shared reference, or to add support for the shared reference to
the existing gate code.


I'd rather not duplicate most or all of the code of clk-gate.c,
instead I looked into how to add "shared gate" support to the
existing driver.

My question is whether the approach is acceptable.  It adds
minimal overhead and shall be OK for the enable/disable path from
a technical POV.  And it doesn't feel like too much of a stretch.
But there may be non-technical reasons to reject the approach.
I'd like to learn whether to follow that path before preparing
another version of the patch series.

The diffs were taken with the '-w -b' options to demonstrate
their essence and not drown it in whitespace changes.  The
implementation assumes that the caller which registers the gate
(the platform's clock driver) provides both the counter cell and
the lock.  And that all gates with a "shared use counter" use the
same lock (which is satisfied as they all get registered from the
same spot in the platform's clock driver).

The CLK_IGNORE_UNUSED flag addresses a different problem.  The
SoC has four MSCAN components, while two of them are enabled in
the device tree (the other two are present but disabled).  So
during probe two of the clocks get enabled.  After probe all
unused clocks automatically get disabled (that's another two).
So the "shared use counter" drops to zero although components are
in use, because "disable, it's unused" isn't told from "disable
after enable, regular use".  The flag would become obsolete if
the common gate logic would implement a separate disable_unused()
routine, but I guess this isn't necessary and the use of the flag
is appropriate.

That the example use creates a field for just one counter is to
better demonstrate the use and potential extension as need
arises.  Reducing this to a mere integer variable would be a
micro optimization.


The extension of the existing clk_gate implementation:
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -46,6 +46,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
        struct clk_gate *gate = to_clk_gate(hw);
        int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
        unsigned long flags = 0;
+       int need_reg_access;
        u32 reg;
 
        set ^= enable;
@@ -53,6 +54,20 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
        if (gate->lock)
                spin_lock_irqsave(gate->lock, flags);
 
+       /*
+        * if a "shared use counter" was specified, keep track of enable
+        * and disable calls and only access hardware registers upon the
+        * very first enable or very last disable call
+        */
+       if (!gate->share_count) {
+               need_reg_access = 1;
+       } else if (enable) {
+               need_reg_access = (*gate->share_count)++ == 0;
+       } else {
+               need_reg_access = --(*gate->share_count) == 0;
+       }
+
+       if (need_reg_access) {
                if (gate->flags & CLK_GATE_HIWORD_MASK) {
                        reg = BIT(gate->bit_idx + 16);
                        if (set)
@@ -67,6 +82,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
                }
 
                clk_writel(reg, gate->reg);
+       }
 
        if (gate->lock)
                spin_unlock_irqrestore(gate->lock, flags);
@@ -118,10 +134,11 @@ EXPORT_SYMBOL_GPL(clk_gate_ops);
  * @clk_gate_flags: gate-specific flags for this clock
  * @lock: shared register lock for this clock
  */
-struct clk *clk_register_gate(struct device *dev, const char *name,
+struct clk *clk_register_gate_shared(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
-               u8 clk_gate_flags, spinlock_t *lock)
+               u8 clk_gate_flags, spinlock_t *lock,
+               int *share_count)
 {
        struct clk_gate *gate;
        struct clk *clk;
@@ -152,6 +169,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
        gate->bit_idx = bit_idx;
        gate->flags = clk_gate_flags;
        gate->lock = lock;
+       gate->share_count = share_count;
        gate->hw.init = &init;
 
        clk = clk_register(dev, &gate->hw);
@@ -161,3 +179,14 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 
        return clk;
 }
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 bit_idx,
+               u8 clk_gate_flags, spinlock_t *lock)
+{
+
+       return clk_register_gate_shared(dev, name, parent_name, flags,
+                                       reg, bit_idx, clk_gate_flags,
+                                       lock, NULL);
+}
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -222,6 +222,7 @@ struct clk_gate {
        u8              bit_idx;
        u8              flags;
        spinlock_t      *lock;
+       int             *share_count;
 };
 
 #define CLK_GATE_SET_TO_DISABLE                BIT(0)
@@ -232,6 +233,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
                u8 clk_gate_flags, spinlock_t *lock);
+struct clk *clk_register_gate_shared(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 bit_idx,
+               u8 clk_gate_flags, spinlock_t *lock,
+               int *share_count);
 
 struct clk_div_table {
        unsigned int    val;

How to use these shared gates:
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -123,6 +123,39 @@ static inline struct clk *mpc512x_clk_gated(
                                 reg, pos, 0, &clklock);
 }
 
+enum mpc512x_clk_shared_gate_id_t {
+       MPC512x_CLK_SHARED_GATE_MSCAN,
+       MPC512x_CLK_SHARED_GATE_MAX,
+};
+
+static int mpc512x_clk_gate_counters[MPC512x_CLK_SHARED_GATE_MAX];
+
+/*
+ * implementor's note:  since clk_gate items don't implement a separate
+ * .disable_unused() callback, their .disable() routine gets called and
+ * "disable the clock as we can't see it's in use" cannot be told from
+ * "regular disable, count these events please"
+ *
+ * passing the CLK_IGNORE_UNUSED flag upon clock creation will suppress
+ * the "disable, unused" call, so use counts won't get unbalanced, the
+ * clock either never got enabled and thus need not get disabled, or
+ * part of the hardware got enabled while disabling the other part isn't
+ * wanted
+ */
+static inline struct clk *mpc512x_clk_gated_shared(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos,
+       enum mpc512x_clk_shared_gate_id_t share_id)
+{
+       int clkflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       clkflags |= CLK_IGNORE_UNUSED;
+       return clk_register_gate_shared(NULL, name, parent_name, clkflags,
+                                       reg, pos, 0, &clklock,
+                                       &mpc512x_clk_gate_counters[share_id]);
+}
+
 static inline struct clk *mpc512x_clk_muxed(const char *name,
        const char **parent_names, int parent_count,
        u32 __iomem *reg, u8 pos, u8 len)
@@ -520,9 +553,16 @@ static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
                                1, 1);
        }
        if (sccr_reg) {
+               if (entry->type == MCLK_TYPE_MSCAN) {
+                       clks[clks_idx_pub] = mpc512x_clk_gated_shared(
+                                       entry->name_mclk,
+                                       entry->name_mux1, sccr_reg, sccr_bit,
+                                       MPC512x_CLK_SHARED_GATE_MSCAN);
+               } else {
                        clks[clks_idx_pub] = mpc512x_clk_gated(
                                        entry->name_mclk,
                                        entry->name_mux1, sccr_reg, sccr_bit);
+               }
        } else {
                clks[clks_idx_pub] = mpc512x_clk_factor(
                                entry->name_mclk,
Local tests have shown that the extension solves the problem of
how to satisfy the SoC's constraints on the MPC512x platform.
The MSCAN clocks no longer need to get pre-enabled, instead they
get setup and enabled only as the mscan(4) driver probes devices
according to how it was instructed (device tree nodes).

What do you think?  Is the "shared gate" support in the common
logic appropriate?  I'd rather not duplicate all of this code
just to introduce the specific gate I need, while most of the
logic is identical to the existing gate implementation.  The
desire isn't to override the gate's operations, but to wrap them
and to consult a counter in addition, while the register access
still applies.

virtually yours
Gerhard Sittig
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

[PATCH v3 17/31] clk: mpc512x: introduce COMMON_CLK for MPC512x

From: Gerhard Sittig <hidden>
Date: 2013-08-03 15:03:42

[ this is about the MPC512x platform's clock driver, the core of
  the series; trim the CC: list and only keep ARM (for clock) and
  PPC lists and people ]

On Fri, Aug 02, 2013 at 16:41 -0700, Mike Turquette wrote:
Quoting Gerhard Sittig (2013-07-22 05:14:44)
quoted
this change implements a clock driver for the MPC512x PowerPC platform
which follows the COMMON_CLK approach and uses common clock drivers
shared with other platforms

this driver implements the publicly announced set of clocks (which can
get referenced by means of symbolic identifiers from the dt-bindings
header file), as well as generates additional 'struct clk' items where
the SoC hardware cannot easily get mapped to the common primitives of
the clock API, or requires "intermediate" clock nodes to represent
clocks that have both gates and dividers

the previous PPC_CLOCK implementation is kept in place and remains in
parallel to the common clock implementation for test and comparison
during migration, a compile time option picks one of the two
alternatives (Kconfig switch, common clock used by default)

some of the clock items get pre-enabled in the clock driver to not have
them automatically disabled by the underlying clock subsystem because of
their being unused -- this approach is desirable because
- some of the clocks are useful to have for diagnostics and information
  despite their not getting claimed by any drivers (CPU, internal and
  external RAM, internal busses, boot media)
- some of the clocks aren't claimed by their peripheral drivers yet,
  either because of missing driver support or because device tree specs
  aren't available yet (but the workarounds will get removed as the
  drivers get adjusted and the device tree provides the clock specs)
- some help introduce support for and migrate to the common
  infrastructure, while more appropriate support for specific hardware
  constraints isn't available yet (remaining changes are strictly
  internal to the clock driver and won't affect peripheral drivers)

clkdev registration provides "alias names" for few clock items
- to not break those peripheral drivers which encode their component
  index into the name that is used for clock lookup (UART, SPI, USB)
- to not break those drivers which use names for the clock lookup which
  were encoded in the previous PPC_CLOCK implementation (NFC, VIU, CAN)
this workaround will get removed as these drivers get adjusted after
device tree based clock lookup has become available

Signed-off-by: Gerhard Sittig <redacted>
Hi Gerhard,

This looks OK to me. Do you want me to take it or will you keep the
series together? Note that I took "clk: wrap I/O access for improved
portability" into the clk tree already.

Regards,
Mike
Thank you for the feedback and for the interest!  It's nice to
hear that you like the central part of the series. :)


There will be another version of the series (v4), addressing the
remaining feedback, further reducing pre-enable workarounds,
eliminating the need for "shared gates" by adding more 'ipg'
clocks for serial communication (UART, SPI, CAN).  It's true that
the series has widened its scope after initial submission, but it
as well has much improved from the feedback.

This specific patch introduces an alternative clock driver which
is enabled by default, so it depends on the device tree data
being available before the code becomes operational.  And the
common clock platform driver might break those peripheral drivers
which haven't received their clock API use cleanup yet (earlier
parts of the series).


So I'd like to keep the series together until it has passed
review.  I will make sure that the series remains bisectable and
always keeps working when applied in sequence, and would prefer
to only start splitting it or staging parts of it later if
needed.

quoted
---
 arch/powerpc/platforms/512x/Kconfig           |   14 +-
 arch/powerpc/platforms/512x/Makefile          |    4 +-
 arch/powerpc/platforms/512x/clock-commonclk.c |  786 +++++++++++++++++++++++++
 include/linux/clk-provider.h                  |   16 +
 4 files changed, 818 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index fc9c1cb..c5fcdd0 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -1,9 +1,21 @@
+config MPC512x_COMMON_CLK
+       bool "MPC512x platform uses COMMON_CLK"
+       default y
+       depends on PPC_MPC512x
+       help
+         This option is only here to support tests and comparison
+         during development and migration.  This option will get
+         removed after the COMMON_CLK support for MPC512x has become
+         fully operational and all drivers were adjusted to explicitly
+         acquire their required clocks.
+
 config PPC_MPC512x
        bool "512x-based boards"
        depends on 6xx
        select FSL_SOC
        select IPIC
-       select PPC_CLOCK
+       select PPC_CLOCK if !MPC512x_COMMON_CLK
+       select COMMON_CLK if MPC512x_COMMON_CLK
        select PPC_PCI_CHOICE
        select FSL_PCI if PCI
        select ARCH_WANT_OPTIONAL_GPIOLIB
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
index 72fb934..1e05f9d 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -1,7 +1,9 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-y                          += clock.o mpc512x_shared.o
+obj-$(CONFIG_PPC_CLOCK)                += clock.o
+obj-$(CONFIG_COMMON_CLK)       += clock-commonclk.o
+obj-y                          += mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)      += mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)  += mpc512x_generic.o
 obj-$(CONFIG_PDM360NG)         += pdm360ng.o
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
new file mode 100644
index 0000000..762ee85
--- /dev/null
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -0,0 +1,786 @@
+/*
+ * Copyright (C) 2013 DENX Software Engineering
+ *
+ * Gerhard Sittig, <gsi@denx.de>
+ *
+ * common clock driver support for the MPC512x platform
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <asm/mpc5121.h>
+#include <dt-bindings/clock/mpc512x-clock.h>
+
+#include "mpc512x.h"           /* our public mpc5121_clk_init() API */
+
+/* helpers to keep the MCLK intermediates "somewhere" in our table */
+enum {
+       MCLK_IDX_MUX0,
+       MCLK_IDX_EN0,
+       MCLK_IDX_DIV0,
+       MCLK_IDX_MUX1,
+       MCLK_MAX_IDX,
+};
+
+#define NR_PSCS                        12
+#define NR_MSCANS              4
+#define NR_SPDIFS              1
+#define NR_MCLKS               (NR_PSCS + NR_MSCANS + NR_SPDIFS)
+
+/* extend the public set of clocks by adding internal slots for management */
+enum {
+       /* arrange for adjacent numbers after the public set */
+       MPC512x_CLK_START_PRIVATE = MPC512x_CLK_LAST_PUBLIC,
+       /* clocks which aren't announced to the public */
+       MPC512x_CLK_DDR,
+       MPC512x_CLK_MEM,
+       MPC512x_CLK_IIM,
+       MPC512x_CLK_SDHC_2,
+       /* intermediates in div+gate combos or fractional dividers */
+       MPC512x_CLK_DDR_UG,
+       MPC512x_CLK_SDHC_x4,
+       MPC512x_CLK_SDHC_UG,
+       MPC512x_CLK_DIU_x4,
+       MPC512x_CLK_DIU_UG,
+       MPC512x_CLK_MBX_BUS_UG,
+       MPC512x_CLK_MBX_UG,
+       MPC512x_CLK_MBX_3D_UG,
+       MPC512x_CLK_PCI_UG,
+       MPC512x_CLK_NFC_UG,
+       MPC512x_CLK_LPC_UG,
+       MPC512x_CLK_SPDIF_TX_IN,
+       /* intermediates for the mux+gate+div+mux MCLK generation */
+       MPC512x_CLK_MCLKS_FIRST,
+       MPC512x_CLK_MCLKS_LAST = MPC512x_CLK_MCLKS_FIRST
+                               + NR_MCLKS * MCLK_MAX_IDX,
+       /* internal, symbolic spec for the number of slots */
+       MPC512x_CLK_LAST_PRIVATE,
+};
+
+/* data required for the OF clock provider registration */
+static struct clk *clks[MPC512x_CLK_LAST_PRIVATE];
+static struct clk_onecell_data clk_data;
+
+/* CCM register access */
+static struct mpc512x_ccm __iomem *clkregs;
+static DEFINE_SPINLOCK(clklock);
+
+/* convenience wrappers around the common clk API */
+static inline struct clk *mpc512x_clk_fixed(const char *name, int rate)
+{
+       return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);
+}
+
+static inline struct clk *mpc512x_clk_factor(
+       const char *name, const char *parent_name,
+       int mul, int div)
+{
+       int clkflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       return clk_register_fixed_factor(NULL, name, parent_name, clkflags,
+                                        mul, div);
+}
+
+static inline struct clk *mpc512x_clk_divider(
+       const char *name, const char *parent_name, u8 clkflags,
+       u32 __iomem *reg, u8 pos, u8 len, int divflags)
+{
+       return clk_register_divider(NULL, name, parent_name, clkflags,
+                                   reg, pos, len, divflags, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_divtable(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos, u8 len,
+       const struct clk_div_table *divtab)
+{
+       u8 divflags;
+
+       divflags = 0;
+       return clk_register_divider_table(NULL, name, parent_name, 0,
+                                         reg, pos, len, divflags,
+                                         divtab, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_gated(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos)
+{
+       int clkflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       return clk_register_gate(NULL, name, parent_name, clkflags,
+                                reg, pos, 0, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_muxed(const char *name,
+       const char **parent_names, int parent_count,
+       u32 __iomem *reg, u8 pos, u8 len)
+{
+       int clkflags;
+       u8 muxflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       muxflags = 0;
+       return clk_register_mux(NULL, name,
+                               parent_names, parent_count, clkflags,
+                               reg, pos, len, muxflags, &clklock);
+}
+
+/* helper to isolate a bit field from a register */
+static inline int get_bit_field(uint32_t __iomem *reg, uint8_t pos, uint8_t len)
+{
+       uint32_t val;
+
+       val = in_be32(reg);
+       val >>= pos;
+       val &= (1 << len) - 1;
+       return val;
+}
+
+/* get the SPMF and translate it into the "sys pll" multiplier */
+static int get_spmf_mult(void)
+{
+       static int spmf_to_mult[] = {
+               68, 1, 12, 16, 20, 24, 28, 32,
+               36, 40, 44, 48, 52, 56, 60, 64,
+       };
+       int spmf;
+
+       spmf = get_bit_field(&clkregs->spmr, 24, 4);
+       return spmf_to_mult[spmf];
+}
+
+/*
+ * get the SYS_DIV value and translate it into a divide factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * divide ratio is fractional
+ */
+static int get_sys_div_x2(void)
+{
+       static int sysdiv_code_to_x2[] = {
+               4, 5, 6, 7, 8, 9, 10, 14,
+               12, 16, 18, 22, 20, 24, 26, 30,
+               28, 32, 34, 38, 36, 40, 42, 46,
+               44, 48, 50, 54, 52, 56, 58, 62,
+               60, 64, 66,
+       };
+       int divcode;
+
+       divcode = get_bit_field(&clkregs->scfr2, 26, 6);
+       return sysdiv_code_to_x2[divcode];
+}
+
+/*
+ * get the CPMF value and translate it into a multiplier factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * multiplier ratio is fractional
+ */
+static int get_cpmf_mult_x2(void)
+{
+       static int cpmf_to_mult[] = {
+               72, 2, 2, 3, 4, 5, 6, 7,
+       };
+       int cpmf;
+
+       cpmf = get_bit_field(&clkregs->spmr, 16, 4);
+       return cpmf_to_mult[cpmf];
+}
+
+/*
+ * some of the clock dividers do scale in a linear way, yet not all of
+ * their bit combinations are legal; use a divider table to get a
+ * resulting set of applicable divider values
+ */
+
+/* applies to the IPS_DIV, and PCI_DIV values */
+static struct clk_div_table divtab_2346[] = {
+       { .val = 2, .div = 2, },
+       { .val = 3, .div = 3, },
+       { .val = 4, .div = 4, },
+       { .val = 6, .div = 6, },
+       { .div = 0, },
+};
+
+/* applies to the MBX_DIV, LPC_DIV, and NFC_DIV values */
+static struct clk_div_table divtab_1234[] = {
+       { .val = 1, .div = 1, },
+       { .val = 2, .div = 2, },
+       { .val = 3, .div = 3, },
+       { .val = 4, .div = 4, },
+       { .div = 0, },
+};
+
+static int get_freq_from_dt(char *propname)
+{
+       struct device_node *np;
+       const unsigned int *prop;
+       int val;
+
+       val = 0;
+       np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
+       if (np) {
+               prop = of_get_property(np, propname, NULL);
+               if (prop)
+                       val = *prop;
+           of_node_put(np);
+       }
+       return val;
+}
+
+static void mpc512x_clk_preset_data(void)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(clks); i++)
+               clks[i] = ERR_PTR(-ENODEV);
+}
+
+/*
+ * - receives the "bus frequency" from the caller (that's the IPS clock
+ *   rate, the historical source of clock information)
+ * - fetches the system PLL multiplier and divider values as well as the
+ *   IPS divider value from hardware
+ * - determines the REF clock rate either from the XTAL/OSC spec (if
+ *   there is a device tree node describing the oscillator) or from the
+ *   IPS bus clock (supported for backwards compatibility, such that
+ *   setups without XTAL/OSC specs keep working)
+ * - creates the "ref" clock item in the clock tree, such that
+ *   subsequent code can create the remainder of the hierarchy (REF ->
+ *   SYS -> CSB -> IPS) from the REF clock rate and the returned mul/div
+ *   values
+ */
+static void mpc512x_clk_setup_ref_clock(int bus_freq,
+       int *sys_mul, int *sys_div, int *ips_div)
+{
+       struct clk *osc_clk;
+       int calc_freq;
+
+       /* fetch mul/div factors from the hardware */
+       *sys_mul = get_spmf_mult();
+       *sys_mul *= 2;          /* compensate for the fractional divider */
+       *sys_div = get_sys_div_x2();
+       *ips_div = get_bit_field(&clkregs->scfr1, 23, 3);
+
+       /* lookup the oscillator node */
+       osc_clk = clk_get(NULL, "osc");
+       if (osc_clk) {
+               /* descend REF directly from OSC, verify the IPS rate */
+               clks[MPC512x_CLK_REF] = mpc512x_clk_factor("ref", "osc", 1, 1);
+               calc_freq = clk_get_rate(clks[MPC512x_CLK_REF]);
+               calc_freq *= *sys_mul;
+               calc_freq /= *sys_div;
+               calc_freq /= 2;
+               calc_freq /= *ips_div;
+               if (bus_freq && calc_freq != bus_freq)
+                       pr_warn("calc rate %d != OF spec %d\n",
+                               calc_freq, bus_freq);
+       } else {
+               /* calculate OSC rate and create REF from the freq value */
+               calc_freq = bus_freq;   /* start with IPS */
+               calc_freq *= *ips_div;  /* IPS -> CSB */
+               calc_freq *= 2;         /* CSB -> SYS */
+               calc_freq *= *sys_div;  /* SYS -> PLL out */
+               calc_freq /= *sys_mul;  /* PLL out -> REF == OSC */
+               clks[MPC512x_CLK_REF] = mpc512x_clk_fixed("ref", calc_freq);
+       }
+}
+
+/*
+ * helper code for the MCLK subtree setup
+ *
+ * the overview in section 5.2.4 of the MPC5121e Reference Manual rev4
+ * suggests that all instances of the "PSC clock generation" are equal,
+ * and that one might re-use the PSC setup for MSCAN clock generation
+ * (section 5.2.5) as well, at least the logic if not the data for
+ * description
+ *
+ * the details (starting at page 5-20) show differences in the specific
+ * inputs of the first mux stage ("can clk in", "spdif tx"), and the
+ * factual non-availability of the second mux stage (it's present yet
+ * only one input is valid)
+ *
+ * the MSCAN clock related registers (starting at page 5-35) all
+ * reference "spdif clk" at the first mux stage and don't mention any
+ * "can clk" at all, which somehow is unexpected
+ *
+ * TODO re-check the document, and clarify whether the RM is correct in
+ * the overview or in the details, and whether the difference is a
+ * clipboard induced error or results from chip revisions
+ *
+ * it turns out that the RM rev4 as of 2012-06 talks about "can" for the
+ * PSCs while RM rev3 as of 2008-10 talks about "spdif", so I guess that
+ * first a doc update is required which better reflects reality in the
+ * SoC before the implementation should follow while no questions remain
+ */
+
+/*
+ * note that this declaration raises a checkpatch warning, but
+ * it's the very data type which <linux/clk-provider.h> expects,
+ * making this declaration pass checkpatch will break compilation
+ */
+static const char *parent_names_mux0[] = {
+       "sys", "ref", "psc-mclk-in", "spdif-tx",
+};
+
+enum mclk_type {
+       MCLK_TYPE_PSC,
+       MCLK_TYPE_MSCAN,
+       MCLK_TYPE_SPDIF,
+};
+
+struct mclk_setup_data {
+       enum mclk_type type;
+       int comp_idx;
+       bool has_mclk1;
+       int bit_sccr1, bit_sccr2;
+       const char *name_mux0;
+       const char *name_en0;
+       const char *name_div0;
+       const char *parent_names_mux1[2];
+       const char *name_mux1;
+       const char *name_mclk;
+};
+
+#define MCLK_SETUP_DATA_PSC(id) { \
+       MCLK_TYPE_PSC, id, \
+       0, 27 - id, -1, \
+       "psc" #id "-mux0", \
+       "psc" #id "-en0", \
+       "psc" #id "_mclk_div", \
+       { "psc" #id "_mclk_div", "dummy", }, \
+       "psc" #id "_mclk_out", \
+       "psc" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_MSCAN(id) { \
+       MCLK_TYPE_MSCAN, id, \
+       0, -1, 25, \
+       "mscan" #id "-mux0", \
+       "mscan" #id "-en0", \
+       "mscan" #id "_mclk_div", \
+       { "mscan" #id "_mclk_div", "dummy", }, \
+       "mscan" #id "_mclk_out", \
+       "mscan" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_SPDIF { \
+       MCLK_TYPE_SPDIF, 0, \
+       1, -1, 23, \
+       "spdif-mux0", \
+       "spdif-en0", \
+       "spdif_mclk_div", \
+       { "spdif_mclk_div", "spdif-rx", }, \
+       "spdif_mclk_out", \
+       "spdif_mclk", \
+}
+
+static struct mclk_setup_data mclk_psc_data[] = {
+       MCLK_SETUP_DATA_PSC(0),
+       MCLK_SETUP_DATA_PSC(1),
+       MCLK_SETUP_DATA_PSC(2),
+       MCLK_SETUP_DATA_PSC(3),
+       MCLK_SETUP_DATA_PSC(4),
+       MCLK_SETUP_DATA_PSC(5),
+       MCLK_SETUP_DATA_PSC(6),
+       MCLK_SETUP_DATA_PSC(7),
+       MCLK_SETUP_DATA_PSC(8),
+       MCLK_SETUP_DATA_PSC(9),
+       MCLK_SETUP_DATA_PSC(10),
+       MCLK_SETUP_DATA_PSC(11),
+};
+
+static struct mclk_setup_data mclk_mscan_data[] = {
+       MCLK_SETUP_DATA_MSCAN(0),
+       MCLK_SETUP_DATA_MSCAN(1),
+       MCLK_SETUP_DATA_MSCAN(2),
+       MCLK_SETUP_DATA_MSCAN(3),
+};
+
+static struct mclk_setup_data mclk_spdif_data[] = {
+       MCLK_SETUP_DATA_SPDIF,
+};
+
+/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
+static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
+{
+       size_t clks_idx_pub, clks_idx_int;
+       u32 __iomem *mccr_reg;  /* MCLK control register (mux, en, div) */
+       u32 __iomem *sccr_reg;  /* system clock control register (enable) */
+       int sccr_bit;
+       int div;
+
+       /* derive a few parameters from the component type and index */
+       switch (entry->type) {
+       case MCLK_TYPE_PSC:
+               clks_idx_pub = MPC512x_CLK_PSC0_MCLK + entry->comp_idx;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (entry->comp_idx) * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->psc_ccr[entry->comp_idx];
+               break;
+       case MCLK_TYPE_MSCAN:
+               clks_idx_pub = MPC512x_CLK_MSCAN0_MCLK + entry->comp_idx;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (NR_PSCS + entry->comp_idx) * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->mscan_ccr[entry->comp_idx];
+               break;
+       case MCLK_TYPE_SPDIF:
+               clks_idx_pub = MPC512x_CLK_SPDIF_MCLK;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->spccr;
+               break;
+       default:
+               return;
+       }
+       if (entry->bit_sccr1 >= 0) {
+               sccr_reg = &clkregs->sccr1;
+               sccr_bit = entry->bit_sccr1;
+       } else if (entry->bit_sccr2 >= 0) {
+               sccr_reg = &clkregs->sccr2;
+               sccr_bit = entry->bit_sccr2;
+       } else {
+               sccr_reg = NULL;
+       }
+
+       /*
+        * this was grabbed from the PPC_CLOCK implementation, which
+        * enforced a specific MCLK divider while the clock was gated
+        * during setup (that's a documented hardware requirement)
+        *
+        * the PPC_CLOCK implementation might even have violated the
+        * "MCLK <= IPS" constraint, the fixed divider value of 1
+        * results in a divider of 2 and thus MCLK = SYS/2 which equals
+        * CSB which is greater than IPS; the serial port setup may have
+        * adjusted the divider which the clock setup might have left in
+        * an undesirable state
+        *
+        * initial setup is:
+        * - MCLK 0 from SYS
+        * - MCLK DIV such to not exceed the IPS clock
+        * - MCLK 0 enabled
+        * - MCLK 1 from MCLK DIV
+        */
+       div = clk_get_rate(clks[MPC512x_CLK_SYS]);
+       div /= clk_get_rate(clks[MPC512x_CLK_IPS]);
+       out_be32(mccr_reg, (0 << 16));
+       out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
+       out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
+
+       /*
+        * create the 'struct clk' items of the MCLK's clock subtree
+        *
+        * note that by design we always create all nodes and won't take
+        * shortcuts here, because
+        * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
+        *   selectable inputs to the CFM while those who "actually use"
+        *   the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
+        *   for their bitrate
+        * - in the absence of "aliases" for clocks we need to create
+        *   individial 'struct clk' items for whatever might get
+        *   referenced or looked up, even if several of those items are
+        *   identical from the logical POV (their rate value)
+        * - for easier future maintenance and for better reflection of
+        *   the SoC's documentation, it appears appropriate to generate
+        *   clock items even for those muxers which actually are NOPs
+        *   (those with two inputs of which one is reserved)
+        */
+       clks[clks_idx_int + MCLK_IDX_MUX0] = mpc512x_clk_muxed(
+                       entry->name_mux0,
+                       &parent_names_mux0[0], ARRAY_SIZE(parent_names_mux0),
+                       mccr_reg, 14, 2);
+       clks[clks_idx_int + MCLK_IDX_EN0] = mpc512x_clk_gated(
+                       entry->name_en0, entry->name_mux0,
+                       mccr_reg, 16);
+       clks[clks_idx_int + MCLK_IDX_DIV0] = mpc512x_clk_divider(
+                       entry->name_div0,
+                       entry->name_en0, CLK_SET_RATE_GATE,
+                       mccr_reg, 17, 15, 0);
+       if (entry->has_mclk1) {
+               clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_muxed(
+                               entry->name_mux1,
+                               &entry->parent_names_mux1[0],
+                               ARRAY_SIZE(entry->parent_names_mux1),
+                               mccr_reg, 7, 1);
+       } else {
+               clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_factor(
+                               entry->name_mux1, entry->parent_names_mux1[0],
+                               1, 1);
+       }
+       if (sccr_reg) {
+               clks[clks_idx_pub] = mpc512x_clk_gated(
+                               entry->name_mclk,
+                               entry->name_mux1, sccr_reg, sccr_bit);
+       } else {
+               clks[clks_idx_pub] = mpc512x_clk_factor(
+                               entry->name_mclk,
+                               entry->name_mux1, 1, 1);
+       }
+
+       /*
+        * without this "clock device" registration, "simple" lookups in
+        * the SPI master initialization and serial port setup will fail
+        *
+        * those drivers need to get adjusted to lookup their required
+        * clocks from device tree specs, and device tree nodes need to
+        * provide the clock specs, before this clkdev registration
+        * becomes obsolete
+        */
+       clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
+}
+
+static void mpc512x_clk_setup_mclks(struct mclk_setup_data *table, size_t count)
+{
+       while (count-- > 0)
+               mpc512x_clk_setup_mclk(table++);
+}
+
+static void mpc512x_clk_setup_clock_tree(int busfreq)
+{
+       int sys_mul, sys_div, ips_div;
+       int mul, div;
+       int freq;
+
+       /*
+        * TODO
+        * - consider whether to handle clocks which have both gates and
+        *   dividers via intermediates or by means of composites
+        * - fractional dividers appear to not map well to composites
+        *   since they can be seen as a fixed multiplier and an
+        *   adjustable divider, while composites can only combine at
+        *   most one of a mux, div, and gate each into one 'struct clk'
+        *   item
+        * - PSC/MSCAN/SPDIF clock generation OTOH already is very
+        *   specific and cannot get mapped to componsites (at least not
+        *   a single one, maybe two of them, but see the comment about
+        *   "intermediates are referenced from elsewhere, too")
+        * - trim the list of auto-enabled clocks after drivers acquire
+        *   them correctly as needed
+        */
+
+       /* regardless of whether XTAL/OSC exists, have REF created */
+       mpc512x_clk_setup_ref_clock(busfreq, &sys_mul, &sys_div, &ips_div);
+
+       /* now setup the REF -> SYS -> CSB -> IPS hierarchy */
+       clks[MPC512x_CLK_SYS] = mpc512x_clk_factor("sys", "ref",
+                                                  sys_mul, sys_div);
+       clks[MPC512x_CLK_CSB] = mpc512x_clk_factor("csb", "sys", 1, 2);
+       clks[MPC512x_CLK_IPS] = mpc512x_clk_divtable("ips", "csb",
+                                                    &clkregs->scfr1, 23, 3,
+                                                    divtab_2346);
+
+       /* now setup anything below SYS and CSB and IPS */
+       clks[MPC512x_CLK_DDR_UG] = mpc512x_clk_factor("ddr-ug", "sys", 1, 2);
+       clks[MPC512x_CLK_SDHC_x4] = mpc512x_clk_factor("sdhc-x4", "csb", 4, 1);
+       clks[MPC512x_CLK_SDHC_UG] = mpc512x_clk_divider("sdhc-ug", "sdhc-x4", 0,
+                                                       &clkregs->scfr2, 0, 8,
+                                                       CLK_DIVIDER_ONE_BASED);
+       clks[MPC512x_CLK_DIU_x4] = mpc512x_clk_factor("diu-x4", "csb", 4, 1);
+       clks[MPC512x_CLK_DIU_UG] = mpc512x_clk_divider("diu-ug", "diu-x4", 0,
+                                                      &clkregs->scfr1, 0, 8,
+                                                      CLK_DIVIDER_ONE_BASED);
+
+       /*
+        * the "power architecture PLL" was setup from data which was
+        * sampled from the reset config word, at this point in time the
+        * configuration can be considered fixed and read only (i.e. no
+        * longer adjustable, or no longer in need of adjustment), which
+        * is why we don't register a PLL here but assume fixed factors
+        */
+       mul = get_cpmf_mult_x2();
+       div = 2;        /* compensate for the fractional factor */
+       clks[MPC512x_CLK_E300] = mpc512x_clk_factor("e300", "csb", mul, div);
+
+       clks[MPC512x_CLK_MBX_BUS_UG] = mpc512x_clk_factor("mbx-bus-ug", "csb",
+                                                         1, 2);
+       clks[MPC512x_CLK_MBX_UG] = mpc512x_clk_divtable("mbx-ug", "mbx-bus-ug",
+                                                       &clkregs->scfr1, 14, 3,
+                                                       divtab_1234);
+       clks[MPC512x_CLK_MBX_3D_UG] = mpc512x_clk_factor("mbx-3d-ug", "mbx-ug",
+                                                        1, 1);
+       clks[MPC512x_CLK_PCI_UG] = mpc512x_clk_divtable("pci-ug", "csb",
+                                                       &clkregs->scfr1, 20, 3,
+                                                       divtab_2346);
+       clks[MPC512x_CLK_NFC_UG] = mpc512x_clk_divtable("nfc-ug", "ips",
+                                                       &clkregs->scfr1, 8, 3,
+                                                       divtab_1234);
+       clks[MPC512x_CLK_LPC_UG] = mpc512x_clk_divtable("lpc-ug", "ips",
+                                                       &clkregs->scfr1, 11, 3,
+                                                       divtab_1234);
+
+       clks[MPC512x_CLK_LPC] = mpc512x_clk_gated("lpc", "lpc-ug",
+                                                 &clkregs->sccr1, 30);
+       clks[MPC512x_CLK_NFC] = mpc512x_clk_gated("nfc", "nfc-ug",
+                                                 &clkregs->sccr1, 29);
+       clks[MPC512x_CLK_PATA] = mpc512x_clk_gated("pata", "ips",
+                                                  &clkregs->sccr1, 28);
+       mpc512x_clk_setup_mclks(mclk_psc_data, ARRAY_SIZE(mclk_psc_data));
+       clks[MPC512x_CLK_PSC_FIFO] = mpc512x_clk_gated("psc-fifo", "ips",
+                                                      &clkregs->sccr1, 15);
+       clks[MPC512x_CLK_SATA] = mpc512x_clk_gated("sata", "ips",
+                                                  &clkregs->sccr1, 14);
+       clks[MPC512x_CLK_FEC] = mpc512x_clk_gated("fec", "ips",
+                                                 &clkregs->sccr1, 13);
+       clks[MPC512x_CLK_PCI] = mpc512x_clk_gated("pci", "pci-ug",
+                                                 &clkregs->sccr1, 11);
+       clks[MPC512x_CLK_DDR] = mpc512x_clk_gated("ddr", "ddr-ug",
+                                                 &clkregs->sccr1, 10);
+
+       clks[MPC512x_CLK_DIU] = mpc512x_clk_gated("diu", "diu-ug",
+                                                 &clkregs->sccr2, 31);
+       clks[MPC512x_CLK_AXE] = mpc512x_clk_gated("axe", "csb",
+                                                 &clkregs->sccr2, 30);
+       clks[MPC512x_CLK_MEM] = mpc512x_clk_gated("mem", "ips",
+                                                 &clkregs->sccr2, 29);
+       clks[MPC512x_CLK_USB1] = mpc512x_clk_gated("usb1", "csb",
+                                                  &clkregs->sccr2, 28);
+       clks[MPC512x_CLK_USB2] = mpc512x_clk_gated("usb2", "csb",
+                                                  &clkregs->sccr2, 27);
+       clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips",
+                                                 &clkregs->sccr2, 26);
+       mpc512x_clk_setup_mclks(mclk_mscan_data, ARRAY_SIZE(mclk_mscan_data));
+       clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug",
+                                                  &clkregs->sccr2, 24);
+       mpc512x_clk_setup_mclks(mclk_spdif_data, ARRAY_SIZE(mclk_spdif_data));
+       clks[MPC512x_CLK_MBX_BUS] = mpc512x_clk_gated("mbx-bus", "mbx-bus-ug",
+                                                     &clkregs->sccr2, 22);
+       clks[MPC512x_CLK_MBX] = mpc512x_clk_gated("mbx", "mbx-ug",
+                                                 &clkregs->sccr2, 21);
+       clks[MPC512x_CLK_MBX_3D] = mpc512x_clk_gated("mbx-3d", "mbx-3d-ug",
+                                                    &clkregs->sccr2, 20);
+       clks[MPC512x_CLK_IIM] = mpc512x_clk_gated("iim", "csb",
+                                                 &clkregs->sccr2, 19);
+       clks[MPC512x_CLK_VIU] = mpc512x_clk_gated("viu", "csb",
+                                                 &clkregs->sccr2, 18);
+       clks[MPC512x_CLK_SDHC_2] = mpc512x_clk_gated("sdhc-2", "sdhc-ug",
+                                                    &clkregs->sccr2, 17);
+
+       /*
+        * externally provided clocks (when implemented in hardware,
+        * device tree may specify values which otherwise were unknown)
+        */
+       freq = get_freq_from_dt("psc_mclk_in");
+       if (!freq)
+               freq = 25000000;
+       clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq);
+       freq = get_freq_from_dt("spdif_tx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_tx_in", freq);
+       freq = get_freq_from_dt("spdif_rx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_rx_in", freq);
+
+       /* fixed frequency for AC97, always 24.567MHz */
+       clks[MPC512x_CLK_AC97] = mpc512x_clk_fixed("ac97", 24567000);
+
+       /* clkdev registration for compatibility reasons */
+       clk_register_clkdev(clks[MPC512x_CLK_REF], "ref_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_VIU], "viu_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_NFC], "nfc_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_USB1], "usb1_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_USB2], "usb2_clk", NULL);
+
+       pr_debug("clock tree setup complete\n");
+       freq = clk_get_rate(clks[MPC512x_CLK_E300]);
+       pr_debug("derived PPC freq [%d]\n", freq);
+       freq = clk_get_rate(clks[MPC512x_CLK_IPS]);
+       pr_debug("derived IPS freq [%d]\n", freq);
+       freq = clk_get_rate(clks[MPC512x_CLK_LPC]);
+       pr_debug("derived LPC freq [%d]\n", freq);
+
+       /* enable some of the clocks here unconditionally because ... */
+       pr_debug("automatically enabling some clocks\n");
+       /* some are essential yet never get claimed by any driver */
+       clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
+       clk_prepare_enable(clks[MPC512x_CLK_E300]);     /* PowerPC CPU */
+       clk_prepare_enable(clks[MPC512x_CLK_DDR]);      /* DRAM */
+       clk_prepare_enable(clks[MPC512x_CLK_MEM]);      /* SRAM */
+       clk_prepare_enable(clks[MPC512x_CLK_IPS]);      /* SoC periph */
+       clk_prepare_enable(clks[MPC512x_CLK_LPC]);      /* boot media */
+       /* some are required yet no dependencies were declared */
+       clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
+       /* some are not yet acquired by their respective drivers */
+       clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
+       clk_prepare_enable(clks[MPC512x_CLK_FEC]);      /* network, NFS */
+       clk_prepare_enable(clks[MPC512x_CLK_DIU]);      /* display */
+       clk_prepare_enable(clks[MPC512x_CLK_I2C]);
+       /*
+        * some have their individual clock subtree with separate clock
+        * items and their individual enable counters, yet share a
+        * common gate (refer to the same register location) while the
+        * common clock driver code is not aware of the fact and the
+        * platform's code doesn't provide specific support either
+        *
+        * what might happen is that e.g. enabling two MSCAN clock items
+        * and disabling one of them will disable the common gate and
+        * thus break the other MSCAN clock as well
+        */
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN0_MCLK]);
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN1_MCLK]);
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN2_MCLK]);
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN3_MCLK]);
+}
+
+/*
+ * registers the set of public clocks (those listed in the dt-bindings/
+ * header file) for OF lookups, keeps the intermediates private to us
+ */
+static void mpc5121_clk_register_of_provider(struct device_node *np)
+{
+       clk_data.clks = clks;
+       clk_data.clk_num = MPC512x_CLK_LAST_PUBLIC + 1; /* _not_ ARRAY_SIZE() */
+       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+int __init mpc5121_clk_init(void)
+{
+       struct device_node *clk_np;
+       int busfreq;
+
+       /* map the clock control registers */
+       clk_np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+       if (!clk_np)
+               return -ENODEV;
+       clkregs = of_iomap(clk_np, 0);
+       WARN_ON(!clkregs);
+
+       /* invalidate all not yet registered clock slots */
+       mpc512x_clk_preset_data();
+
+       /*
+        * have the device tree scanned for "fixed-clock" nodes (which
+        * includes the oscillator node if the board's DT provides one)
+        */
+       of_clk_init(NULL);
+
+       /*
+        * add a dummy clock for those situations where a clock spec is
+        * required yet no real clock is involved
+        */
+       clks[MPC512x_CLK_DUMMY] = mpc512x_clk_fixed("dummy", 0);
+
+       /*
+        * have all the real nodes in the clock tree populated from REF
+        * down to all leaves, either starting from the OSC node or from
+        * a REF root that was created from the IPS bus clock input
+        */
+       busfreq = get_freq_from_dt("bus-frequency");
+       mpc512x_clk_setup_clock_tree(busfreq);
+
+       /* register as an OF clock provider */
+       mpc5121_clk_register_of_provider(clk_np);
+
+       return 0;
+}
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index c4f7799..7f8fc64 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -497,6 +497,20 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
  * for improved portability across platforms
  */
 
+#if IS_ENABLED(CONFIG_PPC)
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+       return ioread32be(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+       iowrite32be(val, reg);
+}
+
+#else  /* platform dependent I/O accessors */
+
 static inline u32 clk_readl(u32 __iomem *reg)
 {
        return readl(reg);
@@ -507,5 +521,7 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
        writel(val, reg);
 }
 
+#endif /* platform dependent I/O accessors */
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
-- 
1.7.10.4

virtually yours
Gerhard Sittig
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

[PATCH v3 18/31] dts: mpc512x: add clock specs for client lookups

From: Gerhard Sittig <hidden>
Date: 2013-08-03 15:36:30

[ trimming the CC: list to device tree and ARM(clock) and PPC ]

On Fri, Aug 02, 2013 at 16:41 -0700, Mike Turquette wrote:
Quoting Gerhard Sittig (2013-07-22 05:14:45)
quoted
this addresses the client side of device tree based clock lookups

add clock specifiers to the mbx, nfc, mscan, sdhc, i2c, axe, diu, viu,
mdio, fec, usb, pata, psc, psc fifo, and pci nodes in the shared
mpc5121.dtsi include

these specs map 'clock-names' encoded in drivers to their respective
'struct clk' items in the platform's clock driver

Signed-off-by: Gerhard Sittig <redacted>
Reviewed-by: Mike Turquette <redacted>
Thank you for the review, Mike!

Please note that there will be another update for the series.
These clock specs for client side lookups will have additional
'ipg' clock items next to 'mclk' for the PSC (UART, SPI) and
MSCAN (CAN) nodes.  But this change is straight forward.

quoted
---
 arch/powerpc/boot/dts/mpc5121.dtsi |   79 ++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
index 8f4cba0..3657ae6 100644
--- a/arch/powerpc/boot/dts/mpc5121.dtsi
+++ b/arch/powerpc/boot/dts/mpc5121.dtsi
@@ -51,6 +51,10 @@
                compatible = "fsl,mpc5121-mbx";
                reg = <0x20000000 0x4000>;
                interrupts = <66 0x8>;
+               clocks = <&clks MPC512x_CLK_MBX_BUS>,
+                        <&clks MPC512x_CLK_MBX_3D>,
+                        <&clks MPC512x_CLK_MBX>;
+               clock-names = "mbx-bus", "mbx-3d", "mbx";
        };
 
        sram@30000000 {
@@ -64,6 +68,8 @@
                interrupts = <6 8>;
                #address-cells = <1>;
                #size-cells = <1>;
+               clocks = <&clks MPC512x_CLK_NFC>;
+               clock-names = "per";
        };
 
        localbus@80000020 {
@@ -153,12 +159,22 @@
                        compatible = "fsl,mpc5121-mscan";
                        reg = <0x1300 0x80>;
                        interrupts = <12 0x8>;
+                       clocks = <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN0_MCLK>;
+                       clock-names = "ips", "sys", "ref", "mclk";
                };
 
                can@1380 {
                        compatible = "fsl,mpc5121-mscan";
                        reg = <0x1380 0x80>;
                        interrupts = <13 0x8>;
+                       clocks = <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN1_MCLK>;
+                       clock-names = "ips", "sys", "ref", "mclk";
                };
 
                sdhc@1500 {
@@ -167,6 +183,9 @@
                        interrupts = <8 0x8>;
                        dmas = <&dma0 30>;
                        dma-names = "rx-tx";
+                       clocks = <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SDHC>;
+                       clock-names = "ipg", "per";
                };
 
                i2c@1700 {
@@ -175,6 +194,8 @@
                        compatible = "fsl,mpc5121-i2c", "fsl-i2c";
                        reg = <0x1700 0x20>;
                        interrupts = <9 0x8>;
+                       clocks = <&clks MPC512x_CLK_I2C>;
+                       clock-names = "per";
                };
 
                i2c@1720 {
@@ -183,6 +204,8 @@
                        compatible = "fsl,mpc5121-i2c", "fsl-i2c";
                        reg = <0x1720 0x20>;
                        interrupts = <10 0x8>;
+                       clocks = <&clks MPC512x_CLK_I2C>;
+                       clock-names = "per";
                };
 
                i2c@1740 {
@@ -191,6 +214,8 @@
                        compatible = "fsl,mpc5121-i2c", "fsl-i2c";
                        reg = <0x1740 0x20>;
                        interrupts = <11 0x8>;
+                       clocks = <&clks MPC512x_CLK_I2C>;
+                       clock-names = "per";
                };
 
                i2ccontrol@1760 {
@@ -202,30 +227,46 @@
                        compatible = "fsl,mpc5121-axe";
                        reg = <0x2000 0x100>;
                        interrupts = <42 0x8>;
+                       clocks = <&clks MPC512x_CLK_AXE>;
+                       clock-names = "per";
                };
 
                display@2100 {
                        compatible = "fsl,mpc5121-diu";
                        reg = <0x2100 0x100>;
                        interrupts = <64 0x8>;
+                       clocks = <&clks MPC512x_CLK_DIU>;
+                       clock-names = "per";
                };
 
                can@2300 {
                        compatible = "fsl,mpc5121-mscan";
                        reg = <0x2300 0x80>;
                        interrupts = <90 0x8>;
+                       clocks = <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN2_MCLK>;
+                       clock-names = "ips", "sys", "ref", "mclk";
                };
 
                can@2380 {
                        compatible = "fsl,mpc5121-mscan";
                        reg = <0x2380 0x80>;
                        interrupts = <91 0x8>;
+                       clocks = <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN3_MCLK>;
+                       clock-names = "ips", "sys", "ref", "mclk";
                };
 
                viu@2400 {
                        compatible = "fsl,mpc5121-viu";
                        reg = <0x2400 0x400>;
                        interrupts = <67 0x8>;
+                       clocks = <&clks MPC512x_CLK_VIU>;
+                       clock-names = "per";
                };
 
                mdio@2800 {
@@ -233,6 +274,8 @@
                        reg = <0x2800 0x800>;
                        #address-cells = <1>;
                        #size-cells = <0>;
+                       clocks = <&clks MPC512x_CLK_FEC>;
+                       clock-names = "per";
                };
 
                eth0: ethernet@2800 {
@@ -241,6 +284,8 @@
                        reg = <0x2800 0x800>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <4 0x8>;
+                       clocks = <&clks MPC512x_CLK_FEC>;
+                       clock-names = "per";
                };
 
                /* USB1 using external ULPI PHY */
@@ -252,6 +297,8 @@
                        interrupts = <43 0x8>;
                        dr_mode = "otg";
                        phy_type = "ulpi";
+                       clocks = <&clks MPC512x_CLK_USB1>;
+                       clock-names = "per";
                };
 
                /* USB0 using internal UTMI PHY */
@@ -263,6 +310,8 @@
                        interrupts = <44 0x8>;
                        dr_mode = "otg";
                        phy_type = "utmi_wide";
+                       clocks = <&clks MPC512x_CLK_USB2>;
+                       clock-names = "per";
                };
 
                /* IO control */
@@ -281,6 +330,8 @@
                        compatible = "fsl,mpc5121-pata";
                        reg = <0x10200 0x100>;
                        interrupts = <5 0x8>;
+                       clocks = <&clks MPC512x_CLK_PATA>;
+                       clock-names = "per";
                };
 
                /* 512x PSCs are not 52xx PSC compatible */
@@ -292,6 +343,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC0_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC1 */
@@ -301,6 +354,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC1_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC2 */
@@ -310,6 +365,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC2_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC3 */
@@ -319,6 +376,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC3_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC4 */
@@ -328,6 +387,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC4_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC5 */
@@ -337,6 +398,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC5_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC6 */
@@ -346,6 +409,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC6_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC7 */
@@ -355,6 +420,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC7_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC8 */
@@ -364,6 +431,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC8_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC9 */
@@ -373,6 +442,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC9_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC10 */
@@ -382,6 +453,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC10_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC11 */
@@ -391,12 +464,16 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC11_MCLK>;
+                       clock-names = "mclk";
                };
 
                pscfifo@11f00 {
                        compatible = "fsl,mpc5121-psc-fifo";
                        reg = <0x11f00 0x100>;
                        interrupts = <40 0x8>;
+                       clocks = <&clks MPC512x_CLK_PSC_FIFO>;
+                       clock-names = "per";
                };
 
                dma0: dma@14000 {
@@ -414,6 +491,8 @@
                #address-cells = <3>;
                #size-cells = <2>;
                #interrupt-cells = <1>;
+               clocks = <&clks MPC512x_CLK_PCI>;
+               clock-names = "per";
 
                reg = <0x80008500 0x100 /* internal registers */
                       0x80008300 0x8>; /* config space access registers */
-- 
1.7.10.4

virtually yours
Gerhard Sittig
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

[PATCH v3 11/31] net: can: mscan: improve clock API use

From: Gerhard Sittig <hidden>
Date: 2013-08-03 17:07:38

[ trimming the CC: list a bit, as this is CAN and clock specific,
  keeping Mark Brown and Greg KH for the UART and SPI part ]

On Tue, Jul 23, 2013 at 14:33 +0200, Marc Kleine-Budde wrote:
On 07/23/2013 01:53 PM, Gerhard Sittig wrote:
quoted
On Mon, Jul 22, 2013 at 14:31 +0200, Marc Kleine-Budde wrote:
quoted
On 07/22/2013 02:14 PM, Gerhard Sittig wrote:
quoted
the .get_clock() callback is run from probe() and might allocate
resources, introduce a .put_clock() callback that is run from remove()
to undo any allocation activities
looks good
quoted
use devm_get_clk() upon lookup (for SYS and REF) to have the clocks put
upon driver unload
fine
quoted
assume that resources get prepared but not necessarily enabled in the
setup phase, make the open() and close() callbacks of the CAN network
device enable and disable a previously acquired and prepared clock
I think you should call prepare_enable and disable_unprepare in the
open/close functions.
After more local research, which totally eliminated the need to
pre-enable the CAN related clocks, but might need more discussion
as it touches the common gate support, I've learned something
more:

The CAN clock needs to get enabled during probe() already, since
registers get accessed between probe() for the driver and open()
for the network device -- while access to peripheral registers
crashes the kernel when clocks still are disabled (other hardware
may just hang or provide fake data, neither of this is OK).
Then call prepare_enable(); before and disable_unprepare(); after
accessing the registers. Have a look at the flexcan driver.
OK, your feedback made me notice that I mentally have mixed
peripheral access clocks ('ipg') and bitrate clocks ('per') in
the past versions of the driver.

Fixing this, telling 'ipg' and 'per' apart, "in bypassing"
eliminates the need for "shared clock gates".  Since the MCLK
subtree of the clock tree apply to both the CAN controller and
the PSC controller, I will have to adjust all of the following:
- the platform's clock driver, telling the gate for the registers
  and the mux/div for the bitrate apart
- the CAN driver, acquiring both the 'ipg' clock item for
  register access and the "can" clock for the bitrate, the latter
  may get derived from either 'ips' or 'mclk', while 'mclk' may
  be derived from either 'sys' or 'ref' (or 'ips' in this
  hardware while the mscan(4) driver doesn't use this feature)
- the UART and SPI drivers, acquiring both the 'ipg' clock item
  for register access and the 'mclk' item for the bitrate

This obsoletes the request for "shared gates" and eliminates
another pre-enable workaround in the clock driver backend.

It also is an improvement for the MPC512x platform, and remains
neutral to the MPC52xx platform.  It's clearly desirable and
useful, and doesn't break anything.  So I will do it.

[ the above applied to CAN, SPI, and UART; the remainder is
  specific to CAN only ]


But I won't try to even further widen the scope of the series, I
won't try to address each and every potential for improvement
which drivers may have had for several years and which happened
to not have been addressed yet.  This needs to stop at some
reasonable point.  I'm not refusing to improve, but I'm asking to
check what is reasonable and what needs to get avoided.

I already introduced a bug in a recent version of the series
which went unnoticed during review (the unbalanced error path in
the network device open routine).  I'd rather not mess with power
management aspects "in bypassing" in a driver that I'm unable to
test thoroughly.  Not when I'm trying to work on something
totally different (introducing proper common clock support) and
try to minimize risk and avoid damage.

quoted
But I see the point in your suggestion to prepare _and_ enable
the clock during open() as well -- to have open() cope with
whatever probe() did, after all the driver is shared among
platforms, which may differ in what they do during probe().
If you enable a clock to access the registers before open() (and disable
it afterwards), it should not harm any architecture that doesn't need
this clock enabled.
You suggest to turn on the clock during initialization, and turn
it off until the network device actually gets used?  I had a look
at the flexcan driver, saw that it used two clock items, as
outlined above for register access and for wired communication.
This is good.  But I somehow doubt that the flexcan driver will
work if the ipg clock gets disabled (I assume it's a shared clock
that happens to remain enabled since others use it as well).

I'd rather not open that can of worms, too.  My gut is telling me
that either the peripheral does weird things or will lose data
when its (register access) clock gets disabled.  I won't try to
address power management and save/restore issues in that driver
now, and I won't try to hunt down and instrument any register
access in the shared code paths of a driver for multiple
platforms which is full of callbacks.

That's just out of the scope of the series.  It may be desirable
to address this issue as well, but it shall be done in a separate
action, not now "in bypassing".  Thank you for understanding. :)
And I do appreciate your feedback and desire for even better
drivers, just disagree on what to do now in this very moment.


What we already have is:
- probe() and remove() for the driver, calling into clock setup
  and allocation and deallocation routines
- no allocation for MPC52xx and thus no deallocation, keeping the
  status of how things used to be
- allocation of a "can" clock for MPC512x and the respective
  deallocation
- open() and close() for the network device, which prepare/enable
  and disable/unprepare the allocated clocks

What I will add is:
- allocation and release of both the 'ipg' and a "can" clock for
  the MPC512x case
- handling of all allocated clocks in open() and close() (such
  that no assumption is made what occurs at probe() and remove()
  time)
- permanently enabled 'ipg' clock when allocated, such that the
  driver may happily access the controller's registers and may
  assume things remain there
- usually disabled 'can' clock, but enable/disable between open()
  and close()

This shall result in:
- no change in behaviour for MPC52xx
- disabled clocks and hardware for MPC512x when CAN isn't probed
  (not listed in the device tree, or disabled)
- enabled internal peripherals but wire disabled for MPC512x when
  CAN is probed and attached but not in use
- only enabled wire related clock when the network device is open
  and in actual use

The above goal of the next update in the series won't break any
operation of peripherals, will be a clear improvement in that the
driver finally does properly use the clock API, and will result
in an appropriate use of hardware.  There may be potential to
conserve even more power, but it's not essential given the
previous status of the driver, and it's out of the scope for the
very series we are talking about.

quoted
So I will:
- make open() of the network device prepare _and_ enable the
  clock for the peripheral (if acquired during probe())
good
quoted
- adjust open() because ATM it leaves the clock enabled when the
  network device operation fails (the error path is incomplete in
  v3)
yes, clock should be disabled if open() fails.
quoted
- make the MPC512x specific probe() time .get_clock() routine not
  just prepare but enable the clock as well
If needed enable the clock, but disable after probe() has finished.
quoted
- and of course address all the shutdown counter parts of the
  above setup paths
quoted
This results in:
- specific chip drivers only need to balance their private get
  and put clock routines which are called from probe and remove,
  common paths DTRT for all of them
Yes, but clock should not stay enabled between probe() and open().
For this one I offered the compromise of only enabling the "can"
clock during network device operation, but keeping the 'ipg'
clock active over the driver's complete attachment period.  This
shall be acceptable.  Anything else can be done later and
independently.
[...]
quoted
Removing unnecessary devm_put_clk() calls is orthogonal to that.
Putting these in isn't totally wrong (they won't harm, and they
do signal "visual balance" more clearly such that the next person
won't stop and wonder), but it's true that they are redundant.
"Trained persons" will wonder as much about their presence as
untrained persons wonder about their absence. :)  Apparently I'm
not well trained yet.
The whole point about devm_* is to get rid of auto manually tear down
functions. So please remove all devm_put_clk() calls, as it will be
called automatically if a driver instance is removed.
Ah, yes, the devm_*() feedback was processed as well.  Release
won't occur explicitly, as it's done implicitly by common code.


virtually yours
Gerhard Sittig
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

Re: [PATCH v3 17/31] clk: mpc512x: introduce COMMON_CLK for MPC512x

From: Mark Rutland <mark.rutland@arm.com>
Date: 2013-08-05 11:37:20

On Mon, Jul 22, 2013 at 01:14:44PM +0100, Gerhard Sittig wrote:
this change implements a clock driver for the MPC512x PowerPC platform
which follows the COMMON_CLK approach and uses common clock drivers
shared with other platforms

this driver implements the publicly announced set of clocks (which can
get referenced by means of symbolic identifiers from the dt-bindings
header file), as well as generates additional 'struct clk' items where
the SoC hardware cannot easily get mapped to the common primitives of
the clock API, or requires "intermediate" clock nodes to represent
clocks that have both gates and dividers

the previous PPC_CLOCK implementation is kept in place and remains in
parallel to the common clock implementation for test and comparison
during migration, a compile time option picks one of the two
alternatives (Kconfig switch, common clock used by default)

some of the clock items get pre-enabled in the clock driver to not have
them automatically disabled by the underlying clock subsystem because of
their being unused -- this approach is desirable because
- some of the clocks are useful to have for diagnostics and information
  despite their not getting claimed by any drivers (CPU, internal and
  external RAM, internal busses, boot media)
- some of the clocks aren't claimed by their peripheral drivers yet,
  either because of missing driver support or because device tree specs
  aren't available yet (but the workarounds will get removed as the
  drivers get adjusted and the device tree provides the clock specs)
- some help introduce support for and migrate to the common
  infrastructure, while more appropriate support for specific hardware
  constraints isn't available yet (remaining changes are strictly
  internal to the clock driver and won't affect peripheral drivers)

clkdev registration provides "alias names" for few clock items
- to not break those peripheral drivers which encode their component
  index into the name that is used for clock lookup (UART, SPI, USB)
- to not break those drivers which use names for the clock lookup which
  were encoded in the previous PPC_CLOCK implementation (NFC, VIU, CAN)
this workaround will get removed as these drivers get adjusted after
device tree based clock lookup has become available

Signed-off-by: Gerhard Sittig <redacted>
---
 arch/powerpc/platforms/512x/Kconfig           |   14 +-
 arch/powerpc/platforms/512x/Makefile          |    4 +-
 arch/powerpc/platforms/512x/clock-commonclk.c |  786 +++++++++++++++++++++++++
 include/linux/clk-provider.h                  |   16 +
 4 files changed, 818 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
[...]
+static int get_freq_from_dt(char *propname)
+{
+       struct device_node *np;
+       const unsigned int *prop;
+       int val;
+
+       val = 0;
+       np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
+       if (np) {
+               prop = of_get_property(np, propname, NULL);
+               if (prop)
+                       val = *prop;
+           of_node_put(np);
+       }
+       return val;
+}
Can you not use of_property_read_u32 here rather than of_get_property?

Also, this seems rather unlike the common clock bindings method for
describing frequencies in the dt. Given there's nothing in mainline
using this yet, we can do it 'right' from the start.

[...]
+       /*
+        * externally provided clocks (when implemented in hardware,
+        * device tree may specify values which otherwise were unknown)
+        */
+       freq = get_freq_from_dt("psc_mclk_in");
+       if (!freq)
+               freq = 25000000;
+       clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq);
+       freq = get_freq_from_dt("spdif_tx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_tx_in", freq);
+       freq = get_freq_from_dt("spdif_rx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_rx_in", freq);
Can we not just use fixed-clocks for these in the dt? It feels odd to
describe them in a compeltely differnet way in the dt, especially as
we'll have to maintain some backwards compatibility for a while...

I see for psc_mclk_in we assume a default value if not present. I'm not
sure how to handle that, but I assume there's some way of finding out if
we've already registered a clock output with the same name?

Thanks,
Mark.
Next 63 of 63 remaining
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help