Merge tag 'clk-for-linus-3.15' of git://git.linaro.org/people/mike.turquette/linux

Pull clock framework changes from Mike Turquette:
 "The clock framework changes for 3.15 look similar to past pull
  requests.  Mostly clock driver updates, more Device Tree support in
  the form of common functions useful across platforms and a handful of
  features and fixes to the framework core"

* tag 'clk-for-linus-3.15' of git://git.linaro.org/people/mike.turquette/linux: (86 commits)
  clk: shmobile: fix setting paretn clock rate
  clk: shmobile: rcar-gen2: fix lb/sd0/sd1/sdh clock parent to pll1
  clk: Fix minor errors in of_clk_init() function comments
  clk: reverse default clk provider initialization order in of_clk_init()
  clk: sirf: update copyright years to 2014
  clk: mmp: try to use closer one when do round rate
  clk: mmp: fix the wrong calculation formula
  clk: mmp: fix wrong mask when calculate denominator
  clk: st: Adds quadfs clock binding
  clk: st: Adds clockgen-vcc and clockgen-mux clock binding
  clk: st: Adds clockgen clock binding
  clk: st: Adds divmux and prediv clock binding
  clk: st: Support for A9 MUX clocks
  clk: st: Support for ClockGenA9/DDR/GPU
  clk: st: Support for QUADFS inside ClockGenB/C/D/E/F
  clk: st: Support for VCC-mux and MUX clocks
  clk: st: Support for PLLs inside ClockGenA(s)
  clk: st: Support for DIVMUX and PreDiv Clocks
  clk: support hardware-specific debugfs entries
  clk: s2mps11: Use of_get_child_by_name
  ...
diff --git a/Documentation/clk.txt b/Documentation/clk.txt
index 699ef2a..c9c399a 100644
--- a/Documentation/clk.txt
+++ b/Documentation/clk.txt
@@ -255,3 +255,37 @@
 
 To bypass this disabling, include "clk_ignore_unused" in the bootargs to the
 kernel.
+
+	Part 7 - Locking
+
+The common clock framework uses two global locks, the prepare lock and the
+enable lock.
+
+The enable lock is a spinlock and is held across calls to the .enable,
+.disable and .is_enabled operations. Those operations are thus not allowed to
+sleep, and calls to the clk_enable(), clk_disable() and clk_is_enabled() API
+functions are allowed in atomic context.
+
+The prepare lock is a mutex and is held across calls to all other operations.
+All those operations are allowed to sleep, and calls to the corresponding API
+functions are not allowed in atomic context.
+
+This effectively divides operations in two groups from a locking perspective.
+
+Drivers don't need to manually protect resources shared between the operations
+of one group, regardless of whether those resources are shared by multiple
+clocks or not. However, access to resources that are shared between operations
+of the two groups needs to be protected by the drivers. An example of such a
+resource would be a register that controls both the clock rate and the clock
+enable/disable state.
+
+The clock framework is reentrant, in that a driver is allowed to call clock
+framework functions from within its implementation of clock operations. This
+can for instance cause a .set_rate operation of one clock being called from
+within the .set_rate operation of another clock. This case must be considered
+in the driver implementations, but the code flow is usually controlled by the
+driver in that case.
+
+Note that locking must also be considered when code outside of the common
+clock framework needs to access resources used by the clock operations. This
+is considered out of scope of this document.
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index 8c7a465..df0a452 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -30,3 +30,17 @@
 		resume-offset = <0x308>;
 		reboot-offset = <0x4>;
 	};
+
+PCTRL: Peripheral misc control register
+
+Required Properties:
+- compatible: "hisilicon,pctrl"
+- reg: Address and size of pctrl.
+
+Example:
+
+	/* for Hi3620 */
+	pctrl: pctrl@fca09000 {
+		compatible = "hisilicon,pctrl";
+		reg = <0xfca09000 0x1000>;
+	};
diff --git a/Documentation/devicetree/bindings/clock/altr_socfpga.txt b/Documentation/devicetree/bindings/clock/altr_socfpga.txt
index 0045433..5dfd145 100644
--- a/Documentation/devicetree/bindings/clock/altr_socfpga.txt
+++ b/Documentation/devicetree/bindings/clock/altr_socfpga.txt
@@ -23,3 +23,8 @@
         and the bit index.
 - div-reg : For "socfpga-gate-clk", div-reg contains the divider register, bit shift,
         and width.
+- clk-phase : For the sdmmc_clk, contains the value of the clock phase that controls
+	the SDMMC CIU clock. The first value is the clk_sample(smpsel), and the second
+	value is the cclk_in_drv(drvsel). The clk-phase is used to enable the correct
+	hold/delay times that is needed for the SD/MMC CIU clock. The values of both
+	can be 0-315 degrees, in 45 degree increments.
diff --git a/Documentation/devicetree/bindings/clock/axi-clkgen.txt b/Documentation/devicetree/bindings/clock/axi-clkgen.txt
index 028b493..20e1704 100644
--- a/Documentation/devicetree/bindings/clock/axi-clkgen.txt
+++ b/Documentation/devicetree/bindings/clock/axi-clkgen.txt
@@ -5,7 +5,7 @@
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
 
 Required properties:
-- compatible : shall be "adi,axi-clkgen".
+- compatible : shall be "adi,axi-clkgen-1.00.a" or "adi,axi-clkgen-2.00.a".
 - #clock-cells : from common clock binding; Should always be set to 0.
 - reg : Address and length of the axi-clkgen register set.
 - clocks : Phandle and clock specifier for the parent clock.
diff --git a/Documentation/devicetree/bindings/clock/clock-bindings.txt b/Documentation/devicetree/bindings/clock/clock-bindings.txt
index 7c52c29..700e7aa 100644
--- a/Documentation/devicetree/bindings/clock/clock-bindings.txt
+++ b/Documentation/devicetree/bindings/clock/clock-bindings.txt
@@ -44,6 +44,23 @@
   clocks by index. The names should reflect the clock output signal
   names for the device.
 
+clock-indices:	   If the identifyng number for the clocks in the node
+		   is not linear from zero, then the this mapping allows
+		   the mapping of identifiers into the clock-output-names
+		   array.
+
+For example, if we have two clocks <&oscillator 1> and <&oscillator 3>:
+
+	oscillator {
+		compatible = "myclocktype";
+		#clock-cells = <1>;
+		clock-indices = <1>, <3>;
+		clock-output-names = "clka", "clkb";
+	}
+
+	This ensures we do not have any empty nodes in clock-output-names
+
+
 ==Clock consumers==
 
 Required properties:
diff --git a/Documentation/devicetree/bindings/clock/hi3620-clock.txt b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
index 4b71ab4..dad6269 100644
--- a/Documentation/devicetree/bindings/clock/hi3620-clock.txt
+++ b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
@@ -7,6 +7,7 @@
 
 - compatible: should be one of the following.
   - "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC.
+  - "hisilicon,hi3620-mmc-clock" - controller specific for Hi3620 mmc.
 
 - reg: physical base address of the controller and length of memory mapped
   region.
diff --git a/Documentation/devicetree/bindings/clock/moxa,moxart-clock.txt b/Documentation/devicetree/bindings/clock/moxa,moxart-clock.txt
new file mode 100644
index 0000000..fedea84
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/moxa,moxart-clock.txt
@@ -0,0 +1,48 @@
+Device Tree Clock bindings for arch-moxart
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+MOXA ART SoCs allow to determine PLL output and APB frequencies
+by reading registers holding multiplier and divisor information.
+
+
+PLL:
+
+Required properties:
+- compatible : Must be "moxa,moxart-pll-clock"
+- #clock-cells : Should be 0
+- reg : Should contain registers location and length
+- clocks : Should contain phandle + clock-specifier for the parent clock
+
+Optional properties:
+- clock-output-names : Should contain clock name
+
+
+APB:
+
+Required properties:
+- compatible : Must be "moxa,moxart-apb-clock"
+- #clock-cells : Should be 0
+- reg : Should contain registers location and length
+- clocks : Should contain phandle + clock-specifier for the parent clock
+
+Optional properties:
+- clock-output-names : Should contain clock name
+
+
+For example:
+
+	clk_pll: clk_pll@98100000 {
+		compatible = "moxa,moxart-pll-clock";
+		#clock-cells = <0>;
+		reg = <0x98100000 0x34>;
+	};
+
+	clk_apb: clk_apb@98100000 {
+		compatible = "moxa,moxart-apb-clock";
+		#clock-cells = <0>;
+		reg = <0x98100000 0x34>;
+		clocks = <&clk_pll>;
+	};
diff --git a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
index 1e66294..307a503 100644
--- a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
+++ b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
@@ -11,6 +11,18 @@
  3 = hclk    (DRAM control clock)
  4 = dramclk (DDR clock)
 
+The following is a list of provided IDs and clock names on Armada 375:
+ 0 = tclk    (Internal Bus clock)
+ 1 = cpuclk  (CPU clock)
+ 2 = l2clk   (L2 Cache clock)
+ 3 = ddrclk  (DDR clock)
+
+The following is a list of provided IDs and clock names on Armada 380/385:
+ 0 = tclk    (Internal Bus clock)
+ 1 = cpuclk  (CPU clock)
+ 2 = l2clk   (L2 Cache clock)
+ 3 = ddrclk  (DDR clock)
+
 The following is a list of provided IDs and clock names on Kirkwood and Dove:
  0 = tclk   (Internal Bus clock)
  1 = cpuclk (CPU0 clock)
@@ -20,6 +32,8 @@
 Required properties:
 - compatible : shall be one of the following:
 	"marvell,armada-370-core-clock" - For Armada 370 SoC core clocks
+	"marvell,armada-375-core-clock" - For Armada 375 SoC core clocks
+	"marvell,armada-380-core-clock" - For Armada 380/385 SoC core clocks
 	"marvell,armada-xp-core-clock" - For Armada XP SoC core clocks
 	"marvell,dove-core-clock" - for Dove SoC core clocks
 	"marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180)
diff --git a/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt
index c62391f..520562a 100644
--- a/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt
+++ b/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt
@@ -4,7 +4,10 @@
  0 = nand (NAND clock)
 
 Required properties:
-- compatible : must be "marvell,armada-370-corediv-clock"
+- compatible : must be "marvell,armada-370-corediv-clock",
+		       "marvell,armada-375-corediv-clock",
+		       "marvell,armada-380-corediv-clock",
+
 - reg : must be the register address of Core Divider control register
 - #clock-cells : from common clock binding; shall be set to 1
 - clocks : must be set to the parent's phandle
diff --git a/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt
index fc2910f..76477be 100644
--- a/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt
+++ b/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt
@@ -1,9 +1,10 @@
 * Gated Clock bindings for Marvell EBU SoCs
 
-Marvell Armada 370/XP, Dove and Kirkwood allow some peripheral clocks to be
-gated to save some power. The clock consumer should specify the desired clock
-by having the clock ID in its "clocks" phandle cell. The clock ID is directly
-mapped to the corresponding clock gating control bit in HW to ease manual clock
+Marvell Armada 370/375/380/385/XP, Dove and Kirkwood allow some
+peripheral clocks to be gated to save some power. The clock consumer
+should specify the desired clock by having the clock ID in its
+"clocks" phandle cell. The clock ID is directly mapped to the
+corresponding clock gating control bit in HW to ease manual clock
 lookup in datasheet.
 
 The following is a list of provided IDs for Armada 370:
@@ -22,6 +23,60 @@
 28	ddr	DDR Cntrl
 30	sata1	SATA Host 0
 
+The following is a list of provided IDs for Armada 375:
+ID	Clock		Peripheral
+-----------------------------------
+2	mu		Management Unit
+3	pp		Packet Processor
+4	ptp		PTP
+5	pex0		PCIe 0 Clock out
+6	pex1		PCIe 1 Clock out
+8	audio		Audio Cntrl
+11	nd_clk		Nand Flash Cntrl
+14	sata0_link	SATA 0 Link
+15	sata0_core	SATA 0 Core
+16	usb3		USB3 Host
+17	sdio		SDHCI Host
+18	usb		USB Host
+19	gop		Gigabit Ethernet MAC
+20	sata1_link	SATA 1 Link
+21	sata1_core	SATA 1 Core
+22	xor0		XOR DMA 0
+23	xor1		XOR DMA 0
+24	copro		Coprocessor
+25	tdm		Time Division Mplx
+28	crypto0_enc	Cryptographic Unit Port 0 Encryption
+29	crypto0_core	Cryptographic Unit Port 0 Core
+30	crypto1_enc	Cryptographic Unit Port 1 Encryption
+31	crypto1_core	Cryptographic Unit Port 1 Core
+
+The following is a list of provided IDs for Armada 380/385:
+ID	Clock		Peripheral
+-----------------------------------
+0	audio		Audio
+2	ge2		Gigabit Ethernet 2
+3	ge1		Gigabit Ethernet 1
+4	ge0		Gigabit Ethernet 0
+5	pex1		PCIe 1
+6	pex2		PCIe 2
+7	pex3		PCIe 3
+8	pex0		PCIe 0
+9	usb3h0		USB3 Host 0
+10	usb3h1		USB3 Host 1
+11	usb3d		USB3 Device
+13	bm		Buffer Management
+14	crypto0z	Cryptographic 0 Z
+15	sata0		SATA 0
+16	crypto1z	Cryptographic 1 Z
+17	sdio		SDIO
+18	usb2		USB 2
+21	crypto1		Cryptographic 1
+22	xor0		XOR 0
+23	crypto0		Cryptographic 0
+25	tdm		Time Division Multiplexing
+28	xor1		XOR 1
+30	sata1		SATA 1
+
 The following is a list of provided IDs for Armada XP:
 ID	Clock	Peripheral
 -----------------------------------
@@ -95,6 +150,8 @@
 Required properties:
 - compatible : shall be one of the following:
 	"marvell,armada-370-gating-clock" - for Armada 370 SoC clock gating
+	"marvell,armada-375-gating-clock" - for Armada 375 SoC clock gating
+	"marvell,armada-380-gating-clock" - for Armada 380/385 SoC clock gating
 	"marvell,armada-xp-gating-clock" - for Armada XP SoC clock gating
 	"marvell,dove-gating-clock" - for Dove SoC clock gating
 	"marvell,kirkwood-gating-clock" - for Kirkwood SoC clock gating
diff --git a/Documentation/devicetree/bindings/clock/renesas,rz-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,rz-cpg-clocks.txt
new file mode 100644
index 0000000..98a2574
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/renesas,rz-cpg-clocks.txt
@@ -0,0 +1,29 @@
+* Renesas RZ Clock Pulse Generator (CPG)
+
+The CPG generates core clocks for the RZ SoCs. It includes the PLL, variable
+CPU and GPU clocks, and several fixed ratio dividers.
+
+Required Properties:
+
+  - compatible: Must be one of
+    - "renesas,r7s72100-cpg-clocks" for the r7s72100 CPG
+    - "renesas,rz-cpg-clocks" for the generic RZ CPG
+  - reg: Base address and length of the memory resource used by the CPG
+  - clocks: References to possible parent clocks. Order must match clock modes
+    in the datasheet. For the r7s72100, this is extal, usb_x1.
+  - #clock-cells: Must be 1
+  - clock-output-names: The names of the clocks. Supported clocks are "pll",
+    "i", and "g"
+
+
+Example
+-------
+
+	cpg_clocks: cpg_clocks@fcfe0000 {
+		#clock-cells = <1>;
+		compatible = "renesas,r7s72100-cpg-clocks",
+			     "renesas,rz-cpg-clocks";
+		reg = <0xfcfe0000 0x18>;
+		clocks = <&extal_clk>, <&usb_x1_clk>;
+		clock-output-names = "pll", "i", "g";
+	};
diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-divmux.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-divmux.txt
new file mode 100644
index 0000000..ae56315
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/st/st,clkgen-divmux.txt
@@ -0,0 +1,49 @@
+Binding for a ST divider and multiplexer clock driver.
+
+This binding uses the common clock binding[1].
+Base address is located to the parent node. See clock binding[2]
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/clock/st/st,clkgen.txt
+
+Required properties:
+
+- compatible : shall be:
+	"st,clkgena-divmux-c65-hs",	"st,clkgena-divmux"
+	"st,clkgena-divmux-c65-ls",	"st,clkgena-divmux"
+	"st,clkgena-divmux-c32-odf0",	"st,clkgena-divmux"
+	"st,clkgena-divmux-c32-odf1",	"st,clkgena-divmux"
+	"st,clkgena-divmux-c32-odf2",	"st,clkgena-divmux"
+	"st,clkgena-divmux-c32-odf3",	"st,clkgena-divmux"
+
+- #clock-cells : From common clock binding; shall be set to 1.
+
+- clocks : From common clock binding
+
+- clock-output-names : From common clock binding.
+
+Example:
+
+	clockgenA@fd345000 {
+		reg = <0xfd345000 0xb50>;
+
+		CLK_M_A1_DIV1: CLK_M_A1_DIV1 {
+			#clock-cells = <1>;
+			compatible = "st,clkgena-divmux-c32-odf1",
+				     "st,clkgena-divmux";
+
+			clocks = <&CLK_M_A1_OSC_PREDIV>,
+				 <&CLK_M_A1_PLL0 1>, /* PLL0 PHI1 */
+				 <&CLK_M_A1_PLL1 1>; /* PLL1 PHI1 */
+
+			clock-output-names = "CLK_M_RX_ICN_TS",
+					     "CLK_M_RX_ICN_VDP_0",
+					     "", /* Unused */
+					     "CLK_M_PRV_T1_BUS",
+					     "CLK_M_ICN_REG_12",
+					     "CLK_M_ICN_REG_10",
+					     "", /* Unused */
+					     "CLK_M_ICN_ST231";
+		};
+	};
+
diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt
new file mode 100644
index 0000000..943e080
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt
@@ -0,0 +1,36 @@
+Binding for a ST multiplexed clock driver.
+
+This binding supports only simple indexed multiplexers, it does not
+support table based parent index to hardware value translations.
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+
+- compatible : shall be:
+	"st,stih416-clkgenc-vcc-hd",	"st,clkgen-mux"
+	"st,stih416-clkgenf-vcc-fvdp",	"st,clkgen-mux"
+	"st,stih416-clkgenf-vcc-hva", 	"st,clkgen-mux"
+	"st,stih416-clkgenf-vcc-hd",	"st,clkgen-mux"
+	"st,stih416-clkgenf-vcc-sd",	"st,clkgen-mux"
+	"st,stih415-clkgen-a9-mux",	"st,clkgen-mux"
+	"st,stih416-clkgen-a9-mux",	"st,clkgen-mux"
+
+
+- #clock-cells : from common clock binding; shall be set to 0.
+
+- reg : A Base address and length of the register set.
+
+- clocks : from common clock binding
+
+Example:
+
+	CLK_M_HVA: CLK_M_HVA {
+		#clock-cells = <0>;
+		compatible = "st,stih416-clkgenf-vcc-hva", "st,clkgen-mux";
+		reg = <0xfd690868 4>;
+
+		clocks = <&CLOCKGEN_F 1>, <&CLK_M_A1_DIV0 3>;
+	};
diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt
new file mode 100644
index 0000000..81eb385
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt
@@ -0,0 +1,48 @@
+Binding for a ST pll clock driver.
+
+This binding uses the common clock binding[1].
+Base address is located to the parent node. See clock binding[2]
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/clock/st/st,clkgen.txt
+
+Required properties:
+
+- compatible : shall be:
+	"st,clkgena-prediv-c65",	"st,clkgena-prediv"
+	"st,clkgena-prediv-c32",	"st,clkgena-prediv"
+
+	"st,clkgena-plls-c65"
+	"st,plls-c32-a1x-0",		"st,clkgen-plls-c32"
+	"st,plls-c32-a1x-1",		"st,clkgen-plls-c32"
+	"st,stih415-plls-c32-a9",	"st,clkgen-plls-c32"
+	"st,stih415-plls-c32-ddr",	"st,clkgen-plls-c32"
+	"st,stih416-plls-c32-a9",	"st,clkgen-plls-c32"
+	"st,stih416-plls-c32-ddr",	"st,clkgen-plls-c32"
+
+	"st,stih415-gpu-pll-c32",	"st,clkgengpu-pll-c32"
+	"st,stih416-gpu-pll-c32",	"st,clkgengpu-pll-c32"
+
+
+- #clock-cells : From common clock binding; shall be set to 1.
+
+- clocks : From common clock binding
+
+- clock-output-names : From common clock binding.
+
+Example:
+
+	clockgenA@fee62000 {
+		reg = <0xfee62000 0xb48>;
+
+		CLK_S_A0_PLL: CLK_S_A0_PLL {
+			#clock-cells = <1>;
+			compatible = "st,clkgena-plls-c65";
+
+			clocks = <&CLK_SYSIN>;
+
+			clock-output-names = "CLK_S_A0_PLL0_HS",
+					     "CLK_S_A0_PLL0_LS",
+					     "CLK_S_A0_PLL1";
+		};
+	};
diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-prediv.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-prediv.txt
new file mode 100644
index 0000000..566c9d7
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/st/st,clkgen-prediv.txt
@@ -0,0 +1,36 @@
+Binding for a ST pre-divider clock driver.
+
+This binding uses the common clock binding[1].
+Base address is located to the parent node. See clock binding[2]
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/clock/st/st,clkgen.txt
+
+Required properties:
+
+- compatible : shall be:
+	"st,clkgena-prediv-c65",	"st,clkgena-prediv"
+	"st,clkgena-prediv-c32",	"st,clkgena-prediv"
+
+- #clock-cells : From common clock binding; shall be set to 0.
+
+- clocks : From common clock binding
+
+- clock-output-names : From common clock binding.
+
+Example:
+
+	clockgenA@fd345000 {
+		reg = <0xfd345000 0xb50>;
+
+		CLK_M_A2_OSC_PREDIV: CLK_M_A2_OSC_PREDIV {
+			#clock-cells = <0>;
+			compatible = "st,clkgena-prediv-c32",
+				     "st,clkgena-prediv";
+
+			clocks = <&CLK_SYSIN>;
+
+			clock-output-names = "CLK_M_A2_OSC_PREDIV";
+		};
+	};
+
diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-vcc.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-vcc.txt
new file mode 100644
index 0000000..4e3ff28
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/st/st,clkgen-vcc.txt
@@ -0,0 +1,53 @@
+Binding for a type of STMicroelectronics clock crossbar (VCC).
+
+The crossbar can take up to 4 input clocks and control up to 16
+output clocks. Not all inputs or outputs have to be in use in a
+particular instantiation. Each output can be individually enabled,
+select any of the input clocks and apply a divide (by 1,2,4 or 8) to
+that selected clock.
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+
+- compatible : shall be:
+	"st,stih416-clkgenc",		"st,vcc"
+	"st,stih416-clkgenf",		"st,vcc"
+
+- #clock-cells : from common clock binding; shall be set to 1.
+
+- reg : A Base address and length of the register set.
+
+- clocks : from common clock binding
+
+- clock-output-names : From common clock binding. The block has 16
+                       clock outputs but not all of them in a specific instance
+                       have to be used in the SoC. If a clock name is left as
+                       an empty string then no clock will be created for the
+                       output associated with that string index. If fewer than
+                       16 strings are provided then no clocks will be created
+                       for the remaining outputs.
+
+Example:
+
+	CLOCKGEN_C_VCC: CLOCKGEN_C_VCC {
+		#clock-cells = <1>;
+		compatible = "st,stih416-clkgenc", "st,clkgen-vcc";
+		reg = <0xfe8308ac 12>;
+
+		clocks = <&CLK_S_VCC_HD>, <&CLOCKGEN_C 1>,
+			<&CLK_S_TMDS_FROMPHY>, <&CLOCKGEN_C 2>;
+
+		clock-output-names  =
+			"CLK_S_PIX_HDMI",  "CLK_S_PIX_DVO",
+			"CLK_S_OUT_DVO",   "CLK_S_PIX_HD",
+			"CLK_S_HDDAC",     "CLK_S_DENC",
+			"CLK_S_SDDAC",     "CLK_S_PIX_MAIN",
+			"CLK_S_PIX_AUX",   "CLK_S_STFE_FRC_0",
+			"CLK_S_REF_MCRU",  "CLK_S_SLAVE_MCRU",
+			"CLK_S_TMDS_HDMI", "CLK_S_HDMI_REJECT_PLL",
+			"CLK_S_THSENS";
+	};
+
diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen.txt
new file mode 100644
index 0000000..49ec5ae
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/st/st,clkgen.txt
@@ -0,0 +1,83 @@
+Binding for a Clockgen hardware block found on
+certain STMicroelectronics consumer electronics SoC devices.
+
+A Clockgen node can contain pll, diviser or multiplexer nodes.
+
+We will find only the base address of the Clockgen, this base
+address is common of all subnode.
+
+	clockgen_node {
+		reg = <>;
+
+		pll_node {
+			...
+		};
+
+		prediv_node {
+			...
+		};
+
+		divmux_node {
+			...
+		};
+
+		quadfs_node {
+			...
+		};
+		...
+	};
+
+This binding uses the common clock binding[1].
+Each subnode should use the binding discribe in [2]..[4]
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/clock/st,quadfs.txt
+[3] Documentation/devicetree/bindings/clock/st,quadfs.txt
+[4] Documentation/devicetree/bindings/clock/st,quadfs.txt
+
+Required properties:
+- reg : A Base address and length of the register set.
+
+Example:
+
+	clockgenA@fee62000 {
+
+		reg = <0xfee62000 0xb48>;
+
+		CLK_S_A0_PLL: CLK_S_A0_PLL {
+			#clock-cells = <1>;
+			compatible = "st,clkgena-plls-c65";
+
+			clocks = <&CLK_SYSIN>;
+
+			clock-output-names = "CLK_S_A0_PLL0_HS",
+					     "CLK_S_A0_PLL0_LS",
+					     "CLK_S_A0_PLL1";
+		};
+
+		CLK_S_A0_OSC_PREDIV: CLK_S_A0_OSC_PREDIV {
+			#clock-cells = <0>;
+			compatible = "st,clkgena-prediv-c65",
+				     "st,clkgena-prediv";
+
+			clocks = <&CLK_SYSIN>;
+
+			clock-output-names = "CLK_S_A0_OSC_PREDIV";
+		};
+
+		CLK_S_A0_HS: CLK_S_A0_HS {
+			#clock-cells = <1>;
+			compatible = "st,clkgena-divmux-c65-hs",
+				     "st,clkgena-divmux";
+
+			clocks = <&CLK_S_A0_OSC_PREDIV>,
+				 <&CLK_S_A0_PLL 0>, /* PLL0 HS */
+				 <&CLK_S_A0_PLL 2>; /* PLL1 */
+
+			clock-output-names = "CLK_S_FDMA_0",
+					     "CLK_S_FDMA_1",
+					     ""; /* CLK_S_JIT_SENSE */
+					     /* Fourth output unused */
+		};
+	};
+
diff --git a/Documentation/devicetree/bindings/clock/st/st,quadfs.txt b/Documentation/devicetree/bindings/clock/st/st,quadfs.txt
new file mode 100644
index 0000000..ec86d62
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/st/st,quadfs.txt
@@ -0,0 +1,45 @@
+Binding for a type of quad channel digital frequency synthesizer found on
+certain STMicroelectronics consumer electronics SoC devices.
+
+This version contains a programmable PLL which can generate up to 216, 432
+or 660MHz (from a 30MHz oscillator input) as the input to the digital
+synthesizers.
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be:
+  "st,stih416-quadfs216",	"st,quadfs"
+  "st,stih416-quadfs432",	"st,quadfs"
+  "st,stih416-quadfs660-E",	"st,quadfs"
+  "st,stih416-quadfs660-F",	"st,quadfs"
+
+- #clock-cells : from common clock binding; shall be set to 1.
+
+- reg : A Base address and length of the register set.
+
+- clocks : from common clock binding
+
+- clock-output-names : From common clock binding. The block has 4
+                       clock outputs but not all of them in a specific instance
+                       have to be used in the SoC. If a clock name is left as
+                       an empty string then no clock will be created for the
+                       output associated with that string index. If fewer than
+                       4 strings are provided then no clocks will be created
+                       for the remaining outputs.
+
+Example:
+
+	CLOCKGEN_E: CLOCKGEN_E {
+                #clock-cells = <1>;
+                compatible = "st,stih416-quadfs660-E", "st,quadfs";
+                reg = <0xfd3208bc 0xB0>;
+
+                clocks = <&CLK_SYSIN>;
+                clock-output-names = "CLK_M_PIX_MDTP_0",
+                                        "CLK_M_PIX_MDTP_1",
+                                        "CLK_M_PIX_MDTP_2",
+                                        "CLK_M_MPELPC";
+        };
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index c2cb762..a5160d8 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -6,37 +6,41 @@
 
 Required properties:
 - compatible : shall be one of the following:
-	"allwinner,sun4i-osc-clk" - for a gatable oscillator
-	"allwinner,sun4i-pll1-clk" - for the main PLL clock and PLL4
+	"allwinner,sun4i-a10-osc-clk" - for a gatable oscillator
+	"allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4
 	"allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
-	"allwinner,sun4i-pll5-clk" - for the PLL5 clock
-	"allwinner,sun4i-pll6-clk" - for the PLL6 clock
-	"allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
-	"allwinner,sun4i-axi-clk" - for the AXI clock
-	"allwinner,sun4i-axi-gates-clk" - for the AXI gates
-	"allwinner,sun4i-ahb-clk" - for the AHB clock
-	"allwinner,sun4i-ahb-gates-clk" - for the AHB gates on A10
+	"allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock
+	"allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock
+	"allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31
+	"allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock
+	"allwinner,sun4i-a10-axi-clk" - for the AXI clock
+	"allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates
+	"allwinner,sun4i-a10-ahb-clk" - for the AHB clock
+	"allwinner,sun4i-a10-ahb-gates-clk" - for the AHB gates on A10
 	"allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13
 	"allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
 	"allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
 	"allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
 	"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
-	"allwinner,sun4i-apb0-clk" - for the APB0 clock
-	"allwinner,sun4i-apb0-gates-clk" - for the APB0 gates on A10
+	"allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
+	"allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
 	"allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
 	"allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
 	"allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20
-	"allwinner,sun4i-apb1-clk" - for the APB1 clock
-	"allwinner,sun4i-apb1-mux-clk" - for the APB1 clock muxing
-	"allwinner,sun4i-apb1-gates-clk" - for the APB1 gates on A10
+	"allwinner,sun4i-a10-apb1-clk" - for the APB1 clock
+	"allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing
+	"allwinner,sun4i-a10-apb1-gates-clk" - for the APB1 gates on A10
 	"allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13
 	"allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s
 	"allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31
 	"allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20
 	"allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
 	"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
-	"allwinner,sun4i-mod0-clk" - for the module 0 family of clocks
+	"allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
 	"allwinner,sun7i-a20-out-clk" - for the external output clocks
+	"allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
+	"allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
+	"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
 
 Required properties for all clocks:
 - reg : shall be the control register address for the clock.
@@ -44,10 +48,17 @@
 	multiplexed clocks, the list order must match the hardware
 	programming order.
 - #clock-cells : from common clock binding; shall be set to 0 except for
-	"allwinner,*-gates-clk" where it shall be set to 1
+	"allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk" and
+	"allwinner,sun4i-pll6-clk" where it shall be set to 1
+- clock-output-names : shall be the corresponding names of the outputs.
+	If the clock module only has one output, the name shall be the
+	module name.
 
-Additionally, "allwinner,*-gates-clk" clocks require:
-- clock-output-names : the corresponding gate names that the clock controls
+And "allwinner,*-usb-clk" clocks also require:
+- reset-cells : shall be set to 1
+
+For "allwinner,sun7i-a20-gmac-clk", the parent clocks shall be fixed rate
+dummy clocks at 25 MHz and 125 MHz, respectively. See example.
 
 Clock consumers should specify the desired clocks they use with a
 "clocks" phandle cell. Consumers that are using a gated clock should
@@ -56,23 +67,68 @@
 
 For example:
 
-osc24M: osc24M@01c20050 {
+osc24M: clk@01c20050 {
 	#clock-cells = <0>;
-	compatible = "allwinner,sun4i-osc-clk";
+	compatible = "allwinner,sun4i-a10-osc-clk";
 	reg = <0x01c20050 0x4>;
 	clocks = <&osc24M_fixed>;
+	clock-output-names = "osc24M";
 };
 
-pll1: pll1@01c20000 {
+pll1: clk@01c20000 {
 	#clock-cells = <0>;
-	compatible = "allwinner,sun4i-pll1-clk";
+	compatible = "allwinner,sun4i-a10-pll1-clk";
 	reg = <0x01c20000 0x4>;
 	clocks = <&osc24M>;
+	clock-output-names = "pll1";
+};
+
+pll5: clk@01c20020 {
+	#clock-cells = <1>;
+	compatible = "allwinner,sun4i-pll5-clk";
+	reg = <0x01c20020 0x4>;
+	clocks = <&osc24M>;
+	clock-output-names = "pll5_ddr", "pll5_other";
 };
 
 cpu: cpu@01c20054 {
 	#clock-cells = <0>;
-	compatible = "allwinner,sun4i-cpu-clk";
+	compatible = "allwinner,sun4i-a10-cpu-clk";
 	reg = <0x01c20054 0x4>;
 	clocks = <&osc32k>, <&osc24M>, <&pll1>;
+	clock-output-names = "cpu";
+};
+
+mmc0_clk: clk@01c20088 {
+	#clock-cells = <0>;
+	compatible = "allwinner,sun4i-mod0-clk";
+	reg = <0x01c20088 0x4>;
+	clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+	clock-output-names = "mmc0";
+};
+
+mii_phy_tx_clk: clk@2 {
+	#clock-cells = <0>;
+	compatible = "fixed-clock";
+	clock-frequency = <25000000>;
+	clock-output-names = "mii_phy_tx";
+};
+
+gmac_int_tx_clk: clk@3 {
+	#clock-cells = <0>;
+	compatible = "fixed-clock";
+	clock-frequency = <125000000>;
+	clock-output-names = "gmac_int_tx";
+};
+
+gmac_clk: clk@01c20164 {
+	#clock-cells = <0>;
+	compatible = "allwinner,sun7i-a20-gmac-clk";
+	reg = <0x01c20164 0x4>;
+	/*
+	 * The first clock must be fixed at 25MHz;
+	 * the second clock must be fixed at 125MHz
+	 */
+	clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>;
+	clock-output-names = "gmac";
 };
diff --git a/MAINTAINERS b/MAINTAINERS
index 2421c8d..bfff896 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2318,7 +2318,7 @@
 
 COMMON CLK FRAMEWORK
 M:	Mike Turquette <mturquette@linaro.org>
-L:	linux-arm-kernel@lists.infradead.org (same as CLK API & CLKDEV)
+L:	linux-kernel@vger.kernel.org
 T:	git git://git.linaro.org/people/mturquette/linux.git
 S:	Maintained
 F:	drivers/clk/
diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
index 4568c98..56fc214 100644
--- a/arch/arm/boot/dts/socfpga.dtsi
+++ b/arch/arm/boot/dts/socfpga.dtsi
@@ -424,6 +424,7 @@
 						compatible = "altr,socfpga-gate-clk";
 						clocks = <&f2s_periph_ref_clk>, <&main_nand_sdmmc_clk>, <&per_nand_mmc_clk>;
 						clk-gate = <0xa0 8>;
+						clk-phase = <0 135>;
 					};
 
 					nand_x_clk: nand_x_clk {
diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c
index dd0d49c..d86231e 100644
--- a/arch/arm/mach-socfpga/socfpga.c
+++ b/arch/arm/mach-socfpga/socfpga.c
@@ -29,7 +29,6 @@
 void __iomem *socfpga_scu_base_addr = ((void __iomem *)(SOCFPGA_SCU_VIRT_BASE));
 void __iomem *sys_manager_base_addr;
 void __iomem *rst_manager_base_addr;
-void __iomem *clk_mgr_base_addr;
 unsigned long cpu1start_addr;
 
 static struct map_desc scu_io_desc __initdata = {
@@ -78,9 +77,6 @@
 
 	np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr");
 	rst_manager_base_addr = of_iomap(np, 0);
-
-	np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr");
-	clk_mgr_base_addr = of_iomap(np, 0);
 }
 
 static void __init socfpga_init_irq(void)
@@ -106,7 +102,6 @@
 {
 	l2x0_of_init(0, ~0UL);
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-	socfpga_init_clocks();
 }
 
 static const char *altera_dt_match[] = {
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index f9f6056..6f56d3a 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -65,10 +65,12 @@
 	  clock generators.
 
 config COMMON_CLK_S2MPS11
-	tristate "Clock driver for S2MPS11 MFD"
+	tristate "Clock driver for S2MPS11/S5M8767 MFD"
 	depends on MFD_SEC_CORE
 	---help---
-	  This driver supports S2MPS11 crystal oscillator clock.
+	  This driver supports S2MPS11/S5M8767 crystal oscillator clock. These
+	  multi-function devices have 3 fixed-rate oscillators, clocked at
+	  32KHz each.
 
 config CLK_TWL6040
 	tristate "External McPDM functional clock from twl6040"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 88af4a3..5f8a287 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -17,6 +17,7 @@
 obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
 obj-$(CONFIG_MACH_LOONGSON1)		+= clk-ls1x.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
+obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
 obj-$(CONFIG_ARCH_NOMADIK)		+= clk-nomadik.o
 obj-$(CONFIG_ARCH_NSPIRE)		+= clk-nspire.o
 obj-$(CONFIG_CLK_PPC_CORENET)		+= clk-ppc-corenet.o
@@ -31,6 +32,7 @@
 obj-$(CONFIG_COMMON_CLK_AT91)		+= at91/
 obj-$(CONFIG_ARCH_BCM_MOBILE)		+= bcm/
 obj-$(CONFIG_ARCH_HI3xxx)		+= hisilicon/
+obj-$(CONFIG_ARCH_HIP04)		+= hisilicon/
 obj-$(CONFIG_COMMON_CLK_KEYSTONE)	+= keystone/
 ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_ARCH_MMP)			+= mmp/
@@ -44,6 +46,7 @@
 obj-$(CONFIG_ARCH_SIRF)			+= sirf/
 obj-$(CONFIG_ARCH_SOCFPGA)		+= socfpga/
 obj-$(CONFIG_PLAT_SPEAR)		+= spear/
+obj-$(CONFIG_ARCH_STI)			+= st/
 obj-$(CONFIG_ARCH_SUNXI)		+= sunxi/
 obj-$(CONFIG_ARCH_TEGRA)		+= tegra/
 obj-$(CONFIG_ARCH_OMAP2PLUS)		+= ti/
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
index fd792b2..62e2509 100644
--- a/drivers/clk/at91/clk-programmable.c
+++ b/drivers/clk/at91/clk-programmable.c
@@ -13,12 +13,9 @@
 #include <linux/clk/at91_pmc.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
-#include <linux/of_irq.h>
 #include <linux/io.h>
 #include <linux/wait.h>
 #include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
 
 #include "pmc.h"
 
@@ -38,104 +35,59 @@
 struct clk_programmable {
 	struct clk_hw hw;
 	struct at91_pmc *pmc;
-	unsigned int irq;
-	wait_queue_head_t wait;
 	u8 id;
-	u8 css;
-	u8 pres;
-	u8 slckmck;
 	const struct clk_programmable_layout *layout;
 };
 
 #define to_clk_programmable(hw) container_of(hw, struct clk_programmable, hw)
 
-
-static irqreturn_t clk_programmable_irq_handler(int irq, void *dev_id)
-{
-	struct clk_programmable *prog = (struct clk_programmable *)dev_id;
-
-	wake_up(&prog->wait);
-
-	return IRQ_HANDLED;
-}
-
-static int clk_programmable_prepare(struct clk_hw *hw)
-{
-	u32 tmp;
-	struct clk_programmable *prog = to_clk_programmable(hw);
-	struct at91_pmc *pmc = prog->pmc;
-	const struct clk_programmable_layout *layout = prog->layout;
-	u8 id = prog->id;
-	u32 mask = PROG_STATUS_MASK(id);
-
-	tmp = prog->css | (prog->pres << layout->pres_shift);
-	if (layout->have_slck_mck && prog->slckmck)
-		tmp |= AT91_PMC_CSSMCK_MCK;
-
-	pmc_write(pmc, AT91_PMC_PCKR(id), tmp);
-
-	while (!(pmc_read(pmc, AT91_PMC_SR) & mask))
-		wait_event(prog->wait, pmc_read(pmc, AT91_PMC_SR) & mask);
-
-	return 0;
-}
-
-static int clk_programmable_is_ready(struct clk_hw *hw)
-{
-	struct clk_programmable *prog = to_clk_programmable(hw);
-	struct at91_pmc *pmc = prog->pmc;
-
-	return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_PCKR(prog->id));
-}
-
 static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
 						  unsigned long parent_rate)
 {
-	u32 tmp;
+	u32 pres;
 	struct clk_programmable *prog = to_clk_programmable(hw);
 	struct at91_pmc *pmc = prog->pmc;
 	const struct clk_programmable_layout *layout = prog->layout;
 
-	tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
-	prog->pres = (tmp >> layout->pres_shift) & PROG_PRES_MASK;
-
-	return parent_rate >> prog->pres;
+	pres = (pmc_read(pmc, AT91_PMC_PCKR(prog->id)) >> layout->pres_shift) &
+	       PROG_PRES_MASK;
+	return parent_rate >> pres;
 }
 
-static long clk_programmable_round_rate(struct clk_hw *hw, unsigned long rate,
-					unsigned long *parent_rate)
+static long clk_programmable_determine_rate(struct clk_hw *hw,
+					    unsigned long rate,
+					    unsigned long *best_parent_rate,
+					    struct clk **best_parent_clk)
 {
-	unsigned long best_rate = *parent_rate;
-	unsigned long best_diff;
-	unsigned long new_diff;
-	unsigned long cur_rate;
-	int shift = shift;
+	struct clk *parent = NULL;
+	long best_rate = -EINVAL;
+	unsigned long parent_rate;
+	unsigned long tmp_rate;
+	int shift;
+	int i;
 
-	if (rate > *parent_rate)
-		return *parent_rate;
-	else
-		best_diff = *parent_rate - rate;
+	for (i = 0; i < __clk_get_num_parents(hw->clk); i++) {
+		parent = clk_get_parent_by_index(hw->clk, i);
+		if (!parent)
+			continue;
 
-	if (!best_diff)
-		return best_rate;
-
-	for (shift = 1; shift < PROG_PRES_MASK; shift++) {
-		cur_rate = *parent_rate >> shift;
-
-		if (cur_rate > rate)
-			new_diff = cur_rate - rate;
-		else
-			new_diff = rate - cur_rate;
-
-		if (!new_diff)
-			return cur_rate;
-
-		if (new_diff < best_diff) {
-			best_diff = new_diff;
-			best_rate = cur_rate;
+		parent_rate = __clk_get_rate(parent);
+		for (shift = 0; shift < PROG_PRES_MASK; shift++) {
+			tmp_rate = parent_rate >> shift;
+			if (tmp_rate <= rate)
+				break;
 		}
 
-		if (rate > cur_rate)
+		if (tmp_rate > rate)
+			continue;
+
+		if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) {
+			best_rate = tmp_rate;
+			*best_parent_rate = parent_rate;
+			*best_parent_clk = parent;
+		}
+
+		if (!best_rate)
 			break;
 	}
 
@@ -146,17 +98,22 @@
 {
 	struct clk_programmable *prog = to_clk_programmable(hw);
 	const struct clk_programmable_layout *layout = prog->layout;
+	struct at91_pmc *pmc = prog->pmc;
+	u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) & ~layout->css_mask;
+
+	if (layout->have_slck_mck)
+		tmp &= AT91_PMC_CSSMCK_MCK;
+
 	if (index > layout->css_mask) {
 		if (index > PROG_MAX_RM9200_CSS && layout->have_slck_mck) {
-			prog->css = 0;
-			prog->slckmck = 1;
+			tmp |= AT91_PMC_CSSMCK_MCK;
 			return 0;
 		} else {
 			return -EINVAL;
 		}
 	}
 
-	prog->css = index;
+	pmc_write(pmc, AT91_PMC_PCKR(prog->id), tmp | index);
 	return 0;
 }
 
@@ -169,13 +126,9 @@
 	const struct clk_programmable_layout *layout = prog->layout;
 
 	tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
-	prog->css = tmp & layout->css_mask;
-	ret = prog->css;
-	if (layout->have_slck_mck) {
-		prog->slckmck = !!(tmp & AT91_PMC_CSSMCK_MCK);
-		if (prog->slckmck && !ret)
-			ret = PROG_MAX_RM9200_CSS + 1;
-	}
+	ret = tmp & layout->css_mask;
+	if (layout->have_slck_mck && (tmp & AT91_PMC_CSSMCK_MCK) && !ret)
+		ret = PROG_MAX_RM9200_CSS + 1;
 
 	return ret;
 }
@@ -184,67 +137,47 @@
 				     unsigned long parent_rate)
 {
 	struct clk_programmable *prog = to_clk_programmable(hw);
-	unsigned long best_rate = parent_rate;
-	unsigned long best_diff;
-	unsigned long new_diff;
-	unsigned long cur_rate;
+	struct at91_pmc *pmc = prog->pmc;
+	const struct clk_programmable_layout *layout = prog->layout;
+	unsigned long div = parent_rate / rate;
 	int shift = 0;
+	u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) &
+		  ~(PROG_PRES_MASK << layout->pres_shift);
 
-	if (rate > parent_rate)
-		return parent_rate;
-	else
-		best_diff = parent_rate - rate;
+	if (!div)
+		return -EINVAL;
 
-	if (!best_diff) {
-		prog->pres = shift;
-		return 0;
-	}
+	shift = fls(div) - 1;
 
-	for (shift = 1; shift < PROG_PRES_MASK; shift++) {
-		cur_rate = parent_rate >> shift;
+	if (div != (1<<shift))
+		return -EINVAL;
 
-		if (cur_rate > rate)
-			new_diff = cur_rate - rate;
-		else
-			new_diff = rate - cur_rate;
+	if (shift >= PROG_PRES_MASK)
+		return -EINVAL;
 
-		if (!new_diff)
-			break;
+	pmc_write(pmc, AT91_PMC_PCKR(prog->id),
+		  tmp | (shift << layout->pres_shift));
 
-		if (new_diff < best_diff) {
-			best_diff = new_diff;
-			best_rate = cur_rate;
-		}
-
-		if (rate > cur_rate)
-			break;
-	}
-
-	prog->pres = shift;
 	return 0;
 }
 
 static const struct clk_ops programmable_ops = {
-	.prepare = clk_programmable_prepare,
-	.is_prepared = clk_programmable_is_ready,
 	.recalc_rate = clk_programmable_recalc_rate,
-	.round_rate = clk_programmable_round_rate,
+	.determine_rate = clk_programmable_determine_rate,
 	.get_parent = clk_programmable_get_parent,
 	.set_parent = clk_programmable_set_parent,
 	.set_rate = clk_programmable_set_rate,
 };
 
 static struct clk * __init
-at91_clk_register_programmable(struct at91_pmc *pmc, unsigned int irq,
+at91_clk_register_programmable(struct at91_pmc *pmc,
 			       const char *name, const char **parent_names,
 			       u8 num_parents, u8 id,
 			       const struct clk_programmable_layout *layout)
 {
-	int ret;
 	struct clk_programmable *prog;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
-	char irq_name[11];
 
 	if (id > PROG_ID_MAX)
 		return ERR_PTR(-EINVAL);
@@ -263,14 +196,6 @@
 	prog->layout = layout;
 	prog->hw.init = &init;
 	prog->pmc = pmc;
-	prog->irq = irq;
-	init_waitqueue_head(&prog->wait);
-	irq_set_status_flags(prog->irq, IRQ_NOAUTOEN);
-	snprintf(irq_name, sizeof(irq_name), "clk-prog%d", id);
-	ret = request_irq(prog->irq, clk_programmable_irq_handler,
-			  IRQF_TRIGGER_HIGH, irq_name, prog);
-	if (ret)
-		return ERR_PTR(ret);
 
 	clk = clk_register(NULL, &prog->hw);
 	if (IS_ERR(clk))
@@ -304,7 +229,6 @@
 	int num;
 	u32 id;
 	int i;
-	unsigned int irq;
 	struct clk *clk;
 	int num_parents;
 	const char *parent_names[PROG_SOURCE_MAX];
@@ -332,11 +256,7 @@
 		if (of_property_read_string(np, "clock-output-names", &name))
 			name = progclknp->name;
 
-		irq = irq_of_parse_and_map(progclknp, 0);
-		if (!irq)
-			continue;
-
-		clk = at91_clk_register_programmable(pmc, irq, name,
+		clk = at91_clk_register_programmable(pmc, name,
 						     parent_names, num_parents,
 						     id, layout);
 		if (IS_ERR(clk))
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
index 8f7c043..8c96307 100644
--- a/drivers/clk/at91/clk-system.c
+++ b/drivers/clk/at91/clk-system.c
@@ -14,6 +14,11 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
 
 #include "pmc.h"
 
@@ -25,19 +30,48 @@
 struct clk_system {
 	struct clk_hw hw;
 	struct at91_pmc *pmc;
+	unsigned int irq;
+	wait_queue_head_t wait;
 	u8 id;
 };
 
-static int clk_system_enable(struct clk_hw *hw)
+static inline int is_pck(int id)
+{
+	return (id >= 8) && (id <= 15);
+}
+static irqreturn_t clk_system_irq_handler(int irq, void *dev_id)
+{
+	struct clk_system *sys = (struct clk_system *)dev_id;
+
+	wake_up(&sys->wait);
+	disable_irq_nosync(sys->irq);
+
+	return IRQ_HANDLED;
+}
+
+static int clk_system_prepare(struct clk_hw *hw)
 {
 	struct clk_system *sys = to_clk_system(hw);
 	struct at91_pmc *pmc = sys->pmc;
+	u32 mask = 1 << sys->id;
 
-	pmc_write(pmc, AT91_PMC_SCER, 1 << sys->id);
+	pmc_write(pmc, AT91_PMC_SCER, mask);
+
+	if (!is_pck(sys->id))
+		return 0;
+
+	while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) {
+		if (sys->irq) {
+			enable_irq(sys->irq);
+			wait_event(sys->wait,
+				   pmc_read(pmc, AT91_PMC_SR) & mask);
+		} else
+			cpu_relax();
+	}
 	return 0;
 }
 
-static void clk_system_disable(struct clk_hw *hw)
+static void clk_system_unprepare(struct clk_hw *hw)
 {
 	struct clk_system *sys = to_clk_system(hw);
 	struct at91_pmc *pmc = sys->pmc;
@@ -45,27 +79,34 @@
 	pmc_write(pmc, AT91_PMC_SCDR, 1 << sys->id);
 }
 
-static int clk_system_is_enabled(struct clk_hw *hw)
+static int clk_system_is_prepared(struct clk_hw *hw)
 {
 	struct clk_system *sys = to_clk_system(hw);
 	struct at91_pmc *pmc = sys->pmc;
 
-	return !!(pmc_read(pmc, AT91_PMC_SCSR) & (1 << sys->id));
+	if (!(pmc_read(pmc, AT91_PMC_SCSR) & (1 << sys->id)))
+		return 0;
+
+	if (!is_pck(sys->id))
+		return 1;
+
+	return !!(pmc_read(pmc, AT91_PMC_SR) & (1 << sys->id));
 }
 
 static const struct clk_ops system_ops = {
-	.enable = clk_system_enable,
-	.disable = clk_system_disable,
-	.is_enabled = clk_system_is_enabled,
+	.prepare = clk_system_prepare,
+	.unprepare = clk_system_unprepare,
+	.is_prepared = clk_system_is_prepared,
 };
 
 static struct clk * __init
 at91_clk_register_system(struct at91_pmc *pmc, const char *name,
-			 const char *parent_name, u8 id)
+			 const char *parent_name, u8 id, int irq)
 {
 	struct clk_system *sys;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
+	int ret;
 
 	if (!parent_name || id > SYSTEM_MAX_ID)
 		return ERR_PTR(-EINVAL);
@@ -84,11 +125,20 @@
 	 * (see drivers/memory) which would request and enable the ddrck clock.
 	 * When this is done we will be able to remove CLK_IGNORE_UNUSED flag.
 	 */
-	init.flags = CLK_IGNORE_UNUSED;
+	init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED;
 
 	sys->id = id;
 	sys->hw.init = &init;
 	sys->pmc = pmc;
+	sys->irq = irq;
+	if (irq) {
+		init_waitqueue_head(&sys->wait);
+		irq_set_status_flags(sys->irq, IRQ_NOAUTOEN);
+		ret = request_irq(sys->irq, clk_system_irq_handler,
+				IRQF_TRIGGER_HIGH, name, sys);
+		if (ret)
+			return ERR_PTR(ret);
+	}
 
 	clk = clk_register(NULL, &sys->hw);
 	if (IS_ERR(clk))
@@ -101,6 +151,7 @@
 of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc)
 {
 	int num;
+	int irq = 0;
 	u32 id;
 	struct clk *clk;
 	const char *name;
@@ -118,9 +169,12 @@
 		if (of_property_read_string(np, "clock-output-names", &name))
 			name = sysclknp->name;
 
+		if (is_pck(id))
+			irq = irq_of_parse_and_map(sysclknp, 0);
+
 		parent_name = of_clk_get_parent_name(sysclknp, 0);
 
-		clk = at91_clk_register_system(pmc, name, parent_name, id);
+		clk = at91_clk_register_system(pmc, name, parent_name, id, irq);
 		if (IS_ERR(clk))
 			continue;
 
diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c
index 8137327..1127ee4 100644
--- a/drivers/clk/clk-axi-clkgen.c
+++ b/drivers/clk/clk-axi-clkgen.c
@@ -17,23 +17,75 @@
 #include <linux/module.h>
 #include <linux/err.h>
 
-#define AXI_CLKGEN_REG_UPDATE_ENABLE	0x04
-#define AXI_CLKGEN_REG_CLK_OUT1		0x08
-#define AXI_CLKGEN_REG_CLK_OUT2		0x0c
-#define AXI_CLKGEN_REG_CLK_DIV		0x10
-#define AXI_CLKGEN_REG_CLK_FB1		0x14
-#define AXI_CLKGEN_REG_CLK_FB2		0x18
-#define AXI_CLKGEN_REG_LOCK1		0x1c
-#define AXI_CLKGEN_REG_LOCK2		0x20
-#define AXI_CLKGEN_REG_LOCK3		0x24
-#define AXI_CLKGEN_REG_FILTER1		0x28
-#define AXI_CLKGEN_REG_FILTER2		0x2c
+#define AXI_CLKGEN_V1_REG_UPDATE_ENABLE	0x04
+#define AXI_CLKGEN_V1_REG_CLK_OUT1	0x08
+#define AXI_CLKGEN_V1_REG_CLK_OUT2	0x0c
+#define AXI_CLKGEN_V1_REG_CLK_DIV	0x10
+#define AXI_CLKGEN_V1_REG_CLK_FB1	0x14
+#define AXI_CLKGEN_V1_REG_CLK_FB2	0x18
+#define AXI_CLKGEN_V1_REG_LOCK1		0x1c
+#define AXI_CLKGEN_V1_REG_LOCK2		0x20
+#define AXI_CLKGEN_V1_REG_LOCK3		0x24
+#define AXI_CLKGEN_V1_REG_FILTER1	0x28
+#define AXI_CLKGEN_V1_REG_FILTER2	0x2c
+
+#define AXI_CLKGEN_V2_REG_RESET		0x40
+#define AXI_CLKGEN_V2_REG_DRP_CNTRL	0x70
+#define AXI_CLKGEN_V2_REG_DRP_STATUS	0x74
+
+#define AXI_CLKGEN_V2_RESET_MMCM_ENABLE	BIT(1)
+#define AXI_CLKGEN_V2_RESET_ENABLE	BIT(0)
+
+#define AXI_CLKGEN_V2_DRP_CNTRL_SEL	BIT(29)
+#define AXI_CLKGEN_V2_DRP_CNTRL_READ	BIT(28)
+
+#define AXI_CLKGEN_V2_DRP_STATUS_BUSY	BIT(16)
+
+#define MMCM_REG_CLKOUT0_1	0x08
+#define MMCM_REG_CLKOUT0_2	0x09
+#define MMCM_REG_CLK_FB1	0x14
+#define MMCM_REG_CLK_FB2	0x15
+#define MMCM_REG_CLK_DIV	0x16
+#define MMCM_REG_LOCK1		0x18
+#define MMCM_REG_LOCK2		0x19
+#define MMCM_REG_LOCK3		0x1a
+#define MMCM_REG_FILTER1	0x4e
+#define MMCM_REG_FILTER2	0x4f
+
+struct axi_clkgen;
+
+struct axi_clkgen_mmcm_ops {
+	void (*enable)(struct axi_clkgen *axi_clkgen, bool enable);
+	int (*write)(struct axi_clkgen *axi_clkgen, unsigned int reg,
+		     unsigned int val, unsigned int mask);
+	int (*read)(struct axi_clkgen *axi_clkgen, unsigned int reg,
+		    unsigned int *val);
+};
 
 struct axi_clkgen {
 	void __iomem *base;
+	const struct axi_clkgen_mmcm_ops *mmcm_ops;
 	struct clk_hw clk_hw;
 };
 
+static void axi_clkgen_mmcm_enable(struct axi_clkgen *axi_clkgen,
+	bool enable)
+{
+	axi_clkgen->mmcm_ops->enable(axi_clkgen, enable);
+}
+
+static int axi_clkgen_mmcm_write(struct axi_clkgen *axi_clkgen,
+	unsigned int reg, unsigned int val, unsigned int mask)
+{
+	return axi_clkgen->mmcm_ops->write(axi_clkgen, reg, val, mask);
+}
+
+static int axi_clkgen_mmcm_read(struct axi_clkgen *axi_clkgen,
+	unsigned int reg, unsigned int *val)
+{
+	return axi_clkgen->mmcm_ops->read(axi_clkgen, reg, val);
+}
+
 static uint32_t axi_clkgen_lookup_filter(unsigned int m)
 {
 	switch (m) {
@@ -156,6 +208,148 @@
 	*val = readl(axi_clkgen->base + reg);
 }
 
+static unsigned int axi_clkgen_v1_map_mmcm_reg(unsigned int reg)
+{
+	switch (reg) {
+	case MMCM_REG_CLKOUT0_1:
+		return AXI_CLKGEN_V1_REG_CLK_OUT1;
+	case MMCM_REG_CLKOUT0_2:
+		return AXI_CLKGEN_V1_REG_CLK_OUT2;
+	case MMCM_REG_CLK_FB1:
+		return AXI_CLKGEN_V1_REG_CLK_FB1;
+	case MMCM_REG_CLK_FB2:
+		return AXI_CLKGEN_V1_REG_CLK_FB2;
+	case MMCM_REG_CLK_DIV:
+		return AXI_CLKGEN_V1_REG_CLK_DIV;
+	case MMCM_REG_LOCK1:
+		return AXI_CLKGEN_V1_REG_LOCK1;
+	case MMCM_REG_LOCK2:
+		return AXI_CLKGEN_V1_REG_LOCK2;
+	case MMCM_REG_LOCK3:
+		return AXI_CLKGEN_V1_REG_LOCK3;
+	case MMCM_REG_FILTER1:
+		return AXI_CLKGEN_V1_REG_FILTER1;
+	case MMCM_REG_FILTER2:
+		return AXI_CLKGEN_V1_REG_FILTER2;
+	default:
+		return 0;
+	}
+}
+
+static int axi_clkgen_v1_mmcm_write(struct axi_clkgen *axi_clkgen,
+	unsigned int reg, unsigned int val, unsigned int mask)
+{
+	reg = axi_clkgen_v1_map_mmcm_reg(reg);
+	if (reg == 0)
+		return -EINVAL;
+
+	axi_clkgen_write(axi_clkgen, reg, val);
+
+	return 0;
+}
+
+static int axi_clkgen_v1_mmcm_read(struct axi_clkgen *axi_clkgen,
+	unsigned int reg, unsigned int *val)
+{
+	reg = axi_clkgen_v1_map_mmcm_reg(reg);
+	if (reg == 0)
+		return -EINVAL;
+
+	axi_clkgen_read(axi_clkgen, reg, val);
+
+	return 0;
+}
+
+static void axi_clkgen_v1_mmcm_enable(struct axi_clkgen *axi_clkgen,
+	bool enable)
+{
+	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V1_REG_UPDATE_ENABLE, enable);
+}
+
+static const struct axi_clkgen_mmcm_ops axi_clkgen_v1_mmcm_ops = {
+	.write = axi_clkgen_v1_mmcm_write,
+	.read = axi_clkgen_v1_mmcm_read,
+	.enable = axi_clkgen_v1_mmcm_enable,
+};
+
+static int axi_clkgen_wait_non_busy(struct axi_clkgen *axi_clkgen)
+{
+	unsigned int timeout = 10000;
+	unsigned int val;
+
+	do {
+		axi_clkgen_read(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_STATUS, &val);
+	} while ((val & AXI_CLKGEN_V2_DRP_STATUS_BUSY) && --timeout);
+
+	if (val & AXI_CLKGEN_V2_DRP_STATUS_BUSY)
+		return -EIO;
+
+	return val & 0xffff;
+}
+
+static int axi_clkgen_v2_mmcm_read(struct axi_clkgen *axi_clkgen,
+	unsigned int reg, unsigned int *val)
+{
+	unsigned int reg_val;
+	int ret;
+
+	ret = axi_clkgen_wait_non_busy(axi_clkgen);
+	if (ret < 0)
+		return ret;
+
+	reg_val = AXI_CLKGEN_V2_DRP_CNTRL_SEL | AXI_CLKGEN_V2_DRP_CNTRL_READ;
+	reg_val |= (reg << 16);
+
+	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val);
+
+	ret = axi_clkgen_wait_non_busy(axi_clkgen);
+	if (ret < 0)
+		return ret;
+
+	*val = ret;
+
+	return 0;
+}
+
+static int axi_clkgen_v2_mmcm_write(struct axi_clkgen *axi_clkgen,
+	unsigned int reg, unsigned int val, unsigned int mask)
+{
+	unsigned int reg_val = 0;
+	int ret;
+
+	ret = axi_clkgen_wait_non_busy(axi_clkgen);
+	if (ret < 0)
+		return ret;
+
+	if (mask != 0xffff) {
+		axi_clkgen_v2_mmcm_read(axi_clkgen, reg, &reg_val);
+		reg_val &= ~mask;
+	}
+
+	reg_val |= AXI_CLKGEN_V2_DRP_CNTRL_SEL | (reg << 16) | (val & mask);
+
+	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val);
+
+	return 0;
+}
+
+static void axi_clkgen_v2_mmcm_enable(struct axi_clkgen *axi_clkgen,
+	bool enable)
+{
+	unsigned int val = AXI_CLKGEN_V2_RESET_ENABLE;
+
+	if (enable)
+		val |= AXI_CLKGEN_V2_RESET_MMCM_ENABLE;
+
+	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_RESET, val);
+}
+
+static const struct axi_clkgen_mmcm_ops axi_clkgen_v2_mmcm_ops = {
+	.write = axi_clkgen_v2_mmcm_write,
+	.read = axi_clkgen_v2_mmcm_read,
+	.enable = axi_clkgen_v2_mmcm_enable,
+};
+
 static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw)
 {
 	return container_of(clk_hw, struct axi_clkgen, clk_hw);
@@ -184,33 +378,29 @@
 	filter = axi_clkgen_lookup_filter(m - 1);
 	lock = axi_clkgen_lookup_lock(m - 1);
 
-	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 0);
-
 	axi_clkgen_calc_clk_params(dout, &low, &high, &edge, &nocount);
-	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1,
-		(high << 6) | low);
-	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT2,
-		(edge << 7) | (nocount << 6));
+	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLKOUT0_1,
+		(high << 6) | low, 0xefff);
+	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLKOUT0_2,
+		(edge << 7) | (nocount << 6), 0x03ff);
 
 	axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount);
-	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV,
-		(edge << 13) | (nocount << 12) | (high << 6) | low);
+	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_DIV,
+		(edge << 13) | (nocount << 12) | (high << 6) | low, 0x3fff);
 
 	axi_clkgen_calc_clk_params(m, &low, &high, &edge, &nocount);
-	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1,
-		(high << 6) | low);
-	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB2,
-		(edge << 7) | (nocount << 6));
+	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_FB1,
+		(high << 6) | low, 0xefff);
+	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_FB2,
+		(edge << 7) | (nocount << 6), 0x03ff);
 
-	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK1, lock & 0x3ff);
-	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK2,
-		(((lock >> 16) & 0x1f) << 10) | 0x1);
-	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK3,
-		(((lock >> 24) & 0x1f) << 10) | 0x3e9);
-	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER1, filter >> 16);
-	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER2, filter);
-
-	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 1);
+	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK1, lock & 0x3ff, 0x3ff);
+	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK2,
+		(((lock >> 16) & 0x1f) << 10) | 0x1, 0x7fff);
+	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK3,
+		(((lock >> 24) & 0x1f) << 10) | 0x3e9, 0x7fff);
+	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER1, filter >> 16, 0x9900);
+	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER2, filter, 0x9900);
 
 	return 0;
 }
@@ -236,11 +426,11 @@
 	unsigned int reg;
 	unsigned long long tmp;
 
-	axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1, &reg);
+	axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, &reg);
 	dout = (reg & 0x3f) + ((reg >> 6) & 0x3f);
-	axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV, &reg);
+	axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, &reg);
 	d = (reg & 0x3f) + ((reg >> 6) & 0x3f);
-	axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1, &reg);
+	axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, &reg);
 	m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
 
 	if (d == 0 || dout == 0)
@@ -255,14 +445,45 @@
 	return tmp;
 }
 
+static int axi_clkgen_enable(struct clk_hw *clk_hw)
+{
+	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
+
+	axi_clkgen_mmcm_enable(axi_clkgen, true);
+
+	return 0;
+}
+
+static void axi_clkgen_disable(struct clk_hw *clk_hw)
+{
+	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
+
+	axi_clkgen_mmcm_enable(axi_clkgen, false);
+}
+
 static const struct clk_ops axi_clkgen_ops = {
 	.recalc_rate = axi_clkgen_recalc_rate,
 	.round_rate = axi_clkgen_round_rate,
 	.set_rate = axi_clkgen_set_rate,
+	.enable = axi_clkgen_enable,
+	.disable = axi_clkgen_disable,
 };
 
+static const struct of_device_id axi_clkgen_ids[] = {
+	{
+		.compatible = "adi,axi-clkgen-1.00.a",
+		.data = &axi_clkgen_v1_mmcm_ops
+	}, {
+		.compatible = "adi,axi-clkgen-2.00.a",
+		.data = &axi_clkgen_v2_mmcm_ops,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
+
 static int axi_clkgen_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *id;
 	struct axi_clkgen *axi_clkgen;
 	struct clk_init_data init;
 	const char *parent_name;
@@ -270,10 +491,19 @@
 	struct resource *mem;
 	struct clk *clk;
 
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	id = of_match_node(axi_clkgen_ids, pdev->dev.of_node);
+	if (!id)
+		return -ENODEV;
+
 	axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
 	if (!axi_clkgen)
 		return -ENOMEM;
 
+	axi_clkgen->mmcm_ops = id->data;
+
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem);
 	if (IS_ERR(axi_clkgen->base))
@@ -289,10 +519,12 @@
 
 	init.name = clk_name;
 	init.ops = &axi_clkgen_ops;
-	init.flags = 0;
+	init.flags = CLK_SET_RATE_GATE;
 	init.parent_names = &parent_name;
 	init.num_parents = 1;
 
+	axi_clkgen_mmcm_enable(axi_clkgen, false);
+
 	axi_clkgen->clk_hw.init = &init;
 	clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw);
 	if (IS_ERR(clk))
@@ -309,12 +541,6 @@
 	return 0;
 }
 
-static const struct of_device_id axi_clkgen_ids[] = {
-	{ .compatible = "adi,axi-clkgen-1.00.a" },
-	{ },
-};
-MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
-
 static struct platform_driver axi_clkgen_driver = {
 	.driver = {
 		.name = "adi-axi-clkgen",
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 5543b7d..ec22112 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -24,7 +24,7 @@
  * Traits of this clock:
  * prepare - clk_prepare only ensures that parents are prepared
  * enable - clk_enable only ensures that parents are enabled
- * rate - rate is adjustable.  clk->rate = parent->rate / divisor
+ * rate - rate is adjustable.  clk->rate = DIV_ROUND_UP(parent->rate / divisor)
  * parent - fixed parent.  No clk_set_parent support
  */
 
@@ -115,7 +115,7 @@
 		return parent_rate;
 	}
 
-	return parent_rate / div;
+	return DIV_ROUND_UP(parent_rate, div);
 }
 
 /*
@@ -185,7 +185,7 @@
 		}
 		parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
 				MULT_ROUND_UP(rate, i));
-		now = parent_rate / i;
+		now = DIV_ROUND_UP(parent_rate, i);
 		if (now <= rate && now > best) {
 			bestdiv = i;
 			best = now;
@@ -207,7 +207,7 @@
 	int div;
 	div = clk_divider_bestdiv(hw, rate, prate);
 
-	return *prate / div;
+	return DIV_ROUND_UP(*prate, div);
 }
 
 static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -218,7 +218,7 @@
 	unsigned long flags = 0;
 	u32 val;
 
-	div = parent_rate / rate;
+	div = DIV_ROUND_UP(parent_rate, rate);
 	value = _get_val(divider, div);
 
 	if (value > div_mask(divider))
diff --git a/drivers/clk/clk-moxart.c b/drivers/clk/clk-moxart.c
new file mode 100644
index 0000000..30a3b69
--- /dev/null
+++ b/drivers/clk/clk-moxart.c
@@ -0,0 +1,97 @@
+/*
+ * MOXA ART SoCs clock driver.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/clkdev.h>
+
+void __init moxart_of_pll_clk_init(struct device_node *node)
+{
+	static void __iomem *base;
+	struct clk *clk, *ref_clk;
+	unsigned int mul;
+	const char *name = node->name;
+	const char *parent_name;
+
+	of_property_read_string(node, "clock-output-names", &name);
+	parent_name = of_clk_get_parent_name(node, 0);
+
+	base = of_iomap(node, 0);
+	if (!base) {
+		pr_err("%s: of_iomap failed\n", node->full_name);
+		return;
+	}
+
+	mul = readl(base + 0x30) >> 3 & 0x3f;
+	iounmap(base);
+
+	ref_clk = of_clk_get(node, 0);
+	if (IS_ERR(ref_clk)) {
+		pr_err("%s: of_clk_get failed\n", node->full_name);
+		return;
+	}
+
+	clk = clk_register_fixed_factor(NULL, name, parent_name, 0, mul, 1);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register clock\n", node->full_name);
+		return;
+	}
+
+	clk_register_clkdev(clk, NULL, name);
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock",
+	       moxart_of_pll_clk_init);
+
+void __init moxart_of_apb_clk_init(struct device_node *node)
+{
+	static void __iomem *base;
+	struct clk *clk, *pll_clk;
+	unsigned int div, val;
+	unsigned int div_idx[] = { 2, 3, 4, 6, 8};
+	const char *name = node->name;
+	const char *parent_name;
+
+	of_property_read_string(node, "clock-output-names", &name);
+	parent_name = of_clk_get_parent_name(node, 0);
+
+	base = of_iomap(node, 0);
+	if (!base) {
+		pr_err("%s: of_iomap failed\n", node->full_name);
+		return;
+	}
+
+	val = readl(base + 0xc) >> 4 & 0x7;
+	iounmap(base);
+
+	if (val > 4)
+		val = 0;
+	div = div_idx[val] * 2;
+
+	pll_clk = of_clk_get(node, 0);
+	if (IS_ERR(pll_clk)) {
+		pr_err("%s: of_clk_get failed\n", node->full_name);
+		return;
+	}
+
+	clk = clk_register_fixed_factor(NULL, name, parent_name, 0, 1, div);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register clock\n", node->full_name);
+		return;
+	}
+
+	clk_register_clkdev(clk, NULL, name);
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock",
+	       moxart_of_apb_clk_init);
diff --git a/drivers/clk/clk-ppc-corenet.c b/drivers/clk/clk-ppc-corenet.c
index c4f76ed..8b284be 100644
--- a/drivers/clk/clk-ppc-corenet.c
+++ b/drivers/clk/clk-ppc-corenet.c
@@ -27,7 +27,6 @@
 #define CLKSEL_ADJUST		BIT(0)
 #define to_cmux_clk(p)		container_of(p, struct cmux_clk, hw)
 
-static void __iomem *base;
 static unsigned int clocks_per_pll;
 
 static int cmux_set_parent(struct clk_hw *hw, u8 idx)
@@ -100,7 +99,11 @@
 		pr_err("%s: could not allocate cmux_clk\n", __func__);
 		goto err_name;
 	}
-	cmux_clk->reg = base + offset;
+	cmux_clk->reg = of_iomap(np, 0);
+	if (!cmux_clk->reg) {
+		pr_err("%s: could not map register\n", __func__);
+		goto err_clk;
+	}
 
 	node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
 	if (node && (offset >= 0x80))
@@ -143,38 +146,39 @@
 
 static void __init core_pll_init(struct device_node *np)
 {
-	u32 offset, mult;
+	u32 mult;
 	int i, rc, count;
 	const char *clk_name, *parent_name;
 	struct clk_onecell_data *onecell_data;
 	struct clk      **subclks;
+	void __iomem *base;
 
-	rc = of_property_read_u32(np, "reg", &offset);
-	if (rc) {
-		pr_err("%s: could not get reg property\n", np->name);
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("clk-ppc: iomap error\n");
 		return;
 	}
 
 	/* get the multiple of PLL */
-	mult = ioread32be(base + offset);
+	mult = ioread32be(base);
 
 	/* check if this PLL is disabled */
 	if (mult & PLL_KILL) {
 		pr_debug("PLL:%s is disabled\n", np->name);
-		return;
+		goto err_map;
 	}
 	mult = (mult >> 1) & 0x3f;
 
 	parent_name = of_clk_get_parent_name(np, 0);
 	if (!parent_name) {
 		pr_err("PLL: %s must have a parent\n", np->name);
-		return;
+		goto err_map;
 	}
 
 	count = of_property_count_strings(np, "clock-output-names");
 	if (count < 0 || count > 4) {
 		pr_err("%s: clock is not supported\n", np->name);
-		return;
+		goto err_map;
 	}
 
 	/* output clock number per PLL */
@@ -183,7 +187,7 @@
 	subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
 	if (!subclks) {
 		pr_err("%s: could not allocate subclks\n", __func__);
-		return;
+		goto err_map;
 	}
 
 	onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
@@ -230,30 +234,52 @@
 		goto err_cell;
 	}
 
+	iounmap(base);
 	return;
 err_cell:
 	kfree(onecell_data);
 err_clks:
 	kfree(subclks);
+err_map:
+	iounmap(base);
+}
+
+static void __init sysclk_init(struct device_node *node)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+	struct device_node *np = of_get_parent(node);
+	u32 rate;
+
+	if (!np) {
+		pr_err("ppc-clk: could not get parent node\n");
+		return;
+	}
+
+	if (of_property_read_u32(np, "clock-frequency", &rate)) {
+		of_node_put(node);
+		return;
+	}
+
+	of_property_read_string(np, "clock-output-names", &clk_name);
+
+	clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
+	if (!IS_ERR(clk))
+		of_clk_add_provider(np, of_clk_src_simple_get, clk);
 }
 
 static const struct of_device_id clk_match[] __initconst = {
-	{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
-	{ .compatible = "fsl,core-pll-clock", .data = core_pll_init, },
-	{ .compatible = "fsl,core-mux-clock", .data = core_mux_init, },
+	{ .compatible = "fsl,qoriq-sysclk-1.0", .data = sysclk_init, },
+	{ .compatible = "fsl,qoriq-sysclk-2.0", .data = sysclk_init, },
+	{ .compatible = "fsl,qoriq-core-pll-1.0", .data = core_pll_init, },
+	{ .compatible = "fsl,qoriq-core-pll-2.0", .data = core_pll_init, },
+	{ .compatible = "fsl,qoriq-core-mux-1.0", .data = core_mux_init, },
+	{ .compatible = "fsl,qoriq-core-mux-2.0", .data = core_mux_init, },
 	{}
 };
 
 static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
 {
-	struct device_node *np;
-
-	np = pdev->dev.of_node;
-	base = of_iomap(np, 0);
-	if (!base) {
-		dev_err(&pdev->dev, "iomap error\n");
-		return -ENOMEM;
-	}
 	of_clk_init(clk_match);
 
 	return 0;
diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c
index 00a3abe..f2f62a1 100644
--- a/drivers/clk/clk-s2mps11.c
+++ b/drivers/clk/clk-s2mps11.c
@@ -27,6 +27,7 @@
 #include <linux/clk-provider.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s5m8767.h>
 #include <linux/mfd/samsung/core.h>
 
 #define s2mps11_name(a) (a->hw.init->name)
@@ -48,6 +49,7 @@
 	struct clk_lookup *lookup;
 	u32 mask;
 	bool enabled;
+	unsigned int reg;
 };
 
 static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw)
@@ -61,7 +63,7 @@
 	int ret;
 
 	ret = regmap_update_bits(s2mps11->iodev->regmap_pmic,
-				S2MPS11_REG_RTC_CTRL,
+				 s2mps11->reg,
 				 s2mps11->mask, s2mps11->mask);
 	if (!ret)
 		s2mps11->enabled = true;
@@ -74,7 +76,7 @@
 	struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
 	int ret;
 
-	ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, S2MPS11_REG_RTC_CTRL,
+	ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg,
 			   s2mps11->mask, ~s2mps11->mask);
 
 	if (!ret)
@@ -130,9 +132,9 @@
 	int i;
 
 	if (!iodev->dev->of_node)
-		return NULL;
+		return ERR_PTR(-EINVAL);
 
-	clk_np = of_find_node_by_name(iodev->dev->of_node, "clocks");
+	clk_np = of_get_child_by_name(iodev->dev->of_node, "clocks");
 	if (!clk_np) {
 		dev_err(&pdev->dev, "could not find clock sub-node\n");
 		return ERR_PTR(-EINVAL);
@@ -155,6 +157,7 @@
 	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
 	struct s2mps11_clk *s2mps11_clks, *s2mps11_clk;
 	struct device_node *clk_np = NULL;
+	unsigned int s2mps11_reg;
 	int i, ret = 0;
 	u32 val;
 
@@ -169,13 +172,26 @@
 	if (IS_ERR(clk_np))
 		return PTR_ERR(clk_np);
 
+	switch(platform_get_device_id(pdev)->driver_data) {
+	case S2MPS11X:
+		s2mps11_reg = S2MPS11_REG_RTC_CTRL;
+		break;
+	case S5M8767X:
+		s2mps11_reg = S5M8767_REG_CTRL1;
+		break;
+	default:
+		dev_err(&pdev->dev, "Invalid device type\n");
+		return -EINVAL;
+	};
+
 	for (i = 0; i < S2MPS11_CLKS_NUM; i++, s2mps11_clk++) {
 		s2mps11_clk->iodev = iodev;
 		s2mps11_clk->hw.init = &s2mps11_clks_init[i];
 		s2mps11_clk->mask = 1 << i;
+		s2mps11_clk->reg = s2mps11_reg;
 
 		ret = regmap_read(s2mps11_clk->iodev->regmap_pmic,
-				  S2MPS11_REG_RTC_CTRL, &val);
+				  s2mps11_clk->reg, &val);
 		if (ret < 0)
 			goto err_reg;
 
@@ -241,7 +257,8 @@
 }
 
 static const struct platform_device_id s2mps11_clk_id[] = {
-	{ "s2mps11-clk", 0},
+	{ "s2mps11-clk", S2MPS11X},
+	{ "s5m8767-clk", S5M8767X},
 	{ },
 };
 MODULE_DEVICE_TABLE(platform, s2mps11_clk_id);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index c42e608..dff0373 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -277,6 +277,10 @@
 	if (!d)
 		goto err_out;
 
+	if (clk->ops->debug_init)
+		if (clk->ops->debug_init(clk->hw, clk->dentry))
+			goto err_out;
+
 	ret = 0;
 	goto out;
 
@@ -1339,8 +1343,11 @@
 	if (clk->notifier_count)
 		ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
 
-	if (ret & NOTIFY_STOP_MASK)
+	if (ret & NOTIFY_STOP_MASK) {
+		pr_debug("%s: clk notifier callback for clock %s aborted with error %d\n",
+				__func__, clk->name, ret);
 		goto out;
+	}
 
 	hlist_for_each_entry(child, &clk->children, child_node) {
 		ret = __clk_speculate_rates(child, new_rate);
@@ -1588,7 +1595,7 @@
 	/* notify that we are about to change rates */
 	fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
 	if (fail_clk) {
-		pr_warn("%s: failed to set %s rate\n", __func__,
+		pr_debug("%s: failed to set %s rate\n", __func__,
 				fail_clk->name);
 		clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
 		ret = -EBUSY;
@@ -2260,20 +2267,11 @@
  * re-enter into the clk framework by calling any top-level clk APIs;
  * this will cause a nested prepare_lock mutex.
  *
- * Pre-change notifier callbacks will be passed the current, pre-change
- * rate of the clk via struct clk_notifier_data.old_rate.  The new,
- * post-change rate of the clk is passed via struct
+ * In all notification cases cases (pre, post and abort rate change) the
+ * original clock rate is passed to the callback via struct
+ * clk_notifier_data.old_rate and the new frequency is passed via struct
  * clk_notifier_data.new_rate.
  *
- * Post-change notifiers will pass the now-current, post-change rate of
- * the clk in both struct clk_notifier_data.old_rate and struct
- * clk_notifier_data.new_rate.
- *
- * Abort-change notifiers are effectively the opposite of pre-change
- * notifiers: the original pre-change clk rate is passed in via struct
- * clk_notifier_data.new_rate and the failed post-change rate is passed
- * in via struct clk_notifier_data.old_rate.
- *
  * clk_notifier_register() must be called from non-atomic context.
  * Returns -EINVAL if called with null arguments, -ENOMEM upon
  * allocation failure; otherwise, passes along the return value of
@@ -2473,7 +2471,7 @@
 struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec)
 {
 	struct of_clk_provider *provider;
-	struct clk *clk = ERR_PTR(-ENOENT);
+	struct clk *clk = ERR_PTR(-EPROBE_DEFER);
 
 	/* Check if we have such a provider in our array */
 	list_for_each_entry(provider, &of_clk_providers, link) {
@@ -2506,8 +2504,12 @@
 const char *of_clk_get_parent_name(struct device_node *np, int index)
 {
 	struct of_phandle_args clkspec;
+	struct property *prop;
 	const char *clk_name;
+	const __be32 *vp;
+	u32 pv;
 	int rc;
+	int count;
 
 	if (index < 0)
 		return NULL;
@@ -2517,8 +2519,22 @@
 	if (rc)
 		return NULL;
 
+	index = clkspec.args_count ? clkspec.args[0] : 0;
+	count = 0;
+
+	/* if there is an indices property, use it to transfer the index
+	 * specified into an array offset for the clock-output-names property.
+	 */
+	of_property_for_each_u32(clkspec.np, "clock-indices", prop, vp, pv) {
+		if (index == pv) {
+			index = count;
+			break;
+		}
+		count++;
+	}
+
 	if (of_property_read_string_index(clkspec.np, "clock-output-names",
-					  clkspec.args_count ? clkspec.args[0] : 0,
+					  index,
 					  &clk_name) < 0)
 		clk_name = clkspec.np->name;
 
@@ -2527,24 +2543,99 @@
 }
 EXPORT_SYMBOL_GPL(of_clk_get_parent_name);
 
+struct clock_provider {
+	of_clk_init_cb_t clk_init_cb;
+	struct device_node *np;
+	struct list_head node;
+};
+
+static LIST_HEAD(clk_provider_list);
+
+/*
+ * This function looks for a parent clock. If there is one, then it
+ * checks that the provider for this parent clock was initialized, in
+ * this case the parent clock will be ready.
+ */
+static int parent_ready(struct device_node *np)
+{
+	int i = 0;
+
+	while (true) {
+		struct clk *clk = of_clk_get(np, i);
+
+		/* this parent is ready we can check the next one */
+		if (!IS_ERR(clk)) {
+			clk_put(clk);
+			i++;
+			continue;
+		}
+
+		/* at least one parent is not ready, we exit now */
+		if (PTR_ERR(clk) == -EPROBE_DEFER)
+			return 0;
+
+		/*
+		 * Here we make assumption that the device tree is
+		 * written correctly. So an error means that there is
+		 * no more parent. As we didn't exit yet, then the
+		 * previous parent are ready. If there is no clock
+		 * parent, no need to wait for them, then we can
+		 * consider their absence as being ready
+		 */
+		return 1;
+	}
+}
+
 /**
  * of_clk_init() - Scan and init clock providers from the DT
  * @matches: array of compatible values and init functions for providers.
  *
- * This function scans the device tree for matching clock providers and
- * calls their initialization functions
+ * This function scans the device tree for matching clock providers
+ * and calls their initialization functions. It also does it by trying
+ * to follow the dependencies.
  */
 void __init of_clk_init(const struct of_device_id *matches)
 {
 	const struct of_device_id *match;
 	struct device_node *np;
+	struct clock_provider *clk_provider, *next;
+	bool is_init_done;
+	bool force = false;
 
 	if (!matches)
 		matches = &__clk_of_table;
 
+	/* First prepare the list of the clocks providers */
 	for_each_matching_node_and_match(np, matches, &match) {
-		of_clk_init_cb_t clk_init_cb = match->data;
-		clk_init_cb(np);
+		struct clock_provider *parent =
+			kzalloc(sizeof(struct clock_provider),	GFP_KERNEL);
+
+		parent->clk_init_cb = match->data;
+		parent->np = np;
+		list_add_tail(&parent->node, &clk_provider_list);
+	}
+
+	while (!list_empty(&clk_provider_list)) {
+		is_init_done = false;
+		list_for_each_entry_safe(clk_provider, next,
+					&clk_provider_list, node) {
+			if (force || parent_ready(clk_provider->np)) {
+				clk_provider->clk_init_cb(clk_provider->np);
+				list_del(&clk_provider->node);
+				kfree(clk_provider);
+				is_init_done = true;
+			}
+		}
+
+		/*
+		 * We didn't manage to initialize any of the
+		 * remaining providers during the last loop, so now we
+		 * initialize all the remaining ones unconditionally
+		 * in case the clock parent was not mandatory
+		 */
+		if (!is_init_done)
+			force = true;
+
 	}
 }
 #endif
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 48f6721..a360b2e 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -167,6 +167,8 @@
 		clk = of_clk_get_by_name(dev->of_node, con_id);
 		if (!IS_ERR(clk))
 			return clk;
+		if (PTR_ERR(clk) == -EPROBE_DEFER)
+			return clk;
 	}
 
 	return clk_get_sys(dev_id, con_id);
diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
index a049108..40b33c6 100644
--- a/drivers/clk/hisilicon/Makefile
+++ b/drivers/clk/hisilicon/Makefile
@@ -2,4 +2,7 @@
 # Hisilicon Clock specific Makefile
 #
 
-obj-y	+= clk.o clkgate-separated.o clk-hi3620.o
+obj-y	+= clk.o clkgate-separated.o
+
+obj-$(CONFIG_ARCH_HI3xxx)	+= clk-hi3620.o
+obj-$(CONFIG_ARCH_HIP04)	+= clk-hip04.o
diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c
index f24ad6a..339945d 100644
--- a/drivers/clk/hisilicon/clk-hi3620.c
+++ b/drivers/clk/hisilicon/clk-hi3620.c
@@ -210,33 +210,297 @@
 
 static void __init hi3620_clk_init(struct device_node *np)
 {
-	void __iomem *base;
+	struct hisi_clock_data *clk_data;
 
-	if (np) {
-		base = of_iomap(np, 0);
-		if (!base) {
-			pr_err("failed to map Hi3620 clock registers\n");
-			return;
-		}
-	} else {
-		pr_err("failed to find Hi3620 clock node in DTS\n");
+	clk_data = hisi_clk_init(np, HI3620_NR_CLKS);
+	if (!clk_data)
 		return;
-	}
-
-	hisi_clk_init(np, HI3620_NR_CLKS);
 
 	hisi_clk_register_fixed_rate(hi3620_fixed_rate_clks,
 				     ARRAY_SIZE(hi3620_fixed_rate_clks),
-				     base);
+				     clk_data);
 	hisi_clk_register_fixed_factor(hi3620_fixed_factor_clks,
 				       ARRAY_SIZE(hi3620_fixed_factor_clks),
-				       base);
+				       clk_data);
 	hisi_clk_register_mux(hi3620_mux_clks, ARRAY_SIZE(hi3620_mux_clks),
-			      base);
+			      clk_data);
 	hisi_clk_register_divider(hi3620_div_clks, ARRAY_SIZE(hi3620_div_clks),
-				  base);
+				  clk_data);
 	hisi_clk_register_gate_sep(hi3620_seperated_gate_clks,
 				   ARRAY_SIZE(hi3620_seperated_gate_clks),
-				   base);
+				   clk_data);
 }
 CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init);
+
+struct hisi_mmc_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	u32			clken_reg;
+	u32			clken_bit;
+	u32			div_reg;
+	u32			div_off;
+	u32			div_bits;
+	u32			drv_reg;
+	u32			drv_off;
+	u32			drv_bits;
+	u32			sam_reg;
+	u32			sam_off;
+	u32			sam_bits;
+};
+
+struct clk_mmc {
+	struct clk_hw	hw;
+	u32		id;
+	void __iomem	*clken_reg;
+	u32		clken_bit;
+	void __iomem	*div_reg;
+	u32		div_off;
+	u32		div_bits;
+	void __iomem	*drv_reg;
+	u32		drv_off;
+	u32		drv_bits;
+	void __iomem	*sam_reg;
+	u32		sam_off;
+	u32		sam_bits;
+};
+
+#define to_mmc(_hw) container_of(_hw, struct clk_mmc, hw)
+
+static struct hisi_mmc_clock hi3620_mmc_clks[] __initdata = {
+	{ HI3620_SD_CIUCLK,	"sd_bclk1", "sd_clk", CLK_SET_RATE_PARENT, 0x1f8, 0, 0x1f8, 1, 3, 0x1f8, 4, 4, 0x1f8, 8, 4},
+	{ HI3620_MMC_CIUCLK1,   "mmc_bclk1", "mmc_clk1", CLK_SET_RATE_PARENT, 0x1f8, 12, 0x1f8, 13, 3, 0x1f8, 16, 4, 0x1f8, 20, 4},
+	{ HI3620_MMC_CIUCLK2,   "mmc_bclk2", "mmc_clk2", CLK_SET_RATE_PARENT, 0x1f8, 24, 0x1f8, 25, 3, 0x1f8, 28, 4, 0x1fc, 0, 4},
+	{ HI3620_MMC_CIUCLK3,   "mmc_bclk3", "mmc_clk3", CLK_SET_RATE_PARENT, 0x1fc, 4, 0x1fc, 5, 3, 0x1fc, 8, 4, 0x1fc, 12, 4},
+};
+
+static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
+		       unsigned long parent_rate)
+{
+	switch (parent_rate) {
+	case 26000000:
+		return 13000000;
+	case 180000000:
+		return 25000000;
+	case 360000000:
+		return 50000000;
+	case 720000000:
+		return 100000000;
+	case 1440000000:
+		return 180000000;
+	default:
+		return parent_rate;
+	}
+}
+
+static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+			      unsigned long *best_parent_rate,
+			      struct clk **best_parent_p)
+{
+	struct clk_mmc *mclk = to_mmc(hw);
+	unsigned long best = 0;
+
+	if ((rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) {
+		rate = 13000000;
+		best = 26000000;
+	} else if (rate <= 26000000) {
+		rate = 25000000;
+		best = 180000000;
+	} else if (rate <= 52000000) {
+		rate = 50000000;
+		best = 360000000;
+	} else if (rate <= 100000000) {
+		rate = 100000000;
+		best = 720000000;
+	} else {
+		/* max is 180M */
+		rate = 180000000;
+		best = 1440000000;
+	}
+	*best_parent_rate = best;
+	return rate;
+}
+
+static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len)
+{
+	u32 i;
+
+	for (i = 0; i < len; i++) {
+		if (para % 2)
+			val |= 1 << (off + i);
+		else
+			val &= ~(1 << (off + i));
+		para = para >> 1;
+	}
+
+	return val;
+}
+
+static int mmc_clk_set_timing(struct clk_hw *hw, unsigned long rate)
+{
+	struct clk_mmc *mclk = to_mmc(hw);
+	unsigned long flags;
+	u32 sam, drv, div, val;
+	static DEFINE_SPINLOCK(mmc_clk_lock);
+
+	switch (rate) {
+	case 13000000:
+		sam = 3;
+		drv = 1;
+		div = 1;
+		break;
+	case 25000000:
+		sam = 13;
+		drv = 6;
+		div = 6;
+		break;
+	case 50000000:
+		sam = 3;
+		drv = 6;
+		div = 6;
+		break;
+	case 100000000:
+		sam = 6;
+		drv = 4;
+		div = 6;
+		break;
+	case 180000000:
+		sam = 6;
+		drv = 4;
+		div = 7;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&mmc_clk_lock, flags);
+
+	val = readl_relaxed(mclk->clken_reg);
+	val &= ~(1 << mclk->clken_bit);
+	writel_relaxed(val, mclk->clken_reg);
+
+	val = readl_relaxed(mclk->sam_reg);
+	val = mmc_clk_delay(val, sam, mclk->sam_off, mclk->sam_bits);
+	writel_relaxed(val, mclk->sam_reg);
+
+	val = readl_relaxed(mclk->drv_reg);
+	val = mmc_clk_delay(val, drv, mclk->drv_off, mclk->drv_bits);
+	writel_relaxed(val, mclk->drv_reg);
+
+	val = readl_relaxed(mclk->div_reg);
+	val = mmc_clk_delay(val, div, mclk->div_off, mclk->div_bits);
+	writel_relaxed(val, mclk->div_reg);
+
+	val = readl_relaxed(mclk->clken_reg);
+	val |= 1 << mclk->clken_bit;
+	writel_relaxed(val, mclk->clken_reg);
+
+	spin_unlock_irqrestore(&mmc_clk_lock, flags);
+
+	return 0;
+}
+
+static int mmc_clk_prepare(struct clk_hw *hw)
+{
+	struct clk_mmc *mclk = to_mmc(hw);
+	unsigned long rate;
+
+	if (mclk->id == HI3620_MMC_CIUCLK1)
+		rate = 13000000;
+	else
+		rate = 25000000;
+
+	return mmc_clk_set_timing(hw, rate);
+}
+
+static int mmc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+			     unsigned long parent_rate)
+{
+	return mmc_clk_set_timing(hw, rate);
+}
+
+static struct clk_ops clk_mmc_ops = {
+	.prepare = mmc_clk_prepare,
+	.determine_rate = mmc_clk_determine_rate,
+	.set_rate = mmc_clk_set_rate,
+	.recalc_rate = mmc_clk_recalc_rate,
+};
+
+static struct clk *hisi_register_clk_mmc(struct hisi_mmc_clock *mmc_clk,
+			void __iomem *base, struct device_node *np)
+{
+	struct clk_mmc *mclk;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	mclk = kzalloc(sizeof(*mclk), GFP_KERNEL);
+	if (!mclk) {
+		pr_err("%s: fail to allocate mmc clk\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	init.name = mmc_clk->name;
+	init.ops = &clk_mmc_ops;
+	init.flags = mmc_clk->flags | CLK_IS_BASIC;
+	init.parent_names = (mmc_clk->parent_name ? &mmc_clk->parent_name : NULL);
+	init.num_parents = (mmc_clk->parent_name ? 1 : 0);
+	mclk->hw.init = &init;
+
+	mclk->id = mmc_clk->id;
+	mclk->clken_reg = base + mmc_clk->clken_reg;
+	mclk->clken_bit = mmc_clk->clken_bit;
+	mclk->div_reg = base + mmc_clk->div_reg;
+	mclk->div_off = mmc_clk->div_off;
+	mclk->div_bits = mmc_clk->div_bits;
+	mclk->drv_reg = base + mmc_clk->drv_reg;
+	mclk->drv_off = mmc_clk->drv_off;
+	mclk->drv_bits = mmc_clk->drv_bits;
+	mclk->sam_reg = base + mmc_clk->sam_reg;
+	mclk->sam_off = mmc_clk->sam_off;
+	mclk->sam_bits = mmc_clk->sam_bits;
+
+	clk = clk_register(NULL, &mclk->hw);
+	if (WARN_ON(IS_ERR(clk)))
+		kfree(mclk);
+	return clk;
+}
+
+static void __init hi3620_mmc_clk_init(struct device_node *node)
+{
+	void __iomem *base;
+	int i, num = ARRAY_SIZE(hi3620_mmc_clks);
+	struct clk_onecell_data *clk_data;
+
+	if (!node) {
+		pr_err("failed to find pctrl node in DTS\n");
+		return;
+	}
+
+	base = of_iomap(node, 0);
+	if (!base) {
+		pr_err("failed to map pctrl\n");
+		return;
+	}
+
+	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (WARN_ON(!clk_data))
+		return;
+
+	clk_data->clks = kzalloc(sizeof(struct clk *) * num, GFP_KERNEL);
+	if (!clk_data->clks) {
+		pr_err("%s: fail to allocate mmc clk\n", __func__);
+		return;
+	}
+
+	for (i = 0; i < num; i++) {
+		struct hisi_mmc_clock *mmc_clk = &hi3620_mmc_clks[i];
+		clk_data->clks[mmc_clk->id] =
+			hisi_register_clk_mmc(mmc_clk, base, node);
+	}
+
+	clk_data->clk_num = num;
+	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+}
+
+CLK_OF_DECLARE(hi3620_mmc_clk, "hisilicon,hi3620-mmc-clock", hi3620_mmc_clk_init);
diff --git a/drivers/clk/hisilicon/clk-hip04.c b/drivers/clk/hisilicon/clk-hip04.c
new file mode 100644
index 0000000..132b57a
--- /dev/null
+++ b/drivers/clk/hisilicon/clk-hip04.c
@@ -0,0 +1,58 @@
+/*
+ * Hisilicon HiP04 clock driver
+ *
+ * Copyright (c) 2013-2014 Hisilicon Limited.
+ * Copyright (c) 2013-2014 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#include <dt-bindings/clock/hip04-clock.h>
+
+#include "clk.h"
+
+/* fixed rate clocks */
+static struct hisi_fixed_rate_clock hip04_fixed_rate_clks[] __initdata = {
+	{ HIP04_OSC50M,   "osc50m",   NULL, CLK_IS_ROOT, 50000000, },
+	{ HIP04_CLK_50M,  "clk50m",   NULL, CLK_IS_ROOT, 50000000, },
+	{ HIP04_CLK_168M, "clk168m",  NULL, CLK_IS_ROOT, 168750000, },
+};
+
+static void __init hip04_clk_init(struct device_node *np)
+{
+	struct hisi_clock_data *clk_data;
+
+	clk_data = hisi_clk_init(np, HIP04_NR_CLKS);
+	if (!clk_data)
+		return;
+
+	hisi_clk_register_fixed_rate(hip04_fixed_rate_clks,
+				     ARRAY_SIZE(hip04_fixed_rate_clks),
+				     clk_data);
+}
+CLK_OF_DECLARE(hip04_clk, "hisilicon,hip04-clock", hip04_clk_init);
diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
index a3a7152..276f672 100644
--- a/drivers/clk/hisilicon/clk.c
+++ b/drivers/clk/hisilicon/clk.c
@@ -37,23 +37,49 @@
 #include "clk.h"
 
 static DEFINE_SPINLOCK(hisi_clk_lock);
-static struct clk **clk_table;
-static struct clk_onecell_data clk_data;
 
-void __init hisi_clk_init(struct device_node *np, int nr_clks)
+struct hisi_clock_data __init *hisi_clk_init(struct device_node *np,
+					     int nr_clks)
 {
+	struct hisi_clock_data *clk_data;
+	struct clk **clk_table;
+	void __iomem *base;
+
+	if (np) {
+		base = of_iomap(np, 0);
+		if (!base) {
+			pr_err("failed to map Hisilicon clock registers\n");
+			goto err;
+		}
+	} else {
+		pr_err("failed to find Hisilicon clock node in DTS\n");
+		goto err;
+	}
+
+	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data) {
+		pr_err("%s: could not allocate clock data\n", __func__);
+		goto err;
+	}
+	clk_data->base = base;
+
 	clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
 	if (!clk_table) {
 		pr_err("%s: could not allocate clock lookup table\n", __func__);
-		return;
+		goto err_data;
 	}
-	clk_data.clks = clk_table;
-	clk_data.clk_num = nr_clks;
-	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	clk_data->clk_data.clks = clk_table;
+	clk_data->clk_data.clk_num = nr_clks;
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
+	return clk_data;
+err_data:
+	kfree(clk_data);
+err:
+	return NULL;
 }
 
 void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks,
-					 int nums, void __iomem *base)
+					 int nums, struct hisi_clock_data *data)
 {
 	struct clk *clk;
 	int i;
@@ -68,11 +94,13 @@
 			       __func__, clks[i].name);
 			continue;
 		}
+		data->clk_data.clks[clks[i].id] = clk;
 	}
 }
 
 void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks,
-					   int nums, void __iomem *base)
+					   int nums,
+					   struct hisi_clock_data *data)
 {
 	struct clk *clk;
 	int i;
@@ -87,13 +115,15 @@
 			       __func__, clks[i].name);
 			continue;
 		}
+		data->clk_data.clks[clks[i].id] = clk;
 	}
 }
 
 void __init hisi_clk_register_mux(struct hisi_mux_clock *clks,
-				  int nums, void __iomem *base)
+				  int nums, struct hisi_clock_data *data)
 {
 	struct clk *clk;
+	void __iomem *base = data->base;
 	int i;
 
 	for (i = 0; i < nums; i++) {
@@ -111,14 +141,15 @@
 		if (clks[i].alias)
 			clk_register_clkdev(clk, clks[i].alias, NULL);
 
-		clk_table[clks[i].id] = clk;
+		data->clk_data.clks[clks[i].id] = clk;
 	}
 }
 
 void __init hisi_clk_register_divider(struct hisi_divider_clock *clks,
-				      int nums, void __iomem *base)
+				      int nums, struct hisi_clock_data *data)
 {
 	struct clk *clk;
+	void __iomem *base = data->base;
 	int i;
 
 	for (i = 0; i < nums; i++) {
@@ -139,14 +170,15 @@
 		if (clks[i].alias)
 			clk_register_clkdev(clk, clks[i].alias, NULL);
 
-		clk_table[clks[i].id] = clk;
+		data->clk_data.clks[clks[i].id] = clk;
 	}
 }
 
 void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
-				       int nums, void __iomem *base)
+				       int nums, struct hisi_clock_data *data)
 {
 	struct clk *clk;
+	void __iomem *base = data->base;
 	int i;
 
 	for (i = 0; i < nums; i++) {
@@ -166,6 +198,6 @@
 		if (clks[i].alias)
 			clk_register_clkdev(clk, clks[i].alias, NULL);
 
-		clk_table[clks[i].id] = clk;
+		data->clk_data.clks[clks[i].id] = clk;
 	}
 }
diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
index 4a6beeb..43fa5da 100644
--- a/drivers/clk/hisilicon/clk.h
+++ b/drivers/clk/hisilicon/clk.h
@@ -30,6 +30,11 @@
 #include <linux/io.h>
 #include <linux/spinlock.h>
 
+struct hisi_clock_data {
+	struct clk_onecell_data	clk_data;
+	void __iomem		*base;
+};
+
 struct hisi_fixed_rate_clock {
 	unsigned int		id;
 	char			*name;
@@ -89,15 +94,15 @@
 				void __iomem *, u8,
 				u8, spinlock_t *);
 
-void __init hisi_clk_init(struct device_node *, int);
+struct hisi_clock_data __init *hisi_clk_init(struct device_node *, int);
 void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
-					int, void __iomem *);
+					int, struct hisi_clock_data *);
 void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *,
-					int, void __iomem *);
+					int, struct hisi_clock_data *);
 void __init hisi_clk_register_mux(struct hisi_mux_clock *, int,
-				void __iomem *);
+				struct hisi_clock_data *);
 void __init hisi_clk_register_divider(struct hisi_divider_clock *,
-				int, void __iomem *);
+				int, struct hisi_clock_data *);
 void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
-					int, void __iomem *);
+					int, struct hisi_clock_data *);
 #endif	/* __HISI_CLK_H */
diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c
index 80c1dd1..23a56f5 100644
--- a/drivers/clk/mmp/clk-frac.c
+++ b/drivers/clk/mmp/clk-frac.c
@@ -40,15 +40,19 @@
 
 	for (i = 0; i < factor->ftbl_cnt; i++) {
 		prev_rate = rate;
-		rate = (((*prate / 10000) * factor->ftbl[i].num) /
-			(factor->ftbl[i].den * factor->masks->factor)) * 10000;
+		rate = (((*prate / 10000) * factor->ftbl[i].den) /
+			(factor->ftbl[i].num * factor->masks->factor)) * 10000;
 		if (rate > drate)
 			break;
 	}
-	if (i == 0)
+	if ((i == 0) || (i == factor->ftbl_cnt)) {
 		return rate;
-	else
-		return prev_rate;
+	} else {
+		if ((drate - prev_rate) > (rate - drate))
+			return rate;
+		else
+			return prev_rate;
+	}
 }
 
 static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
@@ -64,7 +68,7 @@
 	num = (val >> masks->num_shift) & masks->num_mask;
 
 	/* calculate denominator */
-	den = (val >> masks->den_shift) & masks->num_mask;
+	den = (val >> masks->den_shift) & masks->den_mask;
 
 	if (!den)
 		return 0;
@@ -85,8 +89,8 @@
 
 	for (i = 0; i < factor->ftbl_cnt; i++) {
 		prev_rate = rate;
-		rate = (((prate / 10000) * factor->ftbl[i].num) /
-			(factor->ftbl[i].den * factor->masks->factor)) * 10000;
+		rate = (((prate / 10000) * factor->ftbl[i].den) /
+			(factor->ftbl[i].num * factor->masks->factor)) * 10000;
 		if (rate > drate)
 			break;
 	}
diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig
index c339b82..693f7be 100644
--- a/drivers/clk/mvebu/Kconfig
+++ b/drivers/clk/mvebu/Kconfig
@@ -13,6 +13,14 @@
 	select MVEBU_CLK_CPU
 	select MVEBU_CLK_COREDIV
 
+config ARMADA_375_CLK
+	bool
+	select MVEBU_CLK_COMMON
+
+config ARMADA_38X_CLK
+	bool
+	select MVEBU_CLK_COMMON
+
 config ARMADA_XP_CLK
 	bool
 	select MVEBU_CLK_COMMON
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile
index 21bbfb4..4c66162 100644
--- a/drivers/clk/mvebu/Makefile
+++ b/drivers/clk/mvebu/Makefile
@@ -3,6 +3,8 @@
 obj-$(CONFIG_MVEBU_CLK_COREDIV)	+= clk-corediv.o
 
 obj-$(CONFIG_ARMADA_370_CLK)	+= armada-370.o
+obj-$(CONFIG_ARMADA_375_CLK)	+= armada-375.o
+obj-$(CONFIG_ARMADA_38X_CLK)	+= armada-38x.o
 obj-$(CONFIG_ARMADA_XP_CLK)	+= armada-xp.o
 obj-$(CONFIG_DOVE_CLK)		+= dove.o
 obj-$(CONFIG_KIRKWOOD_CLK)	+= kirkwood.o
diff --git a/drivers/clk/mvebu/armada-375.c b/drivers/clk/mvebu/armada-375.c
new file mode 100644
index 0000000..c991a4d
--- /dev/null
+++ b/drivers/clk/mvebu/armada-375.c
@@ -0,0 +1,184 @@
+/*
+ * Marvell Armada 375 SoC clocks
+ *
+ * Copyright (C) 2014 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Andrew Lunn <andrew@lunn.ch>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include "common.h"
+
+/*
+ * Core Clocks
+ */
+
+/*
+ * For the Armada 375 SoCs, the CPU, DDR and L2 clocks frequencies are
+ * all modified at the same time, and not separately as for the Armada
+ * 370 or the Armada XP SoCs.
+ *
+ * SAR0[21:17]   : CPU frequency    DDR frequency   L2 frequency
+ *		 6   =  400 MHz	    400 MHz	    200 MHz
+ *		 15  =  600 MHz	    600 MHz	    300 MHz
+ *		 21  =  800 MHz	    534 MHz	    400 MHz
+ *		 25  = 1000 MHz	    500 MHz	    500 MHz
+ *		 others reserved.
+ *
+ * SAR0[22]   : TCLK frequency
+ *		 0 = 166 MHz
+ *		 1 = 200 MHz
+ */
+
+#define SAR1_A375_TCLK_FREQ_OPT		   22
+#define SAR1_A375_TCLK_FREQ_OPT_MASK	   0x1
+#define SAR1_A375_CPU_DDR_L2_FREQ_OPT	   17
+#define SAR1_A375_CPU_DDR_L2_FREQ_OPT_MASK 0x1F
+
+static const u32 armada_375_tclk_frequencies[] __initconst = {
+	166000000,
+	200000000,
+};
+
+static u32 __init armada_375_get_tclk_freq(void __iomem *sar)
+{
+	u8 tclk_freq_select;
+
+	tclk_freq_select = ((readl(sar) >> SAR1_A375_TCLK_FREQ_OPT) &
+			    SAR1_A375_TCLK_FREQ_OPT_MASK);
+	return armada_375_tclk_frequencies[tclk_freq_select];
+}
+
+
+static const u32 armada_375_cpu_frequencies[] __initconst = {
+	0, 0, 0, 0, 0, 0,
+	400000000,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	600000000,
+	0, 0, 0, 0, 0,
+	800000000,
+	0, 0, 0,
+	1000000000,
+};
+
+static u32 __init armada_375_get_cpu_freq(void __iomem *sar)
+{
+	u8 cpu_freq_select;
+
+	cpu_freq_select = ((readl(sar) >> SAR1_A375_CPU_DDR_L2_FREQ_OPT) &
+			   SAR1_A375_CPU_DDR_L2_FREQ_OPT_MASK);
+	if (cpu_freq_select >= ARRAY_SIZE(armada_375_cpu_frequencies)) {
+		pr_err("Selected CPU frequency (%d) unsupported\n",
+			cpu_freq_select);
+		return 0;
+	} else
+		return armada_375_cpu_frequencies[cpu_freq_select];
+}
+
+enum { A375_CPU_TO_DDR, A375_CPU_TO_L2 };
+
+static const struct coreclk_ratio armada_375_coreclk_ratios[] __initconst = {
+	{ .id = A375_CPU_TO_L2,	 .name = "l2clk" },
+	{ .id = A375_CPU_TO_DDR, .name = "ddrclk" },
+};
+
+static const int armada_375_cpu_l2_ratios[32][2] __initconst = {
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {1, 2}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {1, 2},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {1, 2}, {0, 1}, {0, 1},
+	{0, 1}, {1, 2}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+};
+
+static const int armada_375_cpu_ddr_ratios[32][2] __initconst = {
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {1, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {2, 3},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {2, 3}, {0, 1}, {0, 1},
+	{0, 1}, {1, 2}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+};
+
+static void __init armada_375_get_clk_ratio(
+	void __iomem *sar, int id, int *mult, int *div)
+{
+	u32 opt = ((readl(sar) >> SAR1_A375_CPU_DDR_L2_FREQ_OPT) &
+		SAR1_A375_CPU_DDR_L2_FREQ_OPT_MASK);
+
+	switch (id) {
+	case A375_CPU_TO_L2:
+		*mult = armada_375_cpu_l2_ratios[opt][0];
+		*div = armada_375_cpu_l2_ratios[opt][1];
+		break;
+	case A375_CPU_TO_DDR:
+		*mult = armada_375_cpu_ddr_ratios[opt][0];
+		*div = armada_375_cpu_ddr_ratios[opt][1];
+		break;
+	}
+}
+
+static const struct coreclk_soc_desc armada_375_coreclks = {
+	.get_tclk_freq = armada_375_get_tclk_freq,
+	.get_cpu_freq = armada_375_get_cpu_freq,
+	.get_clk_ratio = armada_375_get_clk_ratio,
+	.ratios = armada_375_coreclk_ratios,
+	.num_ratios = ARRAY_SIZE(armada_375_coreclk_ratios),
+};
+
+static void __init armada_375_coreclk_init(struct device_node *np)
+{
+	mvebu_coreclk_setup(np, &armada_375_coreclks);
+}
+CLK_OF_DECLARE(armada_375_core_clk, "marvell,armada-375-core-clock",
+	       armada_375_coreclk_init);
+
+/*
+ * Clock Gating Control
+ */
+static const struct clk_gating_soc_desc armada_375_gating_desc[] __initconst = {
+	{ "mu", NULL, 2 },
+	{ "pp", NULL, 3 },
+	{ "ptp", NULL, 4 },
+	{ "pex0", NULL, 5 },
+	{ "pex1", NULL, 6 },
+	{ "audio", NULL, 8 },
+	{ "nd_clk", "nand", 11 },
+	{ "sata0_link", "sata0_core", 14 },
+	{ "sata0_core", NULL, 15 },
+	{ "usb3", NULL, 16 },
+	{ "sdio", NULL, 17 },
+	{ "usb", NULL, 18 },
+	{ "gop", NULL, 19 },
+	{ "sata1_link", "sata1_core", 20 },
+	{ "sata1_core", NULL, 21 },
+	{ "xor0", NULL, 22 },
+	{ "xor1", NULL, 23 },
+	{ "copro", NULL, 24 },
+	{ "tdm", NULL, 25 },
+	{ "crypto0_enc", NULL, 28 },
+	{ "crypto0_core", NULL, 29 },
+	{ "crypto1_enc", NULL, 30 },
+	{ "crypto1_core", NULL, 31 },
+	{ }
+};
+
+static void __init armada_375_clk_gating_init(struct device_node *np)
+{
+	mvebu_clk_gating_setup(np, armada_375_gating_desc);
+}
+CLK_OF_DECLARE(armada_375_clk_gating, "marvell,armada-375-gating-clock",
+	       armada_375_clk_gating_init);
diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c
new file mode 100644
index 0000000..8bccf4e
--- /dev/null
+++ b/drivers/clk/mvebu/armada-38x.c
@@ -0,0 +1,167 @@
+/*
+ * Marvell Armada 380/385 SoC clocks
+ *
+ * Copyright (C) 2014 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Andrew Lunn <andrew@lunn.ch>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include "common.h"
+
+/*
+ * SAR[14:10] : Ratios between PCLK0, NBCLK, HCLK and DRAM clocks
+ *
+ * SAR[15]    : TCLK frequency
+ *		 0 = 250 MHz
+ *		 1 = 200 MHz
+ */
+
+#define SAR_A380_TCLK_FREQ_OPT		  15
+#define SAR_A380_TCLK_FREQ_OPT_MASK	  0x1
+#define SAR_A380_CPU_DDR_L2_FREQ_OPT	  10
+#define SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK 0x1F
+
+static const u32 armada_38x_tclk_frequencies[] __initconst = {
+	250000000,
+	200000000,
+};
+
+static u32 __init armada_38x_get_tclk_freq(void __iomem *sar)
+{
+	u8 tclk_freq_select;
+
+	tclk_freq_select = ((readl(sar) >> SAR_A380_TCLK_FREQ_OPT) &
+			    SAR_A380_TCLK_FREQ_OPT_MASK);
+	return armada_38x_tclk_frequencies[tclk_freq_select];
+}
+
+static const u32 armada_38x_cpu_frequencies[] __initconst = {
+	0, 0, 0, 0,
+	1066 * 1000 * 1000, 0, 0, 0,
+	1332 * 1000 * 1000, 0, 0, 0,
+	1600 * 1000 * 1000,
+};
+
+static u32 __init armada_38x_get_cpu_freq(void __iomem *sar)
+{
+	u8 cpu_freq_select;
+
+	cpu_freq_select = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) &
+			   SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK);
+	if (cpu_freq_select >= ARRAY_SIZE(armada_38x_cpu_frequencies)) {
+		pr_err("Selected CPU frequency (%d) unsupported\n",
+			cpu_freq_select);
+		return 0;
+	}
+
+	return armada_38x_cpu_frequencies[cpu_freq_select];
+}
+
+enum { A380_CPU_TO_DDR, A380_CPU_TO_L2 };
+
+static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = {
+	{ .id = A380_CPU_TO_L2,	 .name = "l2clk" },
+	{ .id = A380_CPU_TO_DDR, .name = "ddrclk" },
+};
+
+static const int armada_38x_cpu_l2_ratios[32][2] __initconst = {
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{1, 2}, {0, 1}, {0, 1}, {0, 1},
+	{1, 2}, {0, 1}, {0, 1}, {0, 1},
+	{1, 2}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+};
+
+static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = {
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{1, 2}, {0, 1}, {0, 1}, {0, 1},
+	{1, 2}, {0, 1}, {0, 1}, {0, 1},
+	{1, 2}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+};
+
+static void __init armada_38x_get_clk_ratio(
+	void __iomem *sar, int id, int *mult, int *div)
+{
+	u32 opt = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) &
+		SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK);
+
+	switch (id) {
+	case A380_CPU_TO_L2:
+		*mult = armada_38x_cpu_l2_ratios[opt][0];
+		*div = armada_38x_cpu_l2_ratios[opt][1];
+		break;
+	case A380_CPU_TO_DDR:
+		*mult = armada_38x_cpu_ddr_ratios[opt][0];
+		*div = armada_38x_cpu_ddr_ratios[opt][1];
+		break;
+	}
+}
+
+static const struct coreclk_soc_desc armada_38x_coreclks = {
+	.get_tclk_freq = armada_38x_get_tclk_freq,
+	.get_cpu_freq = armada_38x_get_cpu_freq,
+	.get_clk_ratio = armada_38x_get_clk_ratio,
+	.ratios = armada_38x_coreclk_ratios,
+	.num_ratios = ARRAY_SIZE(armada_38x_coreclk_ratios),
+};
+
+static void __init armada_38x_coreclk_init(struct device_node *np)
+{
+	mvebu_coreclk_setup(np, &armada_38x_coreclks);
+}
+CLK_OF_DECLARE(armada_38x_core_clk, "marvell,armada-380-core-clock",
+	       armada_38x_coreclk_init);
+
+/*
+ * Clock Gating Control
+ */
+static const struct clk_gating_soc_desc armada_38x_gating_desc[] __initconst = {
+	{ "audio", NULL, 0 },
+	{ "ge2", NULL, 2 },
+	{ "ge1", NULL, 3 },
+	{ "ge0", NULL, 4 },
+	{ "pex1", NULL, 5 },
+	{ "pex2", NULL, 6 },
+	{ "pex3", NULL, 7 },
+	{ "pex0", NULL, 8 },
+	{ "usb3h0", NULL, 9 },
+	{ "usb3h1", NULL, 10 },
+	{ "usb3d", NULL, 11 },
+	{ "bm", NULL, 13 },
+	{ "crypto0z", NULL, 14 },
+	{ "sata0", NULL, 15 },
+	{ "crypto1z", NULL, 16 },
+	{ "sdio", NULL, 17 },
+	{ "usb2", NULL, 18 },
+	{ "crypto1", NULL, 21 },
+	{ "xor0", NULL, 22 },
+	{ "crypto0", NULL, 23 },
+	{ "tdm", NULL, 25 },
+	{ "xor1", NULL, 28 },
+	{ "sata1", NULL, 30 },
+	{ }
+};
+
+static void __init armada_38x_clk_gating_init(struct device_node *np)
+{
+	mvebu_clk_gating_setup(np, armada_38x_gating_desc);
+}
+CLK_OF_DECLARE(armada_38x_clk_gating, "marvell,armada-380-gating-clock",
+	       armada_38x_clk_gating_init);
diff --git a/drivers/clk/mvebu/clk-corediv.c b/drivers/clk/mvebu/clk-corediv.c
index 7162615..d1e5863 100644
--- a/drivers/clk/mvebu/clk-corediv.c
+++ b/drivers/clk/mvebu/clk-corediv.c
@@ -18,26 +18,56 @@
 #include "common.h"
 
 #define CORE_CLK_DIV_RATIO_MASK		0xff
-#define CORE_CLK_DIV_RATIO_RELOAD	BIT(8)
-#define CORE_CLK_DIV_ENABLE_OFFSET	24
-#define CORE_CLK_DIV_RATIO_OFFSET	0x8
 
+/*
+ * This structure describes the hardware details (bit offset and mask)
+ * to configure one particular core divider clock. Those hardware
+ * details may differ from one SoC to another. This structure is
+ * therefore typically instantiated statically to describe the
+ * hardware details.
+ */
 struct clk_corediv_desc {
 	unsigned int mask;
 	unsigned int offset;
 	unsigned int fieldbit;
 };
 
+/*
+ * This structure describes the hardware details to configure the core
+ * divider clocks on a given SoC. Amongst others, it points to the
+ * array of core divider clock descriptors for this SoC, as well as
+ * the corresponding operations to manipulate them.
+ */
+struct clk_corediv_soc_desc {
+	const struct clk_corediv_desc *descs;
+	unsigned int ndescs;
+	const struct clk_ops ops;
+	u32 ratio_reload;
+	u32 enable_bit_offset;
+	u32 ratio_offset;
+};
+
+/*
+ * This structure represents one core divider clock for the clock
+ * framework, and is dynamically allocated for each core divider clock
+ * existing in the current SoC.
+ */
 struct clk_corediv {
 	struct clk_hw hw;
 	void __iomem *reg;
-	struct clk_corediv_desc desc;
+	const struct clk_corediv_desc *desc;
+	const struct clk_corediv_soc_desc *soc_desc;
 	spinlock_t lock;
 };
 
 static struct clk_onecell_data clk_data;
 
-static const struct clk_corediv_desc mvebu_corediv_desc[] __initconst = {
+/*
+ * Description of the core divider clocks available. For now, we
+ * support only NAND, and it is available at the same register
+ * locations regardless of the SoC.
+ */
+static const struct clk_corediv_desc mvebu_corediv_desc[] = {
 	{ .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */
 };
 
@@ -46,8 +76,9 @@
 static int clk_corediv_is_enabled(struct clk_hw *hwclk)
 {
 	struct clk_corediv *corediv = to_corediv_clk(hwclk);
-	struct clk_corediv_desc *desc = &corediv->desc;
-	u32 enable_mask = BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET;
+	const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
+	const struct clk_corediv_desc *desc = corediv->desc;
+	u32 enable_mask = BIT(desc->fieldbit) << soc_desc->enable_bit_offset;
 
 	return !!(readl(corediv->reg) & enable_mask);
 }
@@ -55,14 +86,15 @@
 static int clk_corediv_enable(struct clk_hw *hwclk)
 {
 	struct clk_corediv *corediv = to_corediv_clk(hwclk);
-	struct clk_corediv_desc *desc = &corediv->desc;
+	const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
+	const struct clk_corediv_desc *desc = corediv->desc;
 	unsigned long flags = 0;
 	u32 reg;
 
 	spin_lock_irqsave(&corediv->lock, flags);
 
 	reg = readl(corediv->reg);
-	reg |= (BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET);
+	reg |= (BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
 	writel(reg, corediv->reg);
 
 	spin_unlock_irqrestore(&corediv->lock, flags);
@@ -73,14 +105,15 @@
 static void clk_corediv_disable(struct clk_hw *hwclk)
 {
 	struct clk_corediv *corediv = to_corediv_clk(hwclk);
-	struct clk_corediv_desc *desc = &corediv->desc;
+	const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
+	const struct clk_corediv_desc *desc = corediv->desc;
 	unsigned long flags = 0;
 	u32 reg;
 
 	spin_lock_irqsave(&corediv->lock, flags);
 
 	reg = readl(corediv->reg);
-	reg &= ~(BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET);
+	reg &= ~(BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
 	writel(reg, corediv->reg);
 
 	spin_unlock_irqrestore(&corediv->lock, flags);
@@ -90,10 +123,11 @@
 					 unsigned long parent_rate)
 {
 	struct clk_corediv *corediv = to_corediv_clk(hwclk);
-	struct clk_corediv_desc *desc = &corediv->desc;
+	const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
+	const struct clk_corediv_desc *desc = corediv->desc;
 	u32 reg, div;
 
-	reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET);
+	reg = readl(corediv->reg + soc_desc->ratio_offset);
 	div = (reg >> desc->offset) & desc->mask;
 	return parent_rate / div;
 }
@@ -117,7 +151,8 @@
 			    unsigned long parent_rate)
 {
 	struct clk_corediv *corediv = to_corediv_clk(hwclk);
-	struct clk_corediv_desc *desc = &corediv->desc;
+	const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
+	const struct clk_corediv_desc *desc = corediv->desc;
 	unsigned long flags = 0;
 	u32 reg, div;
 
@@ -126,17 +161,17 @@
 	spin_lock_irqsave(&corediv->lock, flags);
 
 	/* Write new divider to the divider ratio register */
-	reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET);
+	reg = readl(corediv->reg + soc_desc->ratio_offset);
 	reg &= ~(desc->mask << desc->offset);
 	reg |= (div & desc->mask) << desc->offset;
-	writel(reg, corediv->reg + CORE_CLK_DIV_RATIO_OFFSET);
+	writel(reg, corediv->reg + soc_desc->ratio_offset);
 
 	/* Set reload-force for this clock */
 	reg = readl(corediv->reg) | BIT(desc->fieldbit);
 	writel(reg, corediv->reg);
 
 	/* Now trigger the clock update */
-	reg = readl(corediv->reg) | CORE_CLK_DIV_RATIO_RELOAD;
+	reg = readl(corediv->reg) | soc_desc->ratio_reload;
 	writel(reg, corediv->reg);
 
 	/*
@@ -144,7 +179,7 @@
 	 * ratios request and the reload request.
 	 */
 	udelay(1000);
-	reg &= ~(CORE_CLK_DIV_RATIO_MASK | CORE_CLK_DIV_RATIO_RELOAD);
+	reg &= ~(CORE_CLK_DIV_RATIO_MASK | soc_desc->ratio_reload);
 	writel(reg, corediv->reg);
 	udelay(1000);
 
@@ -153,16 +188,53 @@
 	return 0;
 }
 
-static const struct clk_ops corediv_ops = {
-	.enable = clk_corediv_enable,
-	.disable = clk_corediv_disable,
-	.is_enabled = clk_corediv_is_enabled,
-	.recalc_rate = clk_corediv_recalc_rate,
-	.round_rate = clk_corediv_round_rate,
-	.set_rate = clk_corediv_set_rate,
+static const struct clk_corediv_soc_desc armada370_corediv_soc = {
+	.descs = mvebu_corediv_desc,
+	.ndescs = ARRAY_SIZE(mvebu_corediv_desc),
+	.ops = {
+		.enable = clk_corediv_enable,
+		.disable = clk_corediv_disable,
+		.is_enabled = clk_corediv_is_enabled,
+		.recalc_rate = clk_corediv_recalc_rate,
+		.round_rate = clk_corediv_round_rate,
+		.set_rate = clk_corediv_set_rate,
+	},
+	.ratio_reload = BIT(8),
+	.enable_bit_offset = 24,
+	.ratio_offset = 0x8,
 };
 
-static void __init mvebu_corediv_clk_init(struct device_node *node)
+static const struct clk_corediv_soc_desc armada380_corediv_soc = {
+	.descs = mvebu_corediv_desc,
+	.ndescs = ARRAY_SIZE(mvebu_corediv_desc),
+	.ops = {
+		.enable = clk_corediv_enable,
+		.disable = clk_corediv_disable,
+		.is_enabled = clk_corediv_is_enabled,
+		.recalc_rate = clk_corediv_recalc_rate,
+		.round_rate = clk_corediv_round_rate,
+		.set_rate = clk_corediv_set_rate,
+	},
+	.ratio_reload = BIT(8),
+	.enable_bit_offset = 16,
+	.ratio_offset = 0x4,
+};
+
+static const struct clk_corediv_soc_desc armada375_corediv_soc = {
+	.descs = mvebu_corediv_desc,
+	.ndescs = ARRAY_SIZE(mvebu_corediv_desc),
+	.ops = {
+		.recalc_rate = clk_corediv_recalc_rate,
+		.round_rate = clk_corediv_round_rate,
+		.set_rate = clk_corediv_set_rate,
+	},
+	.ratio_reload = BIT(8),
+	.ratio_offset = 0x4,
+};
+
+static void __init
+mvebu_corediv_clk_init(struct device_node *node,
+		       const struct clk_corediv_soc_desc *soc_desc)
 {
 	struct clk_init_data init;
 	struct clk_corediv *corediv;
@@ -178,7 +250,7 @@
 
 	parent_name = of_clk_get_parent_name(node, 0);
 
-	clk_data.clk_num = ARRAY_SIZE(mvebu_corediv_desc);
+	clk_data.clk_num = soc_desc->ndescs;
 
 	/* clks holds the clock array */
 	clks = kcalloc(clk_data.clk_num, sizeof(struct clk *),
@@ -199,10 +271,11 @@
 		init.num_parents = 1;
 		init.parent_names = &parent_name;
 		init.name = clk_name;
-		init.ops = &corediv_ops;
+		init.ops = &soc_desc->ops;
 		init.flags = 0;
 
-		corediv[i].desc = mvebu_corediv_desc[i];
+		corediv[i].soc_desc = soc_desc;
+		corediv[i].desc = soc_desc->descs + i;
 		corediv[i].reg = base;
 		corediv[i].hw.init = &init;
 
@@ -219,5 +292,24 @@
 err_unmap:
 	iounmap(base);
 }
-CLK_OF_DECLARE(mvebu_corediv_clk, "marvell,armada-370-corediv-clock",
-	       mvebu_corediv_clk_init);
+
+static void __init armada370_corediv_clk_init(struct device_node *node)
+{
+	return mvebu_corediv_clk_init(node, &armada370_corediv_soc);
+}
+CLK_OF_DECLARE(armada370_corediv_clk, "marvell,armada-370-corediv-clock",
+	       armada370_corediv_clk_init);
+
+static void __init armada375_corediv_clk_init(struct device_node *node)
+{
+	return mvebu_corediv_clk_init(node, &armada375_corediv_soc);
+}
+CLK_OF_DECLARE(armada375_corediv_clk, "marvell,armada-375-corediv-clock",
+	       armada375_corediv_clk_init);
+
+static void __init armada380_corediv_clk_init(struct device_node *node)
+{
+	return mvebu_corediv_clk_init(node, &armada380_corediv_soc);
+}
+CLK_OF_DECLARE(armada380_corediv_clk, "marvell,armada-380-corediv-clock",
+	       armada380_corediv_clk_init);
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index 9ecef14..5404cb9 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_ARCH_EMEV2)		+= clk-emev2.o
+obj-$(CONFIG_ARCH_R7S72100)		+= clk-rz.o
 obj-$(CONFIG_ARCH_R8A7790)		+= clk-rcar-gen2.o
 obj-$(CONFIG_ARCH_R8A7791)		+= clk-rcar-gen2.o
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)	+= clk-div6.o
diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c
index aac4756..f065f69 100644
--- a/drivers/clk/shmobile/clk-div6.c
+++ b/drivers/clk/shmobile/clk-div6.c
@@ -23,7 +23,7 @@
 #define CPG_DIV6_DIV_MASK	0x3f
 
 /**
- * struct div6_clock - MSTP gating clock
+ * struct div6_clock - CPG 6 bit divider clock
  * @hw: handle between common and hardware-specific interfaces
  * @reg: IO-remapped register
  * @div: divisor value (1-64)
diff --git a/drivers/clk/shmobile/clk-mstp.c b/drivers/clk/shmobile/clk-mstp.c
index 42d5912..2e5810c 100644
--- a/drivers/clk/shmobile/clk-mstp.c
+++ b/drivers/clk/shmobile/clk-mstp.c
@@ -137,7 +137,7 @@
 
 	init.name = name;
 	init.ops = &cpg_mstp_clock_ops;
-	init.flags = CLK_IS_BASIC;
+	init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
 	init.parent_names = &parent_name;
 	init.num_parents = 1;
 
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c
index 99c27b1..dff7f79 100644
--- a/drivers/clk/shmobile/clk-rcar-gen2.c
+++ b/drivers/clk/shmobile/clk-rcar-gen2.c
@@ -242,22 +242,22 @@
 		parent_name = "main";
 		mult = config->pll3_mult;
 	} else if (!strcmp(name, "lb")) {
-		parent_name = "pll1_div2";
+		parent_name = "pll1";
 		div = cpg_mode & BIT(18) ? 36 : 24;
 	} else if (!strcmp(name, "qspi")) {
 		parent_name = "pll1_div2";
 		div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2)
 		    ? 8 : 10;
 	} else if (!strcmp(name, "sdh")) {
-		parent_name = "pll1_div2";
+		parent_name = "pll1";
 		table = cpg_sdh_div_table;
 		shift = 8;
 	} else if (!strcmp(name, "sd0")) {
-		parent_name = "pll1_div2";
+		parent_name = "pll1";
 		table = cpg_sd01_div_table;
 		shift = 4;
 	} else if (!strcmp(name, "sd1")) {
-		parent_name = "pll1_div2";
+		parent_name = "pll1";
 		table = cpg_sd01_div_table;
 		shift = 0;
 	} else if (!strcmp(name, "z")) {
diff --git a/drivers/clk/shmobile/clk-rz.c b/drivers/clk/shmobile/clk-rz.c
new file mode 100644
index 0000000..7e68e86
--- /dev/null
+++ b/drivers/clk/shmobile/clk-rz.c
@@ -0,0 +1,103 @@
+/*
+ * rz Core CPG Clocks
+ *
+ * Copyright (C) 2013 Ideas On Board SPRL
+ * Copyright (C) 2014 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
+ *
+ * This program 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; version 2 of the License.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+struct rz_cpg {
+	struct clk_onecell_data data;
+	void __iomem *reg;
+};
+
+#define CPG_FRQCR	0x10
+#define CPG_FRQCR2	0x14
+
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
+
+static struct clk * __init
+rz_cpg_register_clock(struct device_node *np, struct rz_cpg *cpg, const char *name)
+{
+	u32 val;
+	unsigned mult;
+	static const unsigned frqcr_tab[4] = { 3, 2, 0, 1 };
+
+	if (strcmp(name, "pll") == 0) {
+		/* FIXME: cpg_mode should be read from GPIO. But no GPIO support yet */
+		unsigned cpg_mode = 0; /* hardcoded to EXTAL for now */
+		const char *parent_name = of_clk_get_parent_name(np, cpg_mode);
+
+		mult = cpg_mode ? (32 / 4) : 30;
+
+		return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, 1);
+	}
+
+	/* If mapping regs failed, skip non-pll clocks. System will boot anyhow */
+	if (!cpg->reg)
+		return ERR_PTR(-ENXIO);
+
+	/* FIXME:"i" and "g" are variable clocks with non-integer dividers (e.g. 2/3)
+	 * and the constraint that always g <= i. To get the rz platform started,
+	 * let them run at fixed current speed and implement the details later.
+	 */
+	if (strcmp(name, "i") == 0)
+		val = (clk_readl(cpg->reg + CPG_FRQCR) >> 8) & 3;
+	else if (strcmp(name, "g") == 0)
+		val = clk_readl(cpg->reg + CPG_FRQCR2) & 3;
+	else
+		return ERR_PTR(-EINVAL);
+
+	mult = frqcr_tab[val];
+	return clk_register_fixed_factor(NULL, name, "pll", 0, mult, 3);
+}
+
+static void __init rz_cpg_clocks_init(struct device_node *np)
+{
+	struct rz_cpg *cpg;
+	struct clk **clks;
+	unsigned i;
+	int num_clks;
+
+	num_clks = of_property_count_strings(np, "clock-output-names");
+	if (WARN(num_clks <= 0, "can't count CPG clocks\n"))
+		return;
+
+	cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+	clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
+	BUG_ON(!cpg || !clks);
+
+	cpg->data.clks = clks;
+	cpg->data.clk_num = num_clks;
+
+	cpg->reg = of_iomap(np, 0);
+
+	for (i = 0; i < num_clks; ++i) {
+		const char *name;
+		struct clk *clk;
+
+		of_property_read_string_index(np, "clock-output-names", i, &name);
+
+		clk = rz_cpg_register_clock(np, cpg, name);
+		if (IS_ERR(clk))
+			pr_err("%s: failed to register %s %s clock (%ld)\n",
+			       __func__, np->name, name, PTR_ERR(clk));
+		else
+			cpg->data.clks[i] = clk;
+	}
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+}
+CLK_OF_DECLARE(rz_cpg_clks, "renesas,rz-cpg-clocks", rz_cpg_clocks_init);
diff --git a/drivers/clk/sirf/clk-atlas6.c b/drivers/clk/sirf/clk-atlas6.c
index f9f4a15..d63b76c 100644
--- a/drivers/clk/sirf/clk-atlas6.c
+++ b/drivers/clk/sirf/clk-atlas6.c
@@ -1,7 +1,8 @@
 /*
  * Clock tree for CSR SiRFatlasVI
  *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
  *
  * Licensed under GPLv2 or later.
  */
diff --git a/drivers/clk/sirf/clk-common.c b/drivers/clk/sirf/clk-common.c
index 7dde6a8..37af51c 100644
--- a/drivers/clk/sirf/clk-common.c
+++ b/drivers/clk/sirf/clk-common.c
@@ -1,7 +1,8 @@
 /*
  * common clks module for all SiRF SoCs
  *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
  *
  * Licensed under GPLv2 or later.
  */
diff --git a/drivers/clk/sirf/clk-prima2.c b/drivers/clk/sirf/clk-prima2.c
index 7adc5c7..6968e2e 100644
--- a/drivers/clk/sirf/clk-prima2.c
+++ b/drivers/clk/sirf/clk-prima2.c
@@ -1,7 +1,8 @@
 /*
  * Clock tree for CSR SiRFprimaII
  *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
  *
  * Licensed under GPLv2 or later.
  */
diff --git a/drivers/clk/socfpga/Makefile b/drivers/clk/socfpga/Makefile
index 0303c0b..7e2d15a 100644
--- a/drivers/clk/socfpga/Makefile
+++ b/drivers/clk/socfpga/Makefile
@@ -1 +1,4 @@
 obj-y += clk.o
+obj-y += clk-gate.o
+obj-y += clk-pll.o
+obj-y += clk-periph.o
diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c
new file mode 100644
index 0000000..501d513
--- /dev/null
+++ b/drivers/clk/socfpga/clk-gate.c
@@ -0,0 +1,263 @@
+/*
+ *  Copyright 2011-2012 Calxeda, Inc.
+ *  Copyright (C) 2012-2013 Altera Corporation <www.altera.com>
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Based from clk-highbank.c
+ *
+ */
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#include "clk.h"
+
+#define SOCFPGA_L4_MP_CLK		"l4_mp_clk"
+#define SOCFPGA_L4_SP_CLK		"l4_sp_clk"
+#define SOCFPGA_NAND_CLK		"nand_clk"
+#define SOCFPGA_NAND_X_CLK		"nand_x_clk"
+#define SOCFPGA_MMC_CLK			"sdmmc_clk"
+#define SOCFPGA_GPIO_DB_CLK_OFFSET	0xA8
+
+#define div_mask(width)	((1 << (width)) - 1)
+#define streq(a, b) (strcmp((a), (b)) == 0)
+
+#define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw)
+
+/* SDMMC Group for System Manager defines */
+#define SYSMGR_SDMMCGRP_CTRL_OFFSET    0x108
+#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
+	((((smplsel) & 0x7) << 3) | (((drvsel) & 0x7) << 0))
+
+static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
+{
+	u32 l4_src;
+	u32 perpll_src;
+
+	if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
+		l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
+		return l4_src &= 0x1;
+	}
+	if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
+		l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
+		return !!(l4_src & 2);
+	}
+
+	perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
+	if (streq(hwclk->init->name, SOCFPGA_MMC_CLK))
+		return perpll_src &= 0x3;
+	if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
+			streq(hwclk->init->name, SOCFPGA_NAND_X_CLK))
+			return (perpll_src >> 2) & 3;
+
+	/* QSPI clock */
+	return (perpll_src >> 4) & 3;
+
+}
+
+static int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent)
+{
+	u32 src_reg;
+
+	if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
+		src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
+		src_reg &= ~0x1;
+		src_reg |= parent;
+		writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
+	} else if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
+		src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
+		src_reg &= ~0x2;
+		src_reg |= (parent << 1);
+		writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
+	} else {
+		src_reg = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
+		if (streq(hwclk->init->name, SOCFPGA_MMC_CLK)) {
+			src_reg &= ~0x3;
+			src_reg |= parent;
+		} else if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
+			streq(hwclk->init->name, SOCFPGA_NAND_X_CLK)) {
+			src_reg &= ~0xC;
+			src_reg |= (parent << 2);
+		} else {/* QSPI clock */
+			src_reg &= ~0x30;
+			src_reg |= (parent << 4);
+		}
+		writel(src_reg, clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
+	}
+
+	return 0;
+}
+
+static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
+	u32 div = 1, val;
+
+	if (socfpgaclk->fixed_div)
+		div = socfpgaclk->fixed_div;
+	else if (socfpgaclk->div_reg) {
+		val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
+		val &= div_mask(socfpgaclk->width);
+		/* Check for GPIO_DB_CLK by its offset */
+		if ((int) socfpgaclk->div_reg & SOCFPGA_GPIO_DB_CLK_OFFSET)
+			div = val + 1;
+		else
+			div = (1 << val);
+	}
+
+	return parent_rate / div;
+}
+
+static int socfpga_clk_prepare(struct clk_hw *hwclk)
+{
+	struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
+	struct regmap *sys_mgr_base_addr;
+	int i;
+	u32 hs_timing;
+	u32 clk_phase[2];
+
+	if (socfpgaclk->clk_phase[0] || socfpgaclk->clk_phase[1]) {
+		sys_mgr_base_addr = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
+		if (IS_ERR(sys_mgr_base_addr)) {
+			pr_err("%s: failed to find altr,sys-mgr regmap!\n", __func__);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < 2; i++) {
+			switch (socfpgaclk->clk_phase[i]) {
+			case 0:
+				clk_phase[i] = 0;
+				break;
+			case 45:
+				clk_phase[i] = 1;
+				break;
+			case 90:
+				clk_phase[i] = 2;
+				break;
+			case 135:
+				clk_phase[i] = 3;
+				break;
+			case 180:
+				clk_phase[i] = 4;
+				break;
+			case 225:
+				clk_phase[i] = 5;
+				break;
+			case 270:
+				clk_phase[i] = 6;
+				break;
+			case 315:
+				clk_phase[i] = 7;
+				break;
+			default:
+				clk_phase[i] = 0;
+				break;
+			}
+		}
+		hs_timing = SYSMGR_SDMMC_CTRL_SET(clk_phase[0], clk_phase[1]);
+		regmap_write(sys_mgr_base_addr, SYSMGR_SDMMCGRP_CTRL_OFFSET,
+			hs_timing);
+	}
+	return 0;
+}
+
+static struct clk_ops gateclk_ops = {
+	.prepare = socfpga_clk_prepare,
+	.recalc_rate = socfpga_clk_recalc_rate,
+	.get_parent = socfpga_clk_get_parent,
+	.set_parent = socfpga_clk_set_parent,
+};
+
+static void __init __socfpga_gate_init(struct device_node *node,
+	const struct clk_ops *ops)
+{
+	u32 clk_gate[2];
+	u32 div_reg[3];
+	u32 clk_phase[2];
+	u32 fixed_div;
+	struct clk *clk;
+	struct socfpga_gate_clk *socfpga_clk;
+	const char *clk_name = node->name;
+	const char *parent_name[SOCFPGA_MAX_PARENTS];
+	struct clk_init_data init;
+	int rc;
+	int i = 0;
+
+	socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
+	if (WARN_ON(!socfpga_clk))
+		return;
+
+	rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
+	if (rc)
+		clk_gate[0] = 0;
+
+	if (clk_gate[0]) {
+		socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0];
+		socfpga_clk->hw.bit_idx = clk_gate[1];
+
+		gateclk_ops.enable = clk_gate_ops.enable;
+		gateclk_ops.disable = clk_gate_ops.disable;
+	}
+
+	rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
+	if (rc)
+		socfpga_clk->fixed_div = 0;
+	else
+		socfpga_clk->fixed_div = fixed_div;
+
+	rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
+	if (!rc) {
+		socfpga_clk->div_reg = clk_mgr_base_addr + div_reg[0];
+		socfpga_clk->shift = div_reg[1];
+		socfpga_clk->width = div_reg[2];
+	} else {
+		socfpga_clk->div_reg = 0;
+	}
+
+	rc = of_property_read_u32_array(node, "clk-phase", clk_phase, 2);
+	if (!rc) {
+		socfpga_clk->clk_phase[0] = clk_phase[0];
+		socfpga_clk->clk_phase[1] = clk_phase[1];
+	}
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	init.name = clk_name;
+	init.ops = ops;
+	init.flags = 0;
+	while (i < SOCFPGA_MAX_PARENTS && (parent_name[i] =
+			of_clk_get_parent_name(node, i)) != NULL)
+		i++;
+
+	init.parent_names = parent_name;
+	init.num_parents = i;
+	socfpga_clk->hw.hw.init = &init;
+
+	clk = clk_register(NULL, &socfpga_clk->hw.hw);
+	if (WARN_ON(IS_ERR(clk))) {
+		kfree(socfpga_clk);
+		return;
+	}
+	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	if (WARN_ON(rc))
+		return;
+}
+
+void __init socfpga_gate_init(struct device_node *node)
+{
+	__socfpga_gate_init(node, &gateclk_ops);
+}
diff --git a/drivers/clk/socfpga/clk-periph.c b/drivers/clk/socfpga/clk-periph.c
new file mode 100644
index 0000000..81623a3
--- /dev/null
+++ b/drivers/clk/socfpga/clk-periph.c
@@ -0,0 +1,94 @@
+/*
+ *  Copyright 2011-2012 Calxeda, Inc.
+ *  Copyright (C) 2012-2013 Altera Corporation <www.altera.com>
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Based from clk-highbank.c
+ *
+ */
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include "clk.h"
+
+#define to_socfpga_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw.hw)
+
+static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
+					     unsigned long parent_rate)
+{
+	struct socfpga_periph_clk *socfpgaclk = to_socfpga_periph_clk(hwclk);
+	u32 div;
+
+	if (socfpgaclk->fixed_div)
+		div = socfpgaclk->fixed_div;
+	else
+		div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1);
+
+	return parent_rate / div;
+}
+
+static const struct clk_ops periclk_ops = {
+	.recalc_rate = clk_periclk_recalc_rate,
+};
+
+static __init void __socfpga_periph_init(struct device_node *node,
+	const struct clk_ops *ops)
+{
+	u32 reg;
+	struct clk *clk;
+	struct socfpga_periph_clk *periph_clk;
+	const char *clk_name = node->name;
+	const char *parent_name;
+	struct clk_init_data init;
+	int rc;
+	u32 fixed_div;
+
+	of_property_read_u32(node, "reg", &reg);
+
+	periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
+	if (WARN_ON(!periph_clk))
+		return;
+
+	periph_clk->hw.reg = clk_mgr_base_addr + reg;
+
+	rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
+	if (rc)
+		periph_clk->fixed_div = 0;
+	else
+		periph_clk->fixed_div = fixed_div;
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	init.name = clk_name;
+	init.ops = ops;
+	init.flags = 0;
+	parent_name = of_clk_get_parent_name(node, 0);
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	periph_clk->hw.hw.init = &init;
+
+	clk = clk_register(NULL, &periph_clk->hw.hw);
+	if (WARN_ON(IS_ERR(clk))) {
+		kfree(periph_clk);
+		return;
+	}
+	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+void __init socfpga_periph_init(struct device_node *node)
+{
+	__socfpga_periph_init(node, &periclk_ops);
+}
diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c
new file mode 100644
index 0000000..88dafb5
--- /dev/null
+++ b/drivers/clk/socfpga/clk-pll.c
@@ -0,0 +1,131 @@
+/*
+ *  Copyright 2011-2012 Calxeda, Inc.
+ *  Copyright (C) 2012-2013 Altera Corporation <www.altera.com>
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Based from clk-highbank.c
+ *
+ */
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include "clk.h"
+
+/* Clock bypass bits */
+#define MAINPLL_BYPASS		(1<<0)
+#define SDRAMPLL_BYPASS		(1<<1)
+#define SDRAMPLL_SRC_BYPASS	(1<<2)
+#define PERPLL_BYPASS		(1<<3)
+#define PERPLL_SRC_BYPASS	(1<<4)
+
+#define SOCFPGA_PLL_BG_PWRDWN		0
+#define SOCFPGA_PLL_EXT_ENA		1
+#define SOCFPGA_PLL_PWR_DOWN		2
+#define SOCFPGA_PLL_DIVF_MASK		0x0000FFF8
+#define SOCFPGA_PLL_DIVF_SHIFT		3
+#define SOCFPGA_PLL_DIVQ_MASK		0x003F0000
+#define SOCFPGA_PLL_DIVQ_SHIFT		16
+
+#define CLK_MGR_PLL_CLK_SRC_SHIFT	22
+#define CLK_MGR_PLL_CLK_SRC_MASK	0x3
+
+#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
+
+static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
+					 unsigned long parent_rate)
+{
+	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
+	unsigned long divf, divq, reg;
+	unsigned long long vco_freq;
+	unsigned long bypass;
+
+	reg = readl(socfpgaclk->hw.reg);
+	bypass = readl(clk_mgr_base_addr + CLKMGR_BYPASS);
+	if (bypass & MAINPLL_BYPASS)
+		return parent_rate;
+
+	divf = (reg & SOCFPGA_PLL_DIVF_MASK) >> SOCFPGA_PLL_DIVF_SHIFT;
+	divq = (reg & SOCFPGA_PLL_DIVQ_MASK) >> SOCFPGA_PLL_DIVQ_SHIFT;
+	vco_freq = (unsigned long long)parent_rate * (divf + 1);
+	do_div(vco_freq, (1 + divq));
+	return (unsigned long)vco_freq;
+}
+
+static u8 clk_pll_get_parent(struct clk_hw *hwclk)
+{
+	u32 pll_src;
+	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
+
+	pll_src = readl(socfpgaclk->hw.reg);
+	return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &
+			CLK_MGR_PLL_CLK_SRC_MASK;
+}
+
+static struct clk_ops clk_pll_ops = {
+	.recalc_rate = clk_pll_recalc_rate,
+	.get_parent = clk_pll_get_parent,
+};
+
+static __init struct clk *__socfpga_pll_init(struct device_node *node,
+	const struct clk_ops *ops)
+{
+	u32 reg;
+	struct clk *clk;
+	struct socfpga_pll *pll_clk;
+	const char *clk_name = node->name;
+	const char *parent_name[SOCFPGA_MAX_PARENTS];
+	struct clk_init_data init;
+	int rc;
+	int i = 0;
+
+	of_property_read_u32(node, "reg", &reg);
+
+	pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
+	if (WARN_ON(!pll_clk))
+		return NULL;
+
+	pll_clk->hw.reg = clk_mgr_base_addr + reg;
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	init.name = clk_name;
+	init.ops = ops;
+	init.flags = 0;
+
+	while (i < SOCFPGA_MAX_PARENTS && (parent_name[i] =
+			of_clk_get_parent_name(node, i)) != NULL)
+		i++;
+
+	init.num_parents = i;
+	init.parent_names = parent_name;
+	pll_clk->hw.hw.init = &init;
+
+	pll_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;
+	clk_pll_ops.enable = clk_gate_ops.enable;
+	clk_pll_ops.disable = clk_gate_ops.disable;
+
+	clk = clk_register(NULL, &pll_clk->hw.hw);
+	if (WARN_ON(IS_ERR(clk))) {
+		kfree(pll_clk);
+		return NULL;
+	}
+	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	return clk;
+}
+
+void __init socfpga_pll_init(struct device_node *node)
+{
+	__socfpga_pll_init(node, &clk_pll_ops);
+}
diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c
index 5983a26..35a960a 100644
--- a/drivers/clk/socfpga/clk.c
+++ b/drivers/clk/socfpga/clk.c
@@ -22,325 +22,23 @@
 #include <linux/clk-provider.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 
-/* Clock Manager offsets */
-#define CLKMGR_CTRL	0x0
-#define CLKMGR_BYPASS	0x4
-#define CLKMGR_L4SRC	0x70
-#define CLKMGR_PERPLL_SRC	0xAC
+#include "clk.h"
 
-/* Clock bypass bits */
-#define MAINPLL_BYPASS		(1<<0)
-#define SDRAMPLL_BYPASS		(1<<1)
-#define SDRAMPLL_SRC_BYPASS	(1<<2)
-#define PERPLL_BYPASS		(1<<3)
-#define PERPLL_SRC_BYPASS	(1<<4)
+void __iomem *clk_mgr_base_addr;
 
-#define SOCFPGA_PLL_BG_PWRDWN		0
-#define SOCFPGA_PLL_EXT_ENA		1
-#define SOCFPGA_PLL_PWR_DOWN		2
-#define SOCFPGA_PLL_DIVF_MASK		0x0000FFF8
-#define SOCFPGA_PLL_DIVF_SHIFT	3
-#define SOCFPGA_PLL_DIVQ_MASK		0x003F0000
-#define SOCFPGA_PLL_DIVQ_SHIFT	16
-#define SOCFGPA_MAX_PARENTS	3
-
-#define SOCFPGA_L4_MP_CLK		"l4_mp_clk"
-#define SOCFPGA_L4_SP_CLK		"l4_sp_clk"
-#define SOCFPGA_NAND_CLK		"nand_clk"
-#define SOCFPGA_NAND_X_CLK		"nand_x_clk"
-#define SOCFPGA_MMC_CLK			"sdmmc_clk"
-#define SOCFPGA_DB_CLK			"gpio_db_clk"
-
-#define div_mask(width)	((1 << (width)) - 1)
-#define streq(a, b) (strcmp((a), (b)) == 0)
-
-extern void __iomem *clk_mgr_base_addr;
-
-struct socfpga_clk {
-	struct clk_gate hw;
-	char *parent_name;
-	char *clk_name;
-	u32 fixed_div;
-	void __iomem *div_reg;
-	u32 width;	/* only valid if div_reg != 0 */
-	u32 shift;	/* only valid if div_reg != 0 */
-};
-#define to_socfpga_clk(p) container_of(p, struct socfpga_clk, hw.hw)
-
-static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
-					 unsigned long parent_rate)
-{
-	struct socfpga_clk *socfpgaclk = to_socfpga_clk(hwclk);
-	unsigned long divf, divq, vco_freq, reg;
-	unsigned long bypass;
-
-	reg = readl(socfpgaclk->hw.reg);
-	bypass = readl(clk_mgr_base_addr + CLKMGR_BYPASS);
-	if (bypass & MAINPLL_BYPASS)
-		return parent_rate;
-
-	divf = (reg & SOCFPGA_PLL_DIVF_MASK) >> SOCFPGA_PLL_DIVF_SHIFT;
-	divq = (reg & SOCFPGA_PLL_DIVQ_MASK) >> SOCFPGA_PLL_DIVQ_SHIFT;
-	vco_freq = parent_rate * (divf + 1);
-	return vco_freq / (1 + divq);
-}
-
-
-static struct clk_ops clk_pll_ops = {
-	.recalc_rate = clk_pll_recalc_rate,
+static const struct of_device_id socfpga_child_clocks[] __initconst = {
+	{ .compatible = "altr,socfpga-pll-clock", socfpga_pll_init, },
+	{ .compatible = "altr,socfpga-perip-clk", socfpga_periph_init, },
+	{ .compatible = "altr,socfpga-gate-clk", socfpga_gate_init, },
+	{},
 };
 
-static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
-					     unsigned long parent_rate)
+static void __init socfpga_clkmgr_init(struct device_node *node)
 {
-	struct socfpga_clk *socfpgaclk = to_socfpga_clk(hwclk);
-	u32 div;
-
-	if (socfpgaclk->fixed_div)
-		div = socfpgaclk->fixed_div;
-	else
-		div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1);
-
-	return parent_rate / div;
+	clk_mgr_base_addr = of_iomap(node, 0);
+	of_clk_init(socfpga_child_clocks);
 }
+CLK_OF_DECLARE(socfpga_mgr, "altr,clk-mgr", socfpga_clkmgr_init);
 
-static const struct clk_ops periclk_ops = {
-	.recalc_rate = clk_periclk_recalc_rate,
-};
-
-static __init struct clk *socfpga_clk_init(struct device_node *node,
-	const struct clk_ops *ops)
-{
-	u32 reg;
-	struct clk *clk;
-	struct socfpga_clk *socfpga_clk;
-	const char *clk_name = node->name;
-	const char *parent_name;
-	struct clk_init_data init;
-	int rc;
-	u32 fixed_div;
-
-	of_property_read_u32(node, "reg", &reg);
-
-	socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
-	if (WARN_ON(!socfpga_clk))
-		return NULL;
-
-	socfpga_clk->hw.reg = clk_mgr_base_addr + reg;
-
-	rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
-	if (rc)
-		socfpga_clk->fixed_div = 0;
-	else
-		socfpga_clk->fixed_div = fixed_div;
-
-	of_property_read_string(node, "clock-output-names", &clk_name);
-
-	init.name = clk_name;
-	init.ops = ops;
-	init.flags = 0;
-	parent_name = of_clk_get_parent_name(node, 0);
-	init.parent_names = &parent_name;
-	init.num_parents = 1;
-
-	socfpga_clk->hw.hw.init = &init;
-
-	if (streq(clk_name, "main_pll") ||
-		streq(clk_name, "periph_pll") ||
-		streq(clk_name, "sdram_pll")) {
-		socfpga_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;
-		clk_pll_ops.enable = clk_gate_ops.enable;
-		clk_pll_ops.disable = clk_gate_ops.disable;
-	}
-
-	clk = clk_register(NULL, &socfpga_clk->hw.hw);
-	if (WARN_ON(IS_ERR(clk))) {
-		kfree(socfpga_clk);
-		return NULL;
-	}
-	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
-	return clk;
-}
-
-static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
-{
-	u32 l4_src;
-	u32 perpll_src;
-
-	if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
-		l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
-		return l4_src &= 0x1;
-	}
-	if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
-		l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
-		return !!(l4_src & 2);
-	}
-
-	perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
-	if (streq(hwclk->init->name, SOCFPGA_MMC_CLK))
-		return perpll_src &= 0x3;
-	if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
-			streq(hwclk->init->name, SOCFPGA_NAND_X_CLK))
-			return (perpll_src >> 2) & 3;
-
-	/* QSPI clock */
-	return (perpll_src >> 4) & 3;
-
-}
-
-static int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent)
-{
-	u32 src_reg;
-
-	if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
-		src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
-		src_reg &= ~0x1;
-		src_reg |= parent;
-		writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
-	} else if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
-		src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
-		src_reg &= ~0x2;
-		src_reg |= (parent << 1);
-		writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
-	} else {
-		src_reg = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
-		if (streq(hwclk->init->name, SOCFPGA_MMC_CLK)) {
-			src_reg &= ~0x3;
-			src_reg |= parent;
-		} else if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
-			streq(hwclk->init->name, SOCFPGA_NAND_X_CLK)) {
-			src_reg &= ~0xC;
-			src_reg |= (parent << 2);
-		} else {/* QSPI clock */
-			src_reg &= ~0x30;
-			src_reg |= (parent << 4);
-		}
-		writel(src_reg, clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
-	}
-
-	return 0;
-}
-
-static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
-	unsigned long parent_rate)
-{
-	struct socfpga_clk *socfpgaclk = to_socfpga_clk(hwclk);
-	u32 div = 1, val;
-
-	if (socfpgaclk->fixed_div)
-		div = socfpgaclk->fixed_div;
-	else if (socfpgaclk->div_reg) {
-		val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
-		val &= div_mask(socfpgaclk->width);
-		if (streq(hwclk->init->name, SOCFPGA_DB_CLK))
-			div = val + 1;
-		else
-			div = (1 << val);
-	}
-
-	return parent_rate / div;
-}
-
-static struct clk_ops gateclk_ops = {
-	.recalc_rate = socfpga_clk_recalc_rate,
-	.get_parent = socfpga_clk_get_parent,
-	.set_parent = socfpga_clk_set_parent,
-};
-
-static void __init socfpga_gate_clk_init(struct device_node *node,
-	const struct clk_ops *ops)
-{
-	u32 clk_gate[2];
-	u32 div_reg[3];
-	u32 fixed_div;
-	struct clk *clk;
-	struct socfpga_clk *socfpga_clk;
-	const char *clk_name = node->name;
-	const char *parent_name[SOCFGPA_MAX_PARENTS];
-	struct clk_init_data init;
-	int rc;
-	int i = 0;
-
-	socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
-	if (WARN_ON(!socfpga_clk))
-		return;
-
-	rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
-	if (rc)
-		clk_gate[0] = 0;
-
-	if (clk_gate[0]) {
-		socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0];
-		socfpga_clk->hw.bit_idx = clk_gate[1];
-
-		gateclk_ops.enable = clk_gate_ops.enable;
-		gateclk_ops.disable = clk_gate_ops.disable;
-	}
-
-	rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
-	if (rc)
-		socfpga_clk->fixed_div = 0;
-	else
-		socfpga_clk->fixed_div = fixed_div;
-
-	rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
-	if (!rc) {
-		socfpga_clk->div_reg = clk_mgr_base_addr + div_reg[0];
-		socfpga_clk->shift = div_reg[1];
-		socfpga_clk->width = div_reg[2];
-	} else {
-		socfpga_clk->div_reg = NULL;
-	}
-
-	of_property_read_string(node, "clock-output-names", &clk_name);
-
-	init.name = clk_name;
-	init.ops = ops;
-	init.flags = 0;
-	while (i < SOCFGPA_MAX_PARENTS && (parent_name[i] =
-			of_clk_get_parent_name(node, i)) != NULL)
-		i++;
-
-	init.parent_names = parent_name;
-	init.num_parents = i;
-	socfpga_clk->hw.hw.init = &init;
-
-	clk = clk_register(NULL, &socfpga_clk->hw.hw);
-	if (WARN_ON(IS_ERR(clk))) {
-		kfree(socfpga_clk);
-		return;
-	}
-	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
-	if (WARN_ON(rc))
-		return;
-}
-
-static void __init socfpga_pll_init(struct device_node *node)
-{
-	socfpga_clk_init(node, &clk_pll_ops);
-}
-CLK_OF_DECLARE(socfpga_pll, "altr,socfpga-pll-clock", socfpga_pll_init);
-
-static void __init socfpga_periph_init(struct device_node *node)
-{
-	socfpga_clk_init(node, &periclk_ops);
-}
-CLK_OF_DECLARE(socfpga_periph, "altr,socfpga-perip-clk", socfpga_periph_init);
-
-static void __init socfpga_gate_init(struct device_node *node)
-{
-	socfpga_gate_clk_init(node, &gateclk_ops);
-}
-CLK_OF_DECLARE(socfpga_gate, "altr,socfpga-gate-clk", socfpga_gate_init);
-
-void __init socfpga_init_clocks(void)
-{
-	struct clk *clk;
-	int ret;
-
-	clk = clk_register_fixed_factor(NULL, "smp_twd", "mpuclk", 0, 1, 4);
-	ret = clk_register_clkdev(clk, NULL, "smp_twd");
-	if (ret)
-		pr_err("smp_twd alias not registered\n");
-}
diff --git a/drivers/clk/socfpga/clk.h b/drivers/clk/socfpga/clk.h
new file mode 100644
index 0000000..d2e5401
--- /dev/null
+++ b/drivers/clk/socfpga/clk.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013, Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * based on drivers/clk/tegra/clk.h
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __SOCFPGA_CLK_H
+#define __SOCFPGA_CLK_H
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+/* Clock Manager offsets */
+#define CLKMGR_CTRL		0x0
+#define CLKMGR_BYPASS		0x4
+#define CLKMGR_L4SRC		0x70
+#define CLKMGR_PERPLL_SRC	0xAC
+
+#define SOCFPGA_MAX_PARENTS		3
+
+extern void __iomem *clk_mgr_base_addr;
+
+void __init socfpga_pll_init(struct device_node *node);
+void __init socfpga_periph_init(struct device_node *node);
+void __init socfpga_gate_init(struct device_node *node);
+
+struct socfpga_pll {
+	struct clk_gate	hw;
+};
+
+struct socfpga_gate_clk {
+	struct clk_gate hw;
+	char *parent_name;
+	u32 fixed_div;
+	void __iomem *div_reg;
+	u32 width;	/* only valid if div_reg != 0 */
+	u32 shift;	/* only valid if div_reg != 0 */
+	u32 clk_phase[2];
+};
+
+struct socfpga_periph_clk {
+	struct clk_gate hw;
+	char *parent_name;
+	u32 fixed_div;
+};
+
+#endif /* SOCFPGA_CLK_H */
diff --git a/drivers/clk/st/Makefile b/drivers/clk/st/Makefile
new file mode 100644
index 0000000..c7455ff
--- /dev/null
+++ b/drivers/clk/st/Makefile
@@ -0,0 +1 @@
+obj-y += clkgen-mux.o clkgen-pll.o clkgen-fsyn.o
diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c
new file mode 100644
index 0000000..4f53ee0
--- /dev/null
+++ b/drivers/clk/st/clkgen-fsyn.c
@@ -0,0 +1,1039 @@
+/*
+ * Copyright (C) 2014 STMicroelectronics R&D Ltd
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Authors:
+ * Stephen Gallimore <stephen.gallimore@st.com>,
+ * Pankaj Dev <pankaj.dev@st.com>.
+ */
+
+#include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/clk-provider.h>
+
+#include "clkgen.h"
+
+/*
+ * Maximum input clock to the PLL before we divide it down by 2
+ * although in reality in actual systems this has never been seen to
+ * be used.
+ */
+#define QUADFS_NDIV_THRESHOLD 30000000
+
+#define PLL_BW_GOODREF   (0L)
+#define PLL_BW_VBADREF   (1L)
+#define PLL_BW_BADREF    (2L)
+#define PLL_BW_VGOODREF  (3L)
+
+#define QUADFS_MAX_CHAN 4
+
+struct stm_fs {
+	unsigned long ndiv;
+	unsigned long mdiv;
+	unsigned long pe;
+	unsigned long sdiv;
+	unsigned long nsdiv;
+};
+
+static struct stm_fs fs216c65_rtbl[] = {
+	{ .mdiv = 0x1f, .pe = 0x0,	.sdiv = 0x7,	.nsdiv = 0 },	/* 312.5 Khz */
+	{ .mdiv = 0x17, .pe = 0x25ed,	.sdiv = 0x1,	.nsdiv = 0 },	/* 27    MHz */
+	{ .mdiv = 0x1a, .pe = 0x7b36,	.sdiv = 0x2,	.nsdiv = 1 },	/* 36.87 MHz */
+	{ .mdiv = 0x13, .pe = 0x0,	.sdiv = 0x2,	.nsdiv = 1 },	/* 48    MHz */
+	{ .mdiv = 0x11, .pe = 0x1c72,	.sdiv = 0x1,	.nsdiv = 1 },	/* 108   MHz */
+};
+
+static struct stm_fs fs432c65_rtbl[] = {
+	{ .mdiv = 0x1f, .pe = 0x0,	.sdiv = 0x7,	.nsdiv = 0 },	/* 625   Khz */
+	{ .mdiv = 0x11, .pe = 0x1c72,	.sdiv = 0x2,	.nsdiv = 1 },	/* 108   MHz */
+	{ .mdiv = 0x19, .pe = 0x121a,	.sdiv = 0x0,	.nsdiv = 1 },	/* 297   MHz */
+};
+
+static struct stm_fs fs660c32_rtbl[] = {
+	{ .mdiv = 0x01, .pe = 0x2aaa,	.sdiv = 0x8,	.nsdiv = 0 },	/* 600   KHz */
+	{ .mdiv = 0x02, .pe = 0x3d33,	.sdiv = 0x0,	.nsdiv = 0 },	/* 148.5 Mhz */
+	{ .mdiv = 0x13, .pe = 0x5bcc,	.sdiv = 0x0,	.nsdiv = 1 },	/* 297   Mhz */
+	{ .mdiv = 0x0e, .pe = 0x1025,	.sdiv = 0x0,	.nsdiv = 1 },	/* 333   Mhz */
+	{ .mdiv = 0x0b, .pe = 0x715f,	.sdiv = 0x0,	.nsdiv = 1 },	/* 350   Mhz */
+};
+
+struct clkgen_quadfs_data {
+	bool reset_present;
+	bool bwfilter_present;
+	bool lockstatus_present;
+	bool nsdiv_present;
+	struct clkgen_field ndiv;
+	struct clkgen_field ref_bw;
+	struct clkgen_field nreset;
+	struct clkgen_field npda;
+	struct clkgen_field lock_status;
+
+	struct clkgen_field nsb[QUADFS_MAX_CHAN];
+	struct clkgen_field en[QUADFS_MAX_CHAN];
+	struct clkgen_field mdiv[QUADFS_MAX_CHAN];
+	struct clkgen_field pe[QUADFS_MAX_CHAN];
+	struct clkgen_field sdiv[QUADFS_MAX_CHAN];
+	struct clkgen_field nsdiv[QUADFS_MAX_CHAN];
+
+	const struct clk_ops *pll_ops;
+	struct stm_fs *rtbl;
+	u8 rtbl_cnt;
+	int  (*get_rate)(unsigned long , struct stm_fs *,
+			unsigned long *);
+};
+
+static const struct clk_ops st_quadfs_pll_c65_ops;
+static const struct clk_ops st_quadfs_pll_c32_ops;
+static const struct clk_ops st_quadfs_fs216c65_ops;
+static const struct clk_ops st_quadfs_fs432c65_ops;
+static const struct clk_ops st_quadfs_fs660c32_ops;
+
+static int clk_fs216c65_get_rate(unsigned long, struct stm_fs *,
+		unsigned long *);
+static int clk_fs432c65_get_rate(unsigned long, struct stm_fs *,
+		unsigned long *);
+static int clk_fs660c32_dig_get_rate(unsigned long, struct stm_fs *,
+		unsigned long *);
+/*
+ * Values for all of the standalone instances of this clock
+ * generator found in STiH415 and STiH416 SYSCFG register banks. Note
+ * that the individual channel standby control bits (nsb) are in the
+ * first register along with the PLL control bits.
+ */
+static struct clkgen_quadfs_data st_fs216c65_416 = {
+	/* 416 specific */
+	.npda	= CLKGEN_FIELD(0x0, 0x1, 14),
+	.nsb	= { CLKGEN_FIELD(0x0, 0x1, 10),
+		    CLKGEN_FIELD(0x0, 0x1, 11),
+		    CLKGEN_FIELD(0x0, 0x1, 12),
+		    CLKGEN_FIELD(0x0, 0x1, 13) },
+	.nsdiv_present = true,
+	.nsdiv	= { CLKGEN_FIELD(0x0, 0x1, 18),
+		    CLKGEN_FIELD(0x0, 0x1, 19),
+		    CLKGEN_FIELD(0x0, 0x1, 20),
+		    CLKGEN_FIELD(0x0, 0x1, 21) },
+	.mdiv	= { CLKGEN_FIELD(0x4, 0x1f, 0),
+		    CLKGEN_FIELD(0x14, 0x1f, 0),
+		    CLKGEN_FIELD(0x24, 0x1f, 0),
+		    CLKGEN_FIELD(0x34, 0x1f, 0) },
+	.en	= { CLKGEN_FIELD(0x10, 0x1, 0),
+		    CLKGEN_FIELD(0x20, 0x1, 0),
+		    CLKGEN_FIELD(0x30, 0x1, 0),
+		    CLKGEN_FIELD(0x40, 0x1, 0) },
+	.ndiv	= CLKGEN_FIELD(0x0, 0x1, 15),
+	.bwfilter_present = true,
+	.ref_bw = CLKGEN_FIELD(0x0, 0x3, 16),
+	.pe	= { CLKGEN_FIELD(0x8, 0xffff, 0),
+		    CLKGEN_FIELD(0x18, 0xffff, 0),
+		    CLKGEN_FIELD(0x28, 0xffff, 0),
+		    CLKGEN_FIELD(0x38, 0xffff, 0) },
+	.sdiv	= { CLKGEN_FIELD(0xC, 0x7, 0),
+		    CLKGEN_FIELD(0x1C, 0x7, 0),
+		    CLKGEN_FIELD(0x2C, 0x7, 0),
+		    CLKGEN_FIELD(0x3C, 0x7, 0) },
+	.pll_ops	= &st_quadfs_pll_c65_ops,
+	.rtbl		= fs216c65_rtbl,
+	.rtbl_cnt	= ARRAY_SIZE(fs216c65_rtbl),
+	.get_rate	= clk_fs216c65_get_rate,
+};
+
+static struct clkgen_quadfs_data st_fs432c65_416 = {
+	.npda	= CLKGEN_FIELD(0x0, 0x1, 14),
+	.nsb	= { CLKGEN_FIELD(0x0, 0x1, 10),
+		    CLKGEN_FIELD(0x0, 0x1, 11),
+		    CLKGEN_FIELD(0x0, 0x1, 12),
+		    CLKGEN_FIELD(0x0, 0x1, 13) },
+	.nsdiv_present = true,
+	.nsdiv	= { CLKGEN_FIELD(0x0, 0x1, 18),
+		   CLKGEN_FIELD(0x0, 0x1, 19),
+		   CLKGEN_FIELD(0x0, 0x1, 20),
+		   CLKGEN_FIELD(0x0, 0x1, 21) },
+	.mdiv	= { CLKGEN_FIELD(0x4, 0x1f, 0),
+		    CLKGEN_FIELD(0x14, 0x1f, 0),
+		    CLKGEN_FIELD(0x24, 0x1f, 0),
+		    CLKGEN_FIELD(0x34, 0x1f, 0) },
+	.en	= { CLKGEN_FIELD(0x10, 0x1, 0),
+		    CLKGEN_FIELD(0x20, 0x1, 0),
+		    CLKGEN_FIELD(0x30, 0x1, 0),
+		    CLKGEN_FIELD(0x40, 0x1, 0) },
+	.ndiv	= CLKGEN_FIELD(0x0, 0x1, 15),
+	.bwfilter_present = true,
+	.ref_bw = CLKGEN_FIELD(0x0, 0x3, 16),
+	.pe	= { CLKGEN_FIELD(0x8, 0xffff, 0),
+		    CLKGEN_FIELD(0x18, 0xffff, 0),
+		    CLKGEN_FIELD(0x28, 0xffff, 0),
+		    CLKGEN_FIELD(0x38, 0xffff, 0) },
+	.sdiv	= { CLKGEN_FIELD(0xC, 0x7, 0),
+		    CLKGEN_FIELD(0x1C, 0x7, 0),
+		    CLKGEN_FIELD(0x2C, 0x7, 0),
+		    CLKGEN_FIELD(0x3C, 0x7, 0) },
+	.pll_ops	= &st_quadfs_pll_c65_ops,
+	.rtbl		= fs432c65_rtbl,
+	.rtbl_cnt	= ARRAY_SIZE(fs432c65_rtbl),
+	.get_rate	= clk_fs432c65_get_rate,
+};
+
+static struct clkgen_quadfs_data st_fs660c32_E_416 = {
+	.npda	= CLKGEN_FIELD(0x0, 0x1, 14),
+	.nsb	= { CLKGEN_FIELD(0x0, 0x1, 10),
+		    CLKGEN_FIELD(0x0, 0x1, 11),
+		    CLKGEN_FIELD(0x0, 0x1, 12),
+		    CLKGEN_FIELD(0x0, 0x1, 13) },
+	.nsdiv_present = true,
+	.nsdiv	= { CLKGEN_FIELD(0x0, 0x1, 18),
+		    CLKGEN_FIELD(0x0, 0x1, 19),
+		    CLKGEN_FIELD(0x0, 0x1, 20),
+		    CLKGEN_FIELD(0x0, 0x1, 21) },
+	.mdiv	= { CLKGEN_FIELD(0x4, 0x1f, 0),
+		    CLKGEN_FIELD(0x14, 0x1f, 0),
+		    CLKGEN_FIELD(0x24, 0x1f, 0),
+		    CLKGEN_FIELD(0x34, 0x1f, 0) },
+	.en	= { CLKGEN_FIELD(0x10, 0x1, 0),
+		    CLKGEN_FIELD(0x20, 0x1, 0),
+		    CLKGEN_FIELD(0x30, 0x1, 0),
+		    CLKGEN_FIELD(0x40, 0x1, 0) },
+	.ndiv	= CLKGEN_FIELD(0x0, 0x7, 15),
+	.pe	= { CLKGEN_FIELD(0x8, 0x7fff, 0),
+		    CLKGEN_FIELD(0x18, 0x7fff, 0),
+		    CLKGEN_FIELD(0x28, 0x7fff, 0),
+		    CLKGEN_FIELD(0x38, 0x7fff, 0) },
+	.sdiv	= { CLKGEN_FIELD(0xC, 0xf, 0),
+		    CLKGEN_FIELD(0x1C, 0xf, 0),
+		    CLKGEN_FIELD(0x2C, 0xf, 0),
+		    CLKGEN_FIELD(0x3C, 0xf, 0) },
+	.lockstatus_present = true,
+	.lock_status = CLKGEN_FIELD(0xAC, 0x1, 0),
+	.pll_ops	= &st_quadfs_pll_c32_ops,
+	.rtbl		= fs660c32_rtbl,
+	.rtbl_cnt	= ARRAY_SIZE(fs660c32_rtbl),
+	.get_rate	= clk_fs660c32_dig_get_rate,
+};
+
+static struct clkgen_quadfs_data st_fs660c32_F_416 = {
+	.npda	= CLKGEN_FIELD(0x0, 0x1, 14),
+	.nsb	= { CLKGEN_FIELD(0x0, 0x1, 10),
+		    CLKGEN_FIELD(0x0, 0x1, 11),
+		    CLKGEN_FIELD(0x0, 0x1, 12),
+		    CLKGEN_FIELD(0x0, 0x1, 13) },
+	.nsdiv_present = true,
+	.nsdiv	= { CLKGEN_FIELD(0x0, 0x1, 18),
+		    CLKGEN_FIELD(0x0, 0x1, 19),
+		    CLKGEN_FIELD(0x0, 0x1, 20),
+		    CLKGEN_FIELD(0x0, 0x1, 21) },
+	.mdiv	= { CLKGEN_FIELD(0x4, 0x1f, 0),
+		    CLKGEN_FIELD(0x14, 0x1f, 0),
+		    CLKGEN_FIELD(0x24, 0x1f, 0),
+		    CLKGEN_FIELD(0x34, 0x1f, 0) },
+	.en	= { CLKGEN_FIELD(0x10, 0x1, 0),
+		    CLKGEN_FIELD(0x20, 0x1, 0),
+		    CLKGEN_FIELD(0x30, 0x1, 0),
+		    CLKGEN_FIELD(0x40, 0x1, 0) },
+	.ndiv	= CLKGEN_FIELD(0x0, 0x7, 15),
+	.pe	= { CLKGEN_FIELD(0x8, 0x7fff, 0),
+		    CLKGEN_FIELD(0x18, 0x7fff, 0),
+		    CLKGEN_FIELD(0x28, 0x7fff, 0),
+		    CLKGEN_FIELD(0x38, 0x7fff, 0) },
+	.sdiv	= { CLKGEN_FIELD(0xC, 0xf, 0),
+		    CLKGEN_FIELD(0x1C, 0xf, 0),
+		    CLKGEN_FIELD(0x2C, 0xf, 0),
+		    CLKGEN_FIELD(0x3C, 0xf, 0) },
+	.lockstatus_present = true,
+	.lock_status = CLKGEN_FIELD(0xEC, 0x1, 0),
+	.pll_ops	= &st_quadfs_pll_c32_ops,
+	.rtbl		= fs660c32_rtbl,
+	.rtbl_cnt	= ARRAY_SIZE(fs660c32_rtbl),
+	.get_rate	= clk_fs660c32_dig_get_rate,
+};
+
+/**
+ * DOC: A Frequency Synthesizer that multiples its input clock by a fixed factor
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parent is (un)prepared
+ * enable - clk_enable and clk_disable are functional & control the Fsyn
+ * rate - inherits rate from parent. set_rate/round_rate/recalc_rate
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+/**
+ * struct st_clk_quadfs_pll - A pll which outputs a fixed multiplier of
+ *                                  its parent clock, found inside a type of
+ *                                  ST quad channel frequency synthesizer block
+ *
+ * @hw: handle between common and hardware-specific interfaces.
+ * @ndiv: regmap field for the ndiv control.
+ * @regs_base: base address of the configuration registers.
+ * @lock: spinlock.
+ *
+ */
+struct st_clk_quadfs_pll {
+	struct clk_hw	hw;
+	void __iomem	*regs_base;
+	spinlock_t	*lock;
+	struct clkgen_quadfs_data *data;
+	u32 ndiv;
+};
+
+#define to_quadfs_pll(_hw) container_of(_hw, struct st_clk_quadfs_pll, hw)
+
+static int quadfs_pll_enable(struct clk_hw *hw)
+{
+	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
+	unsigned long flags = 0, timeout = jiffies + msecs_to_jiffies(10);
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	/*
+	 * Bring block out of reset if we have reset control.
+	 */
+	if (pll->data->reset_present)
+		CLKGEN_WRITE(pll, nreset, 1);
+
+	/*
+	 * Use a fixed input clock noise bandwidth filter for the moment
+	 */
+	if (pll->data->bwfilter_present)
+		CLKGEN_WRITE(pll, ref_bw, PLL_BW_GOODREF);
+
+
+	CLKGEN_WRITE(pll, ndiv, pll->ndiv);
+
+	/*
+	 * Power up the PLL
+	 */
+	CLKGEN_WRITE(pll, npda, 1);
+
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+
+	if (pll->data->lockstatus_present)
+		while (!CLKGEN_READ(pll, lock_status)) {
+			if (time_after(jiffies, timeout))
+				return -ETIMEDOUT;
+			cpu_relax();
+		}
+
+	return 0;
+}
+
+static void quadfs_pll_disable(struct clk_hw *hw)
+{
+	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
+	unsigned long flags = 0;
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	/*
+	 * Powerdown the PLL and then put block into soft reset if we have
+	 * reset control.
+	 */
+	CLKGEN_WRITE(pll, npda, 0);
+
+	if (pll->data->reset_present)
+		CLKGEN_WRITE(pll, nreset, 0);
+
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static int quadfs_pll_is_enabled(struct clk_hw *hw)
+{
+	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
+	u32 npda = CLKGEN_READ(pll, npda);
+
+	return !!npda;
+}
+
+int clk_fs660c32_vco_get_rate(unsigned long input, struct stm_fs *fs,
+			   unsigned long *rate)
+{
+	unsigned long nd = fs->ndiv + 16; /* ndiv value */
+
+	*rate = input * nd;
+
+	return 0;
+}
+
+static unsigned long quadfs_pll_fs660c32_recalc_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
+	unsigned long rate = 0;
+	struct stm_fs params;
+
+	params.ndiv = CLKGEN_READ(pll, ndiv);
+	if (clk_fs660c32_vco_get_rate(parent_rate, &params, &rate))
+		pr_err("%s:%s error calculating rate\n",
+		       __clk_get_name(hw->clk), __func__);
+
+	pll->ndiv = params.ndiv;
+
+	return rate;
+}
+
+int clk_fs660c32_vco_get_params(unsigned long input,
+				unsigned long output, struct stm_fs *fs)
+{
+/* Formula
+   VCO frequency = (fin x ndiv) / pdiv
+   ndiv = VCOfreq * pdiv / fin
+   */
+	unsigned long pdiv = 1, n;
+
+	/* Output clock range: 384Mhz to 660Mhz */
+	if (output < 384000000 || output > 660000000)
+		return -EINVAL;
+
+	if (input > 40000000)
+		/* This means that PDIV would be 2 instead of 1.
+		   Not supported today. */
+		return -EINVAL;
+
+	input /= 1000;
+	output /= 1000;
+
+	n = output * pdiv / input;
+	if (n < 16)
+		n = 16;
+	fs->ndiv = n - 16; /* Converting formula value to reg value */
+
+	return 0;
+}
+
+static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw, unsigned long rate
+		, unsigned long *prate)
+{
+	struct stm_fs params;
+
+	if (!clk_fs660c32_vco_get_params(*prate, rate, &params))
+		clk_fs660c32_vco_get_rate(*prate, &params, &rate);
+
+	pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n",
+		 __func__, __clk_get_name(hw->clk),
+		 rate, (unsigned int)params.sdiv,
+		 (unsigned int)params.mdiv,
+		 (unsigned int)params.pe, (unsigned int)params.nsdiv);
+
+	return rate;
+}
+
+static int quadfs_pll_fs660c32_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate)
+{
+	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
+	struct stm_fs params;
+	long hwrate = 0;
+	unsigned long flags = 0;
+
+	if (!rate || !parent_rate)
+		return -EINVAL;
+
+	if (!clk_fs660c32_vco_get_params(parent_rate, rate, &params))
+		clk_fs660c32_vco_get_rate(parent_rate, &params, &hwrate);
+
+	pr_debug("%s: %s new rate %ld [ndiv=0x%x]\n",
+		 __func__, __clk_get_name(hw->clk),
+		 hwrate, (unsigned int)params.ndiv);
+
+	if (!hwrate)
+		return -EINVAL;
+
+	pll->ndiv = params.ndiv;
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	CLKGEN_WRITE(pll, ndiv, pll->ndiv);
+
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+
+	return 0;
+}
+
+static const struct clk_ops st_quadfs_pll_c65_ops = {
+	.enable		= quadfs_pll_enable,
+	.disable	= quadfs_pll_disable,
+	.is_enabled	= quadfs_pll_is_enabled,
+};
+
+static const struct clk_ops st_quadfs_pll_c32_ops = {
+	.enable		= quadfs_pll_enable,
+	.disable	= quadfs_pll_disable,
+	.is_enabled	= quadfs_pll_is_enabled,
+	.recalc_rate	= quadfs_pll_fs660c32_recalc_rate,
+	.round_rate	= quadfs_pll_fs660c32_round_rate,
+	.set_rate	= quadfs_pll_fs660c32_set_rate,
+};
+
+static struct clk * __init st_clk_register_quadfs_pll(
+		const char *name, const char *parent_name,
+		struct clkgen_quadfs_data *quadfs, void __iomem *reg,
+		spinlock_t *lock)
+{
+	struct st_clk_quadfs_pll *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	/*
+	 * Sanity check required pointers.
+	 */
+	if (WARN_ON(!name || !parent_name))
+		return ERR_PTR(-EINVAL);
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = quadfs->pll_ops;
+	init.flags = CLK_IS_BASIC;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	pll->data = quadfs;
+	pll->regs_base = reg;
+	pll->lock = lock;
+	pll->hw.init = &init;
+
+	clk = clk_register(NULL, &pll->hw);
+
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
+
+/**
+ * DOC: A digital frequency synthesizer
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parent is (un)prepared
+ * enable - clk_enable and clk_disable are functional
+ * rate - set rate is functional
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+/**
+ * struct st_clk_quadfs_fsynth - One clock output from a four channel digital
+ *                                  frequency synthesizer (fsynth) block.
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ *
+ * @nsb: regmap field in the output control register for the digital
+ *       standby of this fsynth channel. This control is active low so
+ *       the channel is in standby when the control bit is cleared.
+ *
+ * @nsdiv: regmap field in the output control register for
+ *          for the optional divide by 3 of this fsynth channel. This control
+ *          is active low so the divide by 3 is active when the control bit is
+ *          cleared and the divide is bypassed when the bit is set.
+ */
+struct st_clk_quadfs_fsynth {
+	struct clk_hw	hw;
+	void __iomem	*regs_base;
+	spinlock_t	*lock;
+	struct clkgen_quadfs_data *data;
+
+	u32 chan;
+	/*
+	 * Cached hardware values from set_rate so we can program the
+	 * hardware in enable. There are two reasons for this:
+	 *
+	 *  1. The registers may not be writable until the parent has been
+	 *     enabled.
+	 *
+	 *  2. It restores the clock rate when a driver does an enable
+	 *     on PM restore, after a suspend to RAM has lost the hardware
+	 *     setup.
+	 */
+	u32 md;
+	u32 pe;
+	u32 sdiv;
+	u32 nsdiv;
+};
+
+#define to_quadfs_fsynth(_hw) \
+	container_of(_hw, struct st_clk_quadfs_fsynth, hw)
+
+static void quadfs_fsynth_program_enable(struct st_clk_quadfs_fsynth *fs)
+{
+	/*
+	 * Pulse the program enable register lsb to make the hardware take
+	 * notice of the new md/pe values with a glitchless transition.
+	 */
+	CLKGEN_WRITE(fs, en[fs->chan], 1);
+	CLKGEN_WRITE(fs, en[fs->chan], 0);
+}
+
+static void quadfs_fsynth_program_rate(struct st_clk_quadfs_fsynth *fs)
+{
+	unsigned long flags = 0;
+
+	/*
+	 * Ensure the md/pe parameters are ignored while we are
+	 * reprogramming them so we can get a glitchless change
+	 * when fine tuning the speed of a running clock.
+	 */
+	CLKGEN_WRITE(fs, en[fs->chan], 0);
+
+	CLKGEN_WRITE(fs, mdiv[fs->chan], fs->md);
+	CLKGEN_WRITE(fs, pe[fs->chan], fs->pe);
+	CLKGEN_WRITE(fs, sdiv[fs->chan], fs->sdiv);
+
+	if (fs->lock)
+		spin_lock_irqsave(fs->lock, flags);
+
+	if (fs->data->nsdiv_present)
+		CLKGEN_WRITE(fs, nsdiv[fs->chan], fs->nsdiv);
+
+	if (fs->lock)
+		spin_unlock_irqrestore(fs->lock, flags);
+}
+
+static int quadfs_fsynth_enable(struct clk_hw *hw)
+{
+	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
+	unsigned long flags = 0;
+
+	pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
+
+	quadfs_fsynth_program_rate(fs);
+
+	if (fs->lock)
+		spin_lock_irqsave(fs->lock, flags);
+
+	CLKGEN_WRITE(fs, nsb[fs->chan], 1);
+
+	if (fs->lock)
+		spin_unlock_irqrestore(fs->lock, flags);
+
+	quadfs_fsynth_program_enable(fs);
+
+	return 0;
+}
+
+static void quadfs_fsynth_disable(struct clk_hw *hw)
+{
+	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
+	unsigned long flags = 0;
+
+	pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
+
+	if (fs->lock)
+		spin_lock_irqsave(fs->lock, flags);
+
+	CLKGEN_WRITE(fs, nsb[fs->chan], 0);
+
+	if (fs->lock)
+		spin_unlock_irqrestore(fs->lock, flags);
+}
+
+static int quadfs_fsynth_is_enabled(struct clk_hw *hw)
+{
+	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
+	u32 nsb = CLKGEN_READ(fs, nsb[fs->chan]);
+
+	pr_debug("%s: %s enable bit = 0x%x\n",
+		 __func__, __clk_get_name(hw->clk), nsb);
+
+	return !!nsb;
+}
+
+#define P15			(uint64_t)(1 << 15)
+
+static int clk_fs216c65_get_rate(unsigned long input, struct stm_fs *fs,
+		unsigned long *rate)
+{
+	uint64_t res;
+	unsigned long ns;
+	unsigned long nd = 8; /* ndiv stuck at 0 => val = 8 */
+	unsigned long s;
+	long m;
+
+	m = fs->mdiv - 32;
+	s = 1 << (fs->sdiv + 1);
+	ns = (fs->nsdiv ? 1 : 3);
+
+	res = (uint64_t)(s * ns * P15 * (uint64_t)(m + 33));
+	res = res - (s * ns * fs->pe);
+	*rate = div64_u64(P15 * nd * input * 32, res);
+
+	return 0;
+}
+
+static int clk_fs432c65_get_rate(unsigned long input, struct stm_fs *fs,
+		unsigned long *rate)
+{
+	uint64_t res;
+	unsigned long nd = 16; /* ndiv value; stuck at 0 (30Mhz input) */
+	long m;
+	unsigned long sd;
+	unsigned long ns;
+
+	m = fs->mdiv - 32;
+	sd = 1 << (fs->sdiv + 1);
+	ns = (fs->nsdiv ? 1 : 3);
+
+	res = (uint64_t)(sd * ns * P15 * (uint64_t)(m + 33));
+	res = res - (sd * ns * fs->pe);
+	*rate = div64_u64(P15 * nd * input * 32, res);
+
+	return 0;
+}
+
+#define P20		(uint64_t)(1 << 20)
+
+static int clk_fs660c32_dig_get_rate(unsigned long input,
+				struct stm_fs *fs, unsigned long *rate)
+{
+	unsigned long s = (1 << fs->sdiv);
+	unsigned long ns;
+	uint64_t res;
+
+	/*
+	 * 'nsdiv' is a register value ('BIN') which is translated
+	 * to a decimal value according to following rules.
+	 *
+	 *     nsdiv      ns.dec
+	 *       0        3
+	 *       1        1
+	 */
+	ns = (fs->nsdiv == 1) ? 1 : 3;
+
+	res = (P20 * (32 + fs->mdiv) + 32 * fs->pe) * s * ns;
+	*rate = (unsigned long)div64_u64(input * P20 * 32, res);
+
+	return 0;
+}
+
+static int quadfs_fsynt_get_hw_value_for_recalc(struct st_clk_quadfs_fsynth *fs,
+		struct stm_fs *params)
+{
+	/*
+	 * Get the initial hardware values for recalc_rate
+	 */
+	params->mdiv	= CLKGEN_READ(fs, mdiv[fs->chan]);
+	params->pe	= CLKGEN_READ(fs, pe[fs->chan]);
+	params->sdiv	= CLKGEN_READ(fs, sdiv[fs->chan]);
+
+	if (fs->data->nsdiv_present)
+		params->nsdiv = CLKGEN_READ(fs, nsdiv[fs->chan]);
+	else
+		params->nsdiv = 1;
+
+	/*
+	 * If All are NULL then assume no clock rate is programmed.
+	 */
+	if (!params->mdiv && !params->pe && !params->sdiv)
+		return 1;
+
+	fs->md = params->mdiv;
+	fs->pe = params->pe;
+	fs->sdiv = params->sdiv;
+	fs->nsdiv = params->nsdiv;
+
+	return 0;
+}
+
+static long quadfs_find_best_rate(struct clk_hw *hw, unsigned long drate,
+				unsigned long prate, struct stm_fs *params)
+{
+	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
+	int (*clk_fs_get_rate)(unsigned long ,
+				struct stm_fs *, unsigned long *);
+	struct stm_fs prev_params;
+	unsigned long prev_rate, rate = 0;
+	unsigned long diff_rate, prev_diff_rate = ~0;
+	int index;
+
+	clk_fs_get_rate = fs->data->get_rate;
+
+	for (index = 0; index < fs->data->rtbl_cnt; index++) {
+		prev_rate = rate;
+
+		*params = fs->data->rtbl[index];
+		prev_params = *params;
+
+		clk_fs_get_rate(prate, &fs->data->rtbl[index], &rate);
+
+		diff_rate = abs(drate - rate);
+
+		if (diff_rate > prev_diff_rate) {
+			rate = prev_rate;
+			*params = prev_params;
+			break;
+		}
+
+		prev_diff_rate = diff_rate;
+
+		if (drate == rate)
+			return rate;
+	}
+
+
+	if (index == fs->data->rtbl_cnt)
+		*params = prev_params;
+
+	return rate;
+}
+
+static unsigned long quadfs_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
+	unsigned long rate = 0;
+	struct stm_fs params;
+	int (*clk_fs_get_rate)(unsigned long ,
+				struct stm_fs *, unsigned long *);
+
+	clk_fs_get_rate = fs->data->get_rate;
+
+	if (quadfs_fsynt_get_hw_value_for_recalc(fs, &params))
+		return 0;
+
+	if (clk_fs_get_rate(parent_rate, &params, &rate)) {
+		pr_err("%s:%s error calculating rate\n",
+		       __clk_get_name(hw->clk), __func__);
+	}
+
+	pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
+
+	return rate;
+}
+
+static long quadfs_round_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long *prate)
+{
+	struct stm_fs params;
+
+	rate = quadfs_find_best_rate(hw, rate, *prate, &params);
+
+	pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n",
+		 __func__, __clk_get_name(hw->clk),
+		 rate, (unsigned int)params.sdiv, (unsigned int)params.mdiv,
+			 (unsigned int)params.pe, (unsigned int)params.nsdiv);
+
+	return rate;
+}
+
+
+static void quadfs_program_and_enable(struct st_clk_quadfs_fsynth *fs,
+		struct stm_fs *params)
+{
+	fs->md = params->mdiv;
+	fs->pe = params->pe;
+	fs->sdiv = params->sdiv;
+	fs->nsdiv = params->nsdiv;
+
+	/*
+	 * In some integrations you can only change the fsynth programming when
+	 * the parent entity containing it is enabled.
+	 */
+	quadfs_fsynth_program_rate(fs);
+	quadfs_fsynth_program_enable(fs);
+}
+
+static int quadfs_set_rate(struct clk_hw *hw, unsigned long rate,
+				  unsigned long parent_rate)
+{
+	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
+	struct stm_fs params;
+	long hwrate;
+	int uninitialized_var(i);
+
+	if (!rate || !parent_rate)
+		return -EINVAL;
+
+	memset(&params, 0, sizeof(struct stm_fs));
+
+	hwrate = quadfs_find_best_rate(hw, rate, parent_rate, &params);
+	if (!hwrate)
+		return -EINVAL;
+
+	quadfs_program_and_enable(fs, &params);
+
+	return 0;
+}
+
+
+
+static const struct clk_ops st_quadfs_ops = {
+	.enable		= quadfs_fsynth_enable,
+	.disable	= quadfs_fsynth_disable,
+	.is_enabled	= quadfs_fsynth_is_enabled,
+	.round_rate	= quadfs_round_rate,
+	.set_rate	= quadfs_set_rate,
+	.recalc_rate	= quadfs_recalc_rate,
+};
+
+static struct clk * __init st_clk_register_quadfs_fsynth(
+		const char *name, const char *parent_name,
+		struct clkgen_quadfs_data *quadfs, void __iomem *reg, u32 chan,
+		spinlock_t *lock)
+{
+	struct st_clk_quadfs_fsynth *fs;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	/*
+	 * Sanity check required pointers, note that nsdiv3 is optional.
+	 */
+	if (WARN_ON(!name || !parent_name))
+		return ERR_PTR(-EINVAL);
+
+	fs = kzalloc(sizeof(*fs), GFP_KERNEL);
+	if (!fs)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &st_quadfs_ops;
+	init.flags = CLK_GET_RATE_NOCACHE | CLK_IS_BASIC;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	fs->data = quadfs;
+	fs->regs_base = reg;
+	fs->chan = chan;
+	fs->lock = lock;
+	fs->hw.init = &init;
+
+	clk = clk_register(NULL, &fs->hw);
+
+	if (IS_ERR(clk))
+		kfree(fs);
+
+	return clk;
+}
+
+static struct of_device_id quadfs_of_match[] = {
+	{
+		.compatible = "st,stih416-quadfs216",
+		.data = (void *)&st_fs216c65_416
+	},
+	{
+		.compatible = "st,stih416-quadfs432",
+		.data = (void *)&st_fs432c65_416
+	},
+	{
+		.compatible = "st,stih416-quadfs660-E",
+		.data = (void *)&st_fs660c32_E_416
+	},
+	{
+		.compatible = "st,stih416-quadfs660-F",
+		.data = (void *)&st_fs660c32_F_416
+	},
+	{}
+};
+
+static void __init st_of_create_quadfs_fsynths(
+		struct device_node *np, const char *pll_name,
+		struct clkgen_quadfs_data *quadfs, void __iomem *reg,
+		spinlock_t *lock)
+{
+	struct clk_onecell_data *clk_data;
+	int fschan;
+
+	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		return;
+
+	clk_data->clk_num = QUADFS_MAX_CHAN;
+	clk_data->clks = kzalloc(QUADFS_MAX_CHAN * sizeof(struct clk *),
+				 GFP_KERNEL);
+
+	if (!clk_data->clks) {
+		kfree(clk_data);
+		return;
+	}
+
+	for (fschan = 0; fschan < QUADFS_MAX_CHAN; fschan++) {
+		struct clk *clk;
+		const char *clk_name;
+
+		if (of_property_read_string_index(np, "clock-output-names",
+						  fschan, &clk_name)) {
+			break;
+		}
+
+		/*
+		 * If we read an empty clock name then the channel is unused
+		 */
+		if (*clk_name == '\0')
+			continue;
+
+		clk = st_clk_register_quadfs_fsynth(clk_name, pll_name,
+				quadfs, reg, fschan, lock);
+
+		/*
+		 * If there was an error registering this clock output, clean
+		 * up and move on to the next one.
+		 */
+		if (!IS_ERR(clk)) {
+			clk_data->clks[fschan] = clk;
+			pr_debug("%s: parent %s rate %u\n",
+				__clk_get_name(clk),
+				__clk_get_name(clk_get_parent(clk)),
+				(unsigned int)clk_get_rate(clk));
+		}
+	}
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+}
+
+static void __init st_of_quadfs_setup(struct device_node *np)
+{
+	const struct of_device_id *match;
+	struct clk *clk;
+	const char *pll_name, *clk_parent_name;
+	void __iomem *reg;
+	spinlock_t *lock;
+
+	match = of_match_node(quadfs_of_match, np);
+	if (WARN_ON(!match))
+		return;
+
+	reg = of_iomap(np, 0);
+	if (!reg)
+		return;
+
+	clk_parent_name = of_clk_get_parent_name(np, 0);
+	if (!clk_parent_name)
+		return;
+
+	pll_name = kasprintf(GFP_KERNEL, "%s.pll", np->name);
+	if (!pll_name)
+		return;
+
+	lock = kzalloc(sizeof(*lock), GFP_KERNEL);
+	if (!lock)
+		goto err_exit;
+
+	spin_lock_init(lock);
+
+	clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name,
+			(struct clkgen_quadfs_data *) match->data, reg, lock);
+	if (IS_ERR(clk))
+		goto err_exit;
+	else
+		pr_debug("%s: parent %s rate %u\n",
+			__clk_get_name(clk),
+			__clk_get_name(clk_get_parent(clk)),
+			(unsigned int)clk_get_rate(clk));
+
+	st_of_create_quadfs_fsynths(np, pll_name,
+				    (struct clkgen_quadfs_data *)match->data,
+				    reg, lock);
+
+err_exit:
+	kfree(pll_name); /* No longer need local copy of the PLL name */
+}
+CLK_OF_DECLARE(quadfs, "st,quadfs", st_of_quadfs_setup);
diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c
new file mode 100644
index 0000000..a329906
--- /dev/null
+++ b/drivers/clk/st/clkgen-mux.c
@@ -0,0 +1,820 @@
+/*
+ * clkgen-mux.c: ST GEN-MUX Clock driver
+ *
+ * Copyright (C) 2014 STMicroelectronics (R&D) Limited
+ *
+ * Authors: Stephen Gallimore <stephen.gallimore@st.com>
+ *	    Pankaj Dev <pankaj.dev@st.com>
+ *
+ * This program 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/slab.h>
+#include <linux/of_address.h>
+#include <linux/clk-provider.h>
+
+static DEFINE_SPINLOCK(clkgena_divmux_lock);
+static DEFINE_SPINLOCK(clkgenf_lock);
+
+static const char ** __init clkgen_mux_get_parents(struct device_node *np,
+						       int *num_parents)
+{
+	const char **parents;
+	int nparents, i;
+
+	nparents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+	if (WARN_ON(nparents <= 0))
+		return ERR_PTR(-EINVAL);
+
+	parents = kzalloc(nparents * sizeof(const char *), GFP_KERNEL);
+	if (!parents)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < nparents; i++)
+		parents[i] = of_clk_get_parent_name(np, i);
+
+	*num_parents = nparents;
+	return parents;
+}
+
+/**
+ * DOC: Clock mux with a programmable divider on each of its three inputs.
+ *      The mux has an input setting which effectively gates its output.
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parent is (un)prepared
+ * enable - clk_enable and clk_disable are functional & control gating
+ * rate - set rate is supported
+ * parent - set/get parent
+ */
+
+#define NUM_INPUTS 3
+
+struct clkgena_divmux {
+	struct clk_hw hw;
+	/* Subclassed mux and divider structures */
+	struct clk_mux mux;
+	struct clk_divider div[NUM_INPUTS];
+	/* Enable/running feedback register bits for each input */
+	void __iomem *feedback_reg[NUM_INPUTS];
+	int feedback_bit_idx;
+
+	u8              muxsel;
+};
+
+#define to_clkgena_divmux(_hw) container_of(_hw, struct clkgena_divmux, hw)
+
+struct clkgena_divmux_data {
+	int num_outputs;
+	int mux_offset;
+	int mux_offset2;
+	int mux_start_bit;
+	int div_offsets[NUM_INPUTS];
+	int fb_offsets[NUM_INPUTS];
+	int fb_start_bit_idx;
+};
+
+#define CKGAX_CLKOPSRC_SWITCH_OFF 0x3
+
+static int clkgena_divmux_is_running(struct clkgena_divmux *mux)
+{
+	u32 regval = readl(mux->feedback_reg[mux->muxsel]);
+	u32 running = regval & BIT(mux->feedback_bit_idx);
+	return !!running;
+}
+
+static int clkgena_divmux_enable(struct clk_hw *hw)
+{
+	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
+	struct clk_hw *mux_hw = &genamux->mux.hw;
+	unsigned long timeout;
+	int ret = 0;
+
+	mux_hw->clk = hw->clk;
+
+	ret = clk_mux_ops.set_parent(mux_hw, genamux->muxsel);
+	if (ret)
+		return ret;
+
+	timeout = jiffies + msecs_to_jiffies(10);
+
+	while (!clkgena_divmux_is_running(genamux)) {
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+		cpu_relax();
+	}
+
+	return 0;
+}
+
+static void clkgena_divmux_disable(struct clk_hw *hw)
+{
+	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
+	struct clk_hw *mux_hw = &genamux->mux.hw;
+
+	mux_hw->clk = hw->clk;
+
+	clk_mux_ops.set_parent(mux_hw, CKGAX_CLKOPSRC_SWITCH_OFF);
+}
+
+static int clkgena_divmux_is_enabled(struct clk_hw *hw)
+{
+	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
+	struct clk_hw *mux_hw = &genamux->mux.hw;
+
+	mux_hw->clk = hw->clk;
+
+	return (s8)clk_mux_ops.get_parent(mux_hw) > 0;
+}
+
+u8 clkgena_divmux_get_parent(struct clk_hw *hw)
+{
+	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
+	struct clk_hw *mux_hw = &genamux->mux.hw;
+
+	mux_hw->clk = hw->clk;
+
+	genamux->muxsel = clk_mux_ops.get_parent(mux_hw);
+	if ((s8)genamux->muxsel < 0) {
+		pr_debug("%s: %s: Invalid parent, setting to default.\n",
+		      __func__, __clk_get_name(hw->clk));
+		genamux->muxsel = 0;
+	}
+
+	return genamux->muxsel;
+}
+
+static int clkgena_divmux_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
+
+	if (index >= CKGAX_CLKOPSRC_SWITCH_OFF)
+		return -EINVAL;
+
+	genamux->muxsel = index;
+
+	/*
+	 * If the mux is already enabled, call enable directly to set the
+	 * new mux position and wait for it to start running again. Otherwise
+	 * do nothing.
+	 */
+	if (clkgena_divmux_is_enabled(hw))
+		clkgena_divmux_enable(hw);
+
+	return 0;
+}
+
+unsigned long clkgena_divmux_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
+	struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
+
+	div_hw->clk = hw->clk;
+
+	return clk_divider_ops.recalc_rate(div_hw, parent_rate);
+}
+
+static int clkgena_divmux_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate)
+{
+	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
+	struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
+
+	div_hw->clk = hw->clk;
+
+	return clk_divider_ops.set_rate(div_hw, rate, parent_rate);
+}
+
+static long clkgena_divmux_round_rate(struct clk_hw *hw, unsigned long rate,
+				   unsigned long *prate)
+{
+	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
+	struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
+
+	div_hw->clk = hw->clk;
+
+	return clk_divider_ops.round_rate(div_hw, rate, prate);
+}
+
+static const struct clk_ops clkgena_divmux_ops = {
+	.enable = clkgena_divmux_enable,
+	.disable = clkgena_divmux_disable,
+	.is_enabled = clkgena_divmux_is_enabled,
+	.get_parent = clkgena_divmux_get_parent,
+	.set_parent = clkgena_divmux_set_parent,
+	.round_rate = clkgena_divmux_round_rate,
+	.recalc_rate = clkgena_divmux_recalc_rate,
+	.set_rate = clkgena_divmux_set_rate,
+};
+
+/**
+ * clk_register_genamux - register a genamux clock with the clock framework
+ */
+struct clk *clk_register_genamux(const char *name,
+				const char **parent_names, u8 num_parents,
+				void __iomem *reg,
+				const struct clkgena_divmux_data *muxdata,
+				u32 idx)
+{
+	/*
+	 * Fixed constants across all ClockgenA variants
+	 */
+	const int mux_width = 2;
+	const int divider_width = 5;
+	struct clkgena_divmux *genamux;
+	struct clk *clk;
+	struct clk_init_data init;
+	int i;
+
+	genamux = kzalloc(sizeof(*genamux), GFP_KERNEL);
+	if (!genamux)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &clkgena_divmux_ops;
+	init.flags = CLK_IS_BASIC;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+
+	genamux->mux.lock  = &clkgena_divmux_lock;
+	genamux->mux.mask = BIT(mux_width) - 1;
+	genamux->mux.shift = muxdata->mux_start_bit + (idx * mux_width);
+	if (genamux->mux.shift > 31) {
+		/*
+		 * We have spilled into the second mux register so
+		 * adjust the register address and the bit shift accordingly
+		 */
+		genamux->mux.reg = reg + muxdata->mux_offset2;
+		genamux->mux.shift -= 32;
+	} else {
+		genamux->mux.reg   = reg + muxdata->mux_offset;
+	}
+
+	for (i = 0; i < NUM_INPUTS; i++) {
+		/*
+		 * Divider config for each input
+		 */
+		void __iomem *divbase = reg + muxdata->div_offsets[i];
+		genamux->div[i].width = divider_width;
+		genamux->div[i].reg = divbase + (idx * sizeof(u32));
+
+		/*
+		 * Mux enabled/running feedback register for each input.
+		 */
+		genamux->feedback_reg[i] = reg + muxdata->fb_offsets[i];
+	}
+
+	genamux->feedback_bit_idx = muxdata->fb_start_bit_idx + idx;
+	genamux->hw.init = &init;
+
+	clk = clk_register(NULL, &genamux->hw);
+	if (IS_ERR(clk)) {
+		kfree(genamux);
+		goto err;
+	}
+
+	pr_debug("%s: parent %s rate %lu\n",
+			__clk_get_name(clk),
+			__clk_get_name(clk_get_parent(clk)),
+			clk_get_rate(clk));
+err:
+	return clk;
+}
+
+static struct clkgena_divmux_data st_divmux_c65hs = {
+	.num_outputs = 4,
+	.mux_offset = 0x14,
+	.mux_start_bit = 0,
+	.div_offsets = { 0x800, 0x900, 0xb00 },
+	.fb_offsets = { 0x18, 0x1c, 0x20 },
+	.fb_start_bit_idx = 0,
+};
+
+static struct clkgena_divmux_data st_divmux_c65ls = {
+	.num_outputs = 14,
+	.mux_offset = 0x14,
+	.mux_offset2 = 0x24,
+	.mux_start_bit = 8,
+	.div_offsets = { 0x810, 0xa10, 0xb10 },
+	.fb_offsets = { 0x18, 0x1c, 0x20 },
+	.fb_start_bit_idx = 4,
+};
+
+static struct clkgena_divmux_data st_divmux_c32odf0 = {
+	.num_outputs = 8,
+	.mux_offset = 0x1c,
+	.mux_start_bit = 0,
+	.div_offsets = { 0x800, 0x900, 0xa60 },
+	.fb_offsets = { 0x2c, 0x24, 0x28 },
+	.fb_start_bit_idx = 0,
+};
+
+static struct clkgena_divmux_data st_divmux_c32odf1 = {
+	.num_outputs = 8,
+	.mux_offset = 0x1c,
+	.mux_start_bit = 16,
+	.div_offsets = { 0x820, 0x980, 0xa80 },
+	.fb_offsets = { 0x2c, 0x24, 0x28 },
+	.fb_start_bit_idx = 8,
+};
+
+static struct clkgena_divmux_data st_divmux_c32odf2 = {
+	.num_outputs = 8,
+	.mux_offset = 0x20,
+	.mux_start_bit = 0,
+	.div_offsets = { 0x840, 0xa20, 0xb10 },
+	.fb_offsets = { 0x2c, 0x24, 0x28 },
+	.fb_start_bit_idx = 16,
+};
+
+static struct clkgena_divmux_data st_divmux_c32odf3 = {
+	.num_outputs = 8,
+	.mux_offset = 0x20,
+	.mux_start_bit = 16,
+	.div_offsets = { 0x860, 0xa40, 0xb30 },
+	.fb_offsets = { 0x2c, 0x24, 0x28 },
+	.fb_start_bit_idx = 24,
+};
+
+static struct of_device_id clkgena_divmux_of_match[] = {
+	{
+		.compatible = "st,clkgena-divmux-c65-hs",
+		.data = &st_divmux_c65hs,
+	},
+	{
+		.compatible = "st,clkgena-divmux-c65-ls",
+		.data = &st_divmux_c65ls,
+	},
+	{
+		.compatible = "st,clkgena-divmux-c32-odf0",
+		.data = &st_divmux_c32odf0,
+	},
+	{
+		.compatible = "st,clkgena-divmux-c32-odf1",
+		.data = &st_divmux_c32odf1,
+	},
+	{
+		.compatible = "st,clkgena-divmux-c32-odf2",
+		.data = &st_divmux_c32odf2,
+	},
+	{
+		.compatible = "st,clkgena-divmux-c32-odf3",
+		.data = &st_divmux_c32odf3,
+	},
+	{}
+};
+
+static void __iomem * __init clkgen_get_register_base(
+				struct device_node *np)
+{
+	struct device_node *pnode;
+	void __iomem *reg = NULL;
+
+	pnode = of_get_parent(np);
+	if (!pnode)
+		return NULL;
+
+	reg = of_iomap(pnode, 0);
+
+	of_node_put(pnode);
+	return reg;
+}
+
+void __init st_of_clkgena_divmux_setup(struct device_node *np)
+{
+	const struct of_device_id *match;
+	const struct clkgena_divmux_data *data;
+	struct clk_onecell_data *clk_data;
+	void __iomem *reg;
+	const char **parents;
+	int num_parents = 0, i;
+
+	match = of_match_node(clkgena_divmux_of_match, np);
+	if (WARN_ON(!match))
+		return;
+
+	data = (struct clkgena_divmux_data *)match->data;
+
+	reg = clkgen_get_register_base(np);
+	if (!reg)
+		return;
+
+	parents = clkgen_mux_get_parents(np, &num_parents);
+	if (IS_ERR(parents))
+		return;
+
+	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		goto err;
+
+	clk_data->clk_num = data->num_outputs;
+	clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *),
+				 GFP_KERNEL);
+
+	if (!clk_data->clks)
+		goto err;
+
+	for (i = 0; i < clk_data->clk_num; i++) {
+		struct clk *clk;
+		const char *clk_name;
+
+		if (of_property_read_string_index(np, "clock-output-names",
+						  i, &clk_name))
+			break;
+
+		/*
+		 * If we read an empty clock name then the output is unused
+		 */
+		if (*clk_name == '\0')
+			continue;
+
+		clk = clk_register_genamux(clk_name, parents, num_parents,
+					   reg, data, i);
+
+		if (IS_ERR(clk))
+			goto err;
+
+		clk_data->clks[i] = clk;
+	}
+
+	kfree(parents);
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+	return;
+err:
+	if (clk_data)
+		kfree(clk_data->clks);
+
+	kfree(clk_data);
+	kfree(parents);
+}
+CLK_OF_DECLARE(clkgenadivmux, "st,clkgena-divmux", st_of_clkgena_divmux_setup);
+
+struct clkgena_prediv_data {
+	u32 offset;
+	u8 shift;
+	struct clk_div_table *table;
+};
+
+static struct clk_div_table prediv_table16[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 1, .div = 16 },
+	{ .div = 0 },
+};
+
+static struct clkgena_prediv_data prediv_c65_data = {
+	.offset = 0x4c,
+	.shift = 31,
+	.table = prediv_table16,
+};
+
+static struct clkgena_prediv_data prediv_c32_data = {
+	.offset = 0x50,
+	.shift = 1,
+	.table = prediv_table16,
+};
+
+static struct of_device_id clkgena_prediv_of_match[] = {
+	{ .compatible = "st,clkgena-prediv-c65", .data = &prediv_c65_data },
+	{ .compatible = "st,clkgena-prediv-c32", .data = &prediv_c32_data },
+	{}
+};
+
+void __init st_of_clkgena_prediv_setup(struct device_node *np)
+{
+	const struct of_device_id *match;
+	void __iomem *reg;
+	const char *parent_name, *clk_name;
+	struct clk *clk;
+	struct clkgena_prediv_data *data;
+
+	match = of_match_node(clkgena_prediv_of_match, np);
+	if (!match) {
+		pr_err("%s: No matching data\n", __func__);
+		return;
+	}
+
+	data = (struct clkgena_prediv_data *)match->data;
+
+	reg = clkgen_get_register_base(np);
+	if (!reg)
+		return;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return;
+
+	if (of_property_read_string_index(np, "clock-output-names",
+					  0, &clk_name))
+		return;
+
+	clk = clk_register_divider_table(NULL, clk_name, parent_name, 0,
+					 reg + data->offset, data->shift, 1,
+					 0, data->table, NULL);
+	if (IS_ERR(clk))
+		return;
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	pr_debug("%s: parent %s rate %u\n",
+		__clk_get_name(clk),
+		__clk_get_name(clk_get_parent(clk)),
+		(unsigned int)clk_get_rate(clk));
+
+	return;
+}
+CLK_OF_DECLARE(clkgenaprediv, "st,clkgena-prediv", st_of_clkgena_prediv_setup);
+
+struct clkgen_mux_data {
+	u32 offset;
+	u8 shift;
+	u8 width;
+	spinlock_t *lock;
+	unsigned long clk_flags;
+	u8 mux_flags;
+};
+
+static struct clkgen_mux_data clkgen_mux_c_vcc_hd_416 = {
+	.offset = 0,
+	.shift = 0,
+	.width = 1,
+};
+
+static struct clkgen_mux_data clkgen_mux_f_vcc_fvdp_416 = {
+	.offset = 0,
+	.shift = 0,
+	.width = 1,
+};
+
+static struct clkgen_mux_data clkgen_mux_f_vcc_hva_416 = {
+	.offset = 0,
+	.shift = 0,
+	.width = 1,
+};
+
+static struct clkgen_mux_data clkgen_mux_f_vcc_hd_416 = {
+	.offset = 0,
+	.shift = 16,
+	.width = 1,
+	.lock = &clkgenf_lock,
+};
+
+static struct clkgen_mux_data clkgen_mux_c_vcc_sd_416 = {
+	.offset = 0,
+	.shift = 17,
+	.width = 1,
+	.lock = &clkgenf_lock,
+};
+
+static struct clkgen_mux_data stih415_a9_mux_data = {
+	.offset = 0,
+	.shift = 1,
+	.width = 2,
+};
+static struct clkgen_mux_data stih416_a9_mux_data = {
+	.offset = 0,
+	.shift = 0,
+	.width = 2,
+};
+
+static struct of_device_id mux_of_match[] = {
+	{
+		.compatible = "st,stih416-clkgenc-vcc-hd",
+		.data = &clkgen_mux_c_vcc_hd_416,
+	},
+	{
+		.compatible = "st,stih416-clkgenf-vcc-fvdp",
+		.data = &clkgen_mux_f_vcc_fvdp_416,
+	},
+	{
+		.compatible = "st,stih416-clkgenf-vcc-hva",
+		.data = &clkgen_mux_f_vcc_hva_416,
+	},
+	{
+		.compatible = "st,stih416-clkgenf-vcc-hd",
+		.data = &clkgen_mux_f_vcc_hd_416,
+	},
+	{
+		.compatible = "st,stih416-clkgenf-vcc-sd",
+		.data = &clkgen_mux_c_vcc_sd_416,
+	},
+	{
+		.compatible = "st,stih415-clkgen-a9-mux",
+		.data = &stih415_a9_mux_data,
+	},
+	{
+		.compatible = "st,stih416-clkgen-a9-mux",
+		.data = &stih416_a9_mux_data,
+	},
+	{}
+};
+
+void __init st_of_clkgen_mux_setup(struct device_node *np)
+{
+	const struct of_device_id *match;
+	struct clk *clk;
+	void __iomem *reg;
+	const char **parents;
+	int num_parents;
+	struct clkgen_mux_data *data;
+
+	match = of_match_node(mux_of_match, np);
+	if (!match) {
+		pr_err("%s: No matching data\n", __func__);
+		return;
+	}
+
+	data = (struct clkgen_mux_data *)match->data;
+
+	reg = of_iomap(np, 0);
+	if (!reg) {
+		pr_err("%s: Failed to get base address\n", __func__);
+		return;
+	}
+
+	parents = clkgen_mux_get_parents(np, &num_parents);
+	if (IS_ERR(parents)) {
+		pr_err("%s: Failed to get parents (%ld)\n",
+				__func__, PTR_ERR(parents));
+		return;
+	}
+
+	clk = clk_register_mux(NULL, np->name, parents, num_parents,
+				data->clk_flags | CLK_SET_RATE_PARENT,
+				reg + data->offset,
+				data->shift, data->width, data->mux_flags,
+				data->lock);
+	if (IS_ERR(clk))
+		goto err;
+
+	pr_debug("%s: parent %s rate %u\n",
+			__clk_get_name(clk),
+			__clk_get_name(clk_get_parent(clk)),
+			(unsigned int)clk_get_rate(clk));
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+
+err:
+	kfree(parents);
+
+	return;
+}
+CLK_OF_DECLARE(clkgen_mux, "st,clkgen-mux", st_of_clkgen_mux_setup);
+
+#define VCC_MAX_CHANNELS 16
+
+#define VCC_GATE_OFFSET 0x0
+#define VCC_MUX_OFFSET 0x4
+#define VCC_DIV_OFFSET 0x8
+
+struct clkgen_vcc_data {
+	spinlock_t *lock;
+	unsigned long clk_flags;
+};
+
+static struct clkgen_vcc_data st_clkgenc_vcc_416 = {
+	.clk_flags = CLK_SET_RATE_PARENT,
+};
+
+static struct clkgen_vcc_data st_clkgenf_vcc_416 = {
+	.lock = &clkgenf_lock,
+};
+
+static struct of_device_id vcc_of_match[] = {
+	{ .compatible = "st,stih416-clkgenc", .data = &st_clkgenc_vcc_416 },
+	{ .compatible = "st,stih416-clkgenf", .data = &st_clkgenf_vcc_416 },
+	{}
+};
+
+void __init st_of_clkgen_vcc_setup(struct device_node *np)
+{
+	const struct of_device_id *match;
+	void __iomem *reg;
+	const char **parents;
+	int num_parents, i;
+	struct clk_onecell_data *clk_data;
+	struct clkgen_vcc_data *data;
+
+	match = of_match_node(vcc_of_match, np);
+	if (WARN_ON(!match))
+		return;
+	data = (struct clkgen_vcc_data *)match->data;
+
+	reg = of_iomap(np, 0);
+	if (!reg)
+		return;
+
+	parents = clkgen_mux_get_parents(np, &num_parents);
+	if (IS_ERR(parents))
+		return;
+
+	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		goto err;
+
+	clk_data->clk_num = VCC_MAX_CHANNELS;
+	clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *),
+				 GFP_KERNEL);
+
+	if (!clk_data->clks)
+		goto err;
+
+	for (i = 0; i < clk_data->clk_num; i++) {
+		struct clk *clk;
+		const char *clk_name;
+		struct clk_gate *gate;
+		struct clk_divider *div;
+		struct clk_mux *mux;
+
+		if (of_property_read_string_index(np, "clock-output-names",
+						  i, &clk_name))
+			break;
+
+		/*
+		 * If we read an empty clock name then the output is unused
+		 */
+		if (*clk_name == '\0')
+			continue;
+
+		gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+		if (!gate)
+			break;
+
+		div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
+		if (!div) {
+			kfree(gate);
+			break;
+		}
+
+		mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
+		if (!mux) {
+			kfree(gate);
+			kfree(div);
+			break;
+		}
+
+		gate->reg = reg + VCC_GATE_OFFSET;
+		gate->bit_idx = i;
+		gate->flags = CLK_GATE_SET_TO_DISABLE;
+		gate->lock = data->lock;
+
+		div->reg = reg + VCC_DIV_OFFSET;
+		div->shift = 2 * i;
+		div->width = 2;
+		div->flags = CLK_DIVIDER_POWER_OF_TWO;
+
+		mux->reg = reg + VCC_MUX_OFFSET;
+		mux->shift = 2 * i;
+		mux->mask = 0x3;
+
+		clk = clk_register_composite(NULL, clk_name, parents,
+					     num_parents,
+					     &mux->hw, &clk_mux_ops,
+					     &div->hw, &clk_divider_ops,
+					     &gate->hw, &clk_gate_ops,
+					     data->clk_flags);
+		if (IS_ERR(clk)) {
+			kfree(gate);
+			kfree(div);
+			kfree(mux);
+			goto err;
+		}
+
+		pr_debug("%s: parent %s rate %u\n",
+			__clk_get_name(clk),
+			__clk_get_name(clk_get_parent(clk)),
+			(unsigned int)clk_get_rate(clk));
+
+		clk_data->clks[i] = clk;
+	}
+
+	kfree(parents);
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+	return;
+
+err:
+	for (i = 0; i < clk_data->clk_num; i++) {
+		struct clk_composite *composite;
+
+		if (!clk_data->clks[i])
+			continue;
+
+		composite = container_of(__clk_get_hw(clk_data->clks[i]),
+					 struct clk_composite, hw);
+		kfree(container_of(composite->gate_hw, struct clk_gate, hw));
+		kfree(container_of(composite->rate_hw, struct clk_divider, hw));
+		kfree(container_of(composite->mux_hw, struct clk_mux, hw));
+	}
+
+	if (clk_data)
+		kfree(clk_data->clks);
+
+	kfree(clk_data);
+	kfree(parents);
+}
+CLK_OF_DECLARE(clkgen_vcc, "st,clkgen-vcc", st_of_clkgen_vcc_setup);
diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c
new file mode 100644
index 0000000..bca0a0b
--- /dev/null
+++ b/drivers/clk/st/clkgen-pll.c
@@ -0,0 +1,698 @@
+/*
+ * Copyright (C) 2014 STMicroelectronics (R&D) Limited
+ *
+ * This program 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.
+ *
+ */
+
+/*
+ * Authors:
+ * Stephen Gallimore <stephen.gallimore@st.com>,
+ * Pankaj Dev <pankaj.dev@st.com>.
+ */
+
+#include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/clk-provider.h>
+
+#include "clkgen.h"
+
+static DEFINE_SPINLOCK(clkgena_c32_odf_lock);
+
+/*
+ * Common PLL configuration register bits for PLL800 and PLL1600 C65
+ */
+#define C65_MDIV_PLL800_MASK	(0xff)
+#define C65_MDIV_PLL1600_MASK	(0x7)
+#define C65_NDIV_MASK		(0xff)
+#define C65_PDIV_MASK		(0x7)
+
+/*
+ * PLL configuration register bits for PLL3200 C32
+ */
+#define C32_NDIV_MASK (0xff)
+#define C32_IDF_MASK (0x7)
+#define C32_ODF_MASK (0x3f)
+#define C32_LDF_MASK (0x7f)
+
+#define C32_MAX_ODFS (4)
+
+struct clkgen_pll_data {
+	struct clkgen_field pdn_status;
+	struct clkgen_field locked_status;
+	struct clkgen_field mdiv;
+	struct clkgen_field ndiv;
+	struct clkgen_field pdiv;
+	struct clkgen_field idf;
+	struct clkgen_field ldf;
+	unsigned int num_odfs;
+	struct clkgen_field odf[C32_MAX_ODFS];
+	struct clkgen_field odf_gate[C32_MAX_ODFS];
+	const struct clk_ops *ops;
+};
+
+static const struct clk_ops st_pll1600c65_ops;
+static const struct clk_ops st_pll800c65_ops;
+static const struct clk_ops stm_pll3200c32_ops;
+static const struct clk_ops st_pll1200c32_ops;
+
+static struct clkgen_pll_data st_pll1600c65_ax = {
+	.pdn_status	= CLKGEN_FIELD(0x0, 0x1,			19),
+	.locked_status	= CLKGEN_FIELD(0x0, 0x1,			31),
+	.mdiv		= CLKGEN_FIELD(0x0, C65_MDIV_PLL1600_MASK,	0),
+	.ndiv		= CLKGEN_FIELD(0x0, C65_NDIV_MASK,		8),
+	.ops		= &st_pll1600c65_ops
+};
+
+static struct clkgen_pll_data st_pll800c65_ax = {
+	.pdn_status	= CLKGEN_FIELD(0x0,	0x1,			19),
+	.locked_status	= CLKGEN_FIELD(0x0,	0x1,			31),
+	.mdiv		= CLKGEN_FIELD(0x0,	C65_MDIV_PLL800_MASK,	0),
+	.ndiv		= CLKGEN_FIELD(0x0,	C65_NDIV_MASK,		8),
+	.pdiv		= CLKGEN_FIELD(0x0,	C65_PDIV_MASK,		16),
+	.ops		= &st_pll800c65_ops
+};
+
+static struct clkgen_pll_data st_pll3200c32_a1x_0 = {
+	.pdn_status	= CLKGEN_FIELD(0x0,	0x1,			31),
+	.locked_status	= CLKGEN_FIELD(0x4,	0x1,			31),
+	.ndiv		= CLKGEN_FIELD(0x0,	C32_NDIV_MASK,		0x0),
+	.idf		= CLKGEN_FIELD(0x4,	C32_IDF_MASK,		0x0),
+	.num_odfs = 4,
+	.odf =	{	CLKGEN_FIELD(0x54,	C32_ODF_MASK,		4),
+			CLKGEN_FIELD(0x54,	C32_ODF_MASK,		10),
+			CLKGEN_FIELD(0x54,	C32_ODF_MASK,		16),
+			CLKGEN_FIELD(0x54,	C32_ODF_MASK,		22) },
+	.odf_gate = {	CLKGEN_FIELD(0x54,	0x1,			0),
+			CLKGEN_FIELD(0x54,	0x1,			1),
+			CLKGEN_FIELD(0x54,	0x1,			2),
+			CLKGEN_FIELD(0x54,	0x1,			3) },
+	.ops		= &stm_pll3200c32_ops,
+};
+
+static struct clkgen_pll_data st_pll3200c32_a1x_1 = {
+	.pdn_status	= CLKGEN_FIELD(0xC,	0x1,			31),
+	.locked_status	= CLKGEN_FIELD(0x10,	0x1,			31),
+	.ndiv		= CLKGEN_FIELD(0xC,	C32_NDIV_MASK,		0x0),
+	.idf		= CLKGEN_FIELD(0x10,	C32_IDF_MASK,		0x0),
+	.num_odfs = 4,
+	.odf = {	CLKGEN_FIELD(0x58,	C32_ODF_MASK,		4),
+			CLKGEN_FIELD(0x58,	C32_ODF_MASK,		10),
+			CLKGEN_FIELD(0x58,	C32_ODF_MASK,		16),
+			CLKGEN_FIELD(0x58,	C32_ODF_MASK,		22) },
+	.odf_gate = {	CLKGEN_FIELD(0x58,	0x1,			0),
+			CLKGEN_FIELD(0x58,	0x1,			1),
+			CLKGEN_FIELD(0x58,	0x1,			2),
+			CLKGEN_FIELD(0x58,	0x1,			3) },
+	.ops		= &stm_pll3200c32_ops,
+};
+
+/* 415 specific */
+static struct clkgen_pll_data st_pll3200c32_a9_415 = {
+	.pdn_status	= CLKGEN_FIELD(0x0,	0x1,			0),
+	.locked_status	= CLKGEN_FIELD(0x6C,	0x1,			0),
+	.ndiv		= CLKGEN_FIELD(0x0,	C32_NDIV_MASK,		9),
+	.idf		= CLKGEN_FIELD(0x0,	C32_IDF_MASK,		22),
+	.num_odfs = 1,
+	.odf =		{ CLKGEN_FIELD(0x0,	C32_ODF_MASK,		3) },
+	.odf_gate =	{ CLKGEN_FIELD(0x0,	0x1,			28) },
+	.ops		= &stm_pll3200c32_ops,
+};
+
+static struct clkgen_pll_data st_pll3200c32_ddr_415 = {
+	.pdn_status	= CLKGEN_FIELD(0x0,	0x1,			0),
+	.locked_status	= CLKGEN_FIELD(0x100,	0x1,			0),
+	.ndiv		= CLKGEN_FIELD(0x8,	C32_NDIV_MASK,		0),
+	.idf		= CLKGEN_FIELD(0x0,	C32_IDF_MASK,		25),
+	.num_odfs = 2,
+	.odf		= { CLKGEN_FIELD(0x8,	C32_ODF_MASK,		8),
+			    CLKGEN_FIELD(0x8,	C32_ODF_MASK,		14) },
+	.odf_gate	= { CLKGEN_FIELD(0x4,	0x1,			28),
+			    CLKGEN_FIELD(0x4,	0x1,			29) },
+	.ops		= &stm_pll3200c32_ops,
+};
+
+static struct clkgen_pll_data st_pll1200c32_gpu_415 = {
+	.pdn_status	= CLKGEN_FIELD(0x144,	0x1,			3),
+	.locked_status	= CLKGEN_FIELD(0x168,	0x1,			0),
+	.ldf		= CLKGEN_FIELD(0x0,	C32_LDF_MASK,		3),
+	.idf		= CLKGEN_FIELD(0x0,	C32_IDF_MASK,		0),
+	.num_odfs = 0,
+	.odf		= { CLKGEN_FIELD(0x0,	C32_ODF_MASK,		10) },
+	.ops		= &st_pll1200c32_ops,
+};
+
+/* 416 specific */
+static struct clkgen_pll_data st_pll3200c32_a9_416 = {
+	.pdn_status	= CLKGEN_FIELD(0x0,	0x1,			0),
+	.locked_status	= CLKGEN_FIELD(0x6C,	0x1,			0),
+	.ndiv		= CLKGEN_FIELD(0x8,	C32_NDIV_MASK,		0),
+	.idf		= CLKGEN_FIELD(0x0,	C32_IDF_MASK,		25),
+	.num_odfs = 1,
+	.odf		= { CLKGEN_FIELD(0x8,	C32_ODF_MASK,		8) },
+	.odf_gate	= { CLKGEN_FIELD(0x4,	0x1,			28) },
+	.ops		= &stm_pll3200c32_ops,
+};
+
+static struct clkgen_pll_data st_pll3200c32_ddr_416 = {
+	.pdn_status	= CLKGEN_FIELD(0x0,	0x1,			0),
+	.locked_status	= CLKGEN_FIELD(0x10C,	0x1,			0),
+	.ndiv		= CLKGEN_FIELD(0x8,	C32_NDIV_MASK,		0),
+	.idf		= CLKGEN_FIELD(0x0,	C32_IDF_MASK,		25),
+	.num_odfs = 2,
+	.odf		= { CLKGEN_FIELD(0x8,	C32_ODF_MASK,		8),
+			    CLKGEN_FIELD(0x8,	C32_ODF_MASK,		14) },
+	.odf_gate	= { CLKGEN_FIELD(0x4,	0x1,			28),
+			    CLKGEN_FIELD(0x4,	0x1,			29) },
+	.ops		= &stm_pll3200c32_ops,
+};
+
+static struct clkgen_pll_data st_pll1200c32_gpu_416 = {
+	.pdn_status	= CLKGEN_FIELD(0x8E4,	0x1,			3),
+	.locked_status	= CLKGEN_FIELD(0x90C,	0x1,			0),
+	.ldf		= CLKGEN_FIELD(0x0,	C32_LDF_MASK,		3),
+	.idf		= CLKGEN_FIELD(0x0,	C32_IDF_MASK,		0),
+	.num_odfs = 0,
+	.odf		= { CLKGEN_FIELD(0x0,	C32_ODF_MASK,		10) },
+	.ops		= &st_pll1200c32_ops,
+};
+
+/**
+ * DOC: Clock Generated by PLL, rate set and enabled by bootloader
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parent is (un)prepared
+ * enable - clk_enable/disable only ensures parent is enabled
+ * rate - rate is fixed. No clk_set_rate support
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+/**
+ * PLL clock that is integrated in the ClockGenA instances on the STiH415
+ * and STiH416.
+ *
+ * @hw: handle between common and hardware-specific interfaces.
+ * @type: PLL instance type.
+ * @regs_base: base of the PLL configuration register(s).
+ *
+ */
+struct clkgen_pll {
+	struct clk_hw		hw;
+	struct clkgen_pll_data	*data;
+	void __iomem		*regs_base;
+};
+
+#define to_clkgen_pll(_hw) container_of(_hw, struct clkgen_pll, hw)
+
+static int clkgen_pll_is_locked(struct clk_hw *hw)
+{
+	struct clkgen_pll *pll = to_clkgen_pll(hw);
+	u32 locked = CLKGEN_READ(pll, locked_status);
+
+	return !!locked;
+}
+
+static int clkgen_pll_is_enabled(struct clk_hw *hw)
+{
+	struct clkgen_pll *pll = to_clkgen_pll(hw);
+	u32 poweroff = CLKGEN_READ(pll, pdn_status);
+	return !poweroff;
+}
+
+unsigned long recalc_stm_pll800c65(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clkgen_pll *pll = to_clkgen_pll(hw);
+	unsigned long mdiv, ndiv, pdiv;
+	unsigned long rate;
+	uint64_t res;
+
+	if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw))
+		return 0;
+
+	pdiv = CLKGEN_READ(pll, pdiv);
+	mdiv = CLKGEN_READ(pll, mdiv);
+	ndiv = CLKGEN_READ(pll, ndiv);
+
+	if (!mdiv)
+		mdiv++; /* mdiv=0 or 1 => MDIV=1 */
+
+	res = (uint64_t)2 * (uint64_t)parent_rate * (uint64_t)ndiv;
+	rate = (unsigned long)div64_u64(res, mdiv * (1 << pdiv));
+
+	pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
+
+	return rate;
+
+}
+
+unsigned long recalc_stm_pll1600c65(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clkgen_pll *pll = to_clkgen_pll(hw);
+	unsigned long mdiv, ndiv;
+	unsigned long rate;
+
+	if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw))
+		return 0;
+
+	mdiv = CLKGEN_READ(pll, mdiv);
+	ndiv = CLKGEN_READ(pll, ndiv);
+
+	if (!mdiv)
+		mdiv = 1;
+
+	/* Note: input is divided by 1000 to avoid overflow */
+	rate = ((2 * (parent_rate / 1000) * ndiv) / mdiv) * 1000;
+
+	pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
+
+	return rate;
+}
+
+unsigned long recalc_stm_pll3200c32(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clkgen_pll *pll = to_clkgen_pll(hw);
+	unsigned long ndiv, idf;
+	unsigned long rate = 0;
+
+	if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw))
+		return 0;
+
+	ndiv = CLKGEN_READ(pll, ndiv);
+	idf = CLKGEN_READ(pll, idf);
+
+	if (idf)
+		/* Note: input is divided to avoid overflow */
+		rate = ((2 * (parent_rate/1000) * ndiv) / idf) * 1000;
+
+	pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
+
+	return rate;
+}
+
+unsigned long recalc_stm_pll1200c32(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clkgen_pll *pll = to_clkgen_pll(hw);
+	unsigned long odf, ldf, idf;
+	unsigned long rate;
+
+	if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw))
+		return 0;
+
+	odf = CLKGEN_READ(pll, odf[0]);
+	ldf = CLKGEN_READ(pll, ldf);
+	idf = CLKGEN_READ(pll, idf);
+
+	if (!idf) /* idf==0 means 1 */
+		idf = 1;
+	if (!odf) /* odf==0 means 1 */
+		odf = 1;
+
+	/* Note: input is divided by 1000 to avoid overflow */
+	rate = (((parent_rate / 1000) * ldf) / (odf * idf)) * 1000;
+
+	pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
+
+	return rate;
+}
+
+static const struct clk_ops st_pll1600c65_ops = {
+	.is_enabled	= clkgen_pll_is_enabled,
+	.recalc_rate	= recalc_stm_pll1600c65,
+};
+
+static const struct clk_ops st_pll800c65_ops = {
+	.is_enabled	= clkgen_pll_is_enabled,
+	.recalc_rate	= recalc_stm_pll800c65,
+};
+
+static const struct clk_ops stm_pll3200c32_ops = {
+	.is_enabled	= clkgen_pll_is_enabled,
+	.recalc_rate	= recalc_stm_pll3200c32,
+};
+
+static const struct clk_ops st_pll1200c32_ops = {
+	.is_enabled	= clkgen_pll_is_enabled,
+	.recalc_rate	= recalc_stm_pll1200c32,
+};
+
+static struct clk * __init clkgen_pll_register(const char *parent_name,
+				struct clkgen_pll_data	*pll_data,
+				void __iomem *reg,
+				const char *clk_name)
+{
+	struct clkgen_pll *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = clk_name;
+	init.ops = pll_data->ops;
+
+	init.flags = CLK_IS_BASIC;
+	init.parent_names = &parent_name;
+	init.num_parents  = 1;
+
+	pll->data = pll_data;
+	pll->regs_base = reg;
+	pll->hw.init = &init;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk)) {
+		kfree(pll);
+		return clk;
+	}
+
+	pr_debug("%s: parent %s rate %lu\n",
+			__clk_get_name(clk),
+			__clk_get_name(clk_get_parent(clk)),
+			clk_get_rate(clk));
+
+	return clk;
+}
+
+static struct clk * __init clkgen_c65_lsdiv_register(const char *parent_name,
+						     const char *clk_name)
+{
+	struct clk *clk;
+
+	clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0, 1, 2);
+	if (IS_ERR(clk))
+		return clk;
+
+	pr_debug("%s: parent %s rate %lu\n",
+			__clk_get_name(clk),
+			__clk_get_name(clk_get_parent(clk)),
+			clk_get_rate(clk));
+	return clk;
+}
+
+static void __iomem * __init clkgen_get_register_base(
+				struct device_node *np)
+{
+	struct device_node *pnode;
+	void __iomem *reg = NULL;
+
+	pnode = of_get_parent(np);
+	if (!pnode)
+		return NULL;
+
+	reg = of_iomap(pnode, 0);
+
+	of_node_put(pnode);
+	return reg;
+}
+
+#define CLKGENAx_PLL0_OFFSET 0x0
+#define CLKGENAx_PLL1_OFFSET 0x4
+
+static void __init clkgena_c65_pll_setup(struct device_node *np)
+{
+	const int num_pll_outputs = 3;
+	struct clk_onecell_data *clk_data;
+	const char *parent_name;
+	void __iomem *reg;
+	const char *clk_name;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return;
+
+	reg = clkgen_get_register_base(np);
+	if (!reg)
+		return;
+
+	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		return;
+
+	clk_data->clk_num = num_pll_outputs;
+	clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *),
+				 GFP_KERNEL);
+
+	if (!clk_data->clks)
+		goto err;
+
+	if (of_property_read_string_index(np, "clock-output-names",
+					  0, &clk_name))
+		goto err;
+
+	/*
+	 * PLL0 HS (high speed) output
+	 */
+	clk_data->clks[0] = clkgen_pll_register(parent_name,
+						&st_pll1600c65_ax,
+						reg + CLKGENAx_PLL0_OFFSET,
+						clk_name);
+
+	if (IS_ERR(clk_data->clks[0]))
+		goto err;
+
+	if (of_property_read_string_index(np, "clock-output-names",
+					  1, &clk_name))
+		goto err;
+
+	/*
+	 * PLL0 LS (low speed) output, which is a fixed divide by 2 of the
+	 * high speed output.
+	 */
+	clk_data->clks[1] = clkgen_c65_lsdiv_register(__clk_get_name
+						      (clk_data->clks[0]),
+						      clk_name);
+
+	if (IS_ERR(clk_data->clks[1]))
+		goto err;
+
+	if (of_property_read_string_index(np, "clock-output-names",
+					  2, &clk_name))
+		goto err;
+
+	/*
+	 * PLL1 output
+	 */
+	clk_data->clks[2] = clkgen_pll_register(parent_name,
+						&st_pll800c65_ax,
+						reg + CLKGENAx_PLL1_OFFSET,
+						clk_name);
+
+	if (IS_ERR(clk_data->clks[2]))
+		goto err;
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+	return;
+
+err:
+	kfree(clk_data->clks);
+	kfree(clk_data);
+}
+CLK_OF_DECLARE(clkgena_c65_plls,
+	       "st,clkgena-plls-c65", clkgena_c65_pll_setup);
+
+static struct clk * __init clkgen_odf_register(const char *parent_name,
+					       void * __iomem reg,
+					       struct clkgen_pll_data *pll_data,
+					       int odf,
+					       spinlock_t *odf_lock,
+					       const char *odf_name)
+{
+	struct clk *clk;
+	unsigned long flags;
+	struct clk_gate *gate;
+	struct clk_divider *div;
+
+	flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->flags = CLK_GATE_SET_TO_DISABLE;
+	gate->reg = reg + pll_data->odf_gate[odf].offset;
+	gate->bit_idx = pll_data->odf_gate[odf].shift;
+	gate->lock = odf_lock;
+
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div)
+		return ERR_PTR(-ENOMEM);
+
+	div->flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;
+	div->reg = reg + pll_data->odf[odf].offset;
+	div->shift = pll_data->odf[odf].shift;
+	div->width = fls(pll_data->odf[odf].mask);
+	div->lock = odf_lock;
+
+	clk = clk_register_composite(NULL, odf_name, &parent_name, 1,
+				     NULL, NULL,
+				     &div->hw, &clk_divider_ops,
+				     &gate->hw, &clk_gate_ops,
+				     flags);
+	if (IS_ERR(clk))
+		return clk;
+
+	pr_debug("%s: parent %s rate %lu\n",
+			__clk_get_name(clk),
+			__clk_get_name(clk_get_parent(clk)),
+			clk_get_rate(clk));
+	return clk;
+}
+
+static struct of_device_id c32_pll_of_match[] = {
+	{
+		.compatible = "st,plls-c32-a1x-0",
+		.data = &st_pll3200c32_a1x_0,
+	},
+	{
+		.compatible = "st,plls-c32-a1x-1",
+		.data = &st_pll3200c32_a1x_1,
+	},
+	{
+		.compatible = "st,stih415-plls-c32-a9",
+		.data = &st_pll3200c32_a9_415,
+	},
+	{
+		.compatible = "st,stih415-plls-c32-ddr",
+		.data = &st_pll3200c32_ddr_415,
+	},
+	{
+		.compatible = "st,stih416-plls-c32-a9",
+		.data = &st_pll3200c32_a9_416,
+	},
+	{
+		.compatible = "st,stih416-plls-c32-ddr",
+		.data = &st_pll3200c32_ddr_416,
+	},
+	{}
+};
+
+static void __init clkgen_c32_pll_setup(struct device_node *np)
+{
+	const struct of_device_id *match;
+	struct clk *clk;
+	const char *parent_name, *pll_name;
+	void __iomem *pll_base;
+	int num_odfs, odf;
+	struct clk_onecell_data *clk_data;
+	struct clkgen_pll_data	*data;
+
+	match = of_match_node(c32_pll_of_match, np);
+	if (!match) {
+		pr_err("%s: No matching data\n", __func__);
+		return;
+	}
+
+	data = (struct clkgen_pll_data *) match->data;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return;
+
+	pll_base = clkgen_get_register_base(np);
+	if (!pll_base)
+		return;
+
+	clk = clkgen_pll_register(parent_name, data, pll_base, np->name);
+	if (IS_ERR(clk))
+		return;
+
+	pll_name = __clk_get_name(clk);
+
+	num_odfs = data->num_odfs;
+
+	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		return;
+
+	clk_data->clk_num = num_odfs;
+	clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *),
+				 GFP_KERNEL);
+
+	if (!clk_data->clks)
+		goto err;
+
+	for (odf = 0; odf < num_odfs; odf++) {
+		struct clk *clk;
+		const char *clk_name;
+
+		if (of_property_read_string_index(np, "clock-output-names",
+						  odf, &clk_name))
+			return;
+
+		clk = clkgen_odf_register(pll_name, pll_base, data,
+				odf, &clkgena_c32_odf_lock, clk_name);
+		if (IS_ERR(clk))
+			goto err;
+
+		clk_data->clks[odf] = clk;
+	}
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+	return;
+
+err:
+	kfree(pll_name);
+	kfree(clk_data->clks);
+	kfree(clk_data);
+}
+CLK_OF_DECLARE(clkgen_c32_pll, "st,clkgen-plls-c32", clkgen_c32_pll_setup);
+
+static struct of_device_id c32_gpu_pll_of_match[] = {
+	{
+		.compatible = "st,stih415-gpu-pll-c32",
+		.data = &st_pll1200c32_gpu_415,
+	},
+	{
+		.compatible = "st,stih416-gpu-pll-c32",
+		.data = &st_pll1200c32_gpu_416,
+	},
+};
+
+static void __init clkgengpu_c32_pll_setup(struct device_node *np)
+{
+	const struct of_device_id *match;
+	struct clk *clk;
+	const char *parent_name;
+	void __iomem *reg;
+	const char *clk_name;
+	struct clkgen_pll_data	*data;
+
+	match = of_match_node(c32_gpu_pll_of_match, np);
+	if (!match) {
+		pr_err("%s: No matching data\n", __func__);
+		return;
+	}
+
+	data = (struct clkgen_pll_data *)match->data;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return;
+
+	reg = clkgen_get_register_base(np);
+	if (!reg)
+		return;
+
+	if (of_property_read_string_index(np, "clock-output-names",
+					  0, &clk_name))
+		return;
+
+	/*
+	 * PLL 1200MHz output
+	 */
+	clk = clkgen_pll_register(parent_name, data, reg, clk_name);
+
+	if (!IS_ERR(clk))
+		of_clk_add_provider(np, of_clk_src_simple_get, clk);
+
+	return;
+}
+CLK_OF_DECLARE(clkgengpu_c32_pll,
+	       "st,clkgengpu-pll-c32", clkgengpu_c32_pll_setup);
diff --git a/drivers/clk/st/clkgen.h b/drivers/clk/st/clkgen.h
new file mode 100644
index 0000000..35c8632
--- /dev/null
+++ b/drivers/clk/st/clkgen.h
@@ -0,0 +1,48 @@
+/************************************************************************
+File  : Clock H/w specific Information
+
+Author: Pankaj Dev <pankaj.dev@st.com>
+
+Copyright (C) 2014 STMicroelectronics
+************************************************************************/
+
+#ifndef __CLKGEN_INFO_H
+#define __CLKGEN_INFO_H
+
+struct clkgen_field {
+	unsigned int offset;
+	unsigned int mask;
+	unsigned int shift;
+};
+
+static inline unsigned long clkgen_read(void __iomem	*base,
+					  struct clkgen_field *field)
+{
+	return (readl(base + field->offset) >> field->shift) & field->mask;
+}
+
+
+static inline void clkgen_write(void __iomem *base, struct clkgen_field *field,
+				  unsigned long val)
+{
+	writel((readl(base + field->offset) &
+	       ~(field->mask << field->shift)) | (val << field->shift),
+	       base + field->offset);
+
+	return;
+}
+
+#define CLKGEN_FIELD(_offset, _mask, _shift) {		\
+				.offset	= _offset,	\
+				.mask	= _mask,	\
+				.shift	= _shift,	\
+				}
+
+#define CLKGEN_READ(pll, field) clkgen_read(pll->regs_base, \
+		&pll->data->field)
+
+#define CLKGEN_WRITE(pll, field, val) clkgen_write(pll->regs_base, \
+		&pll->data->field, val)
+
+#endif /*__CLKGEN_INFO_H*/
+
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index abb6c5a..bd7dc73 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -18,6 +18,7 @@
 #include <linux/clkdev.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/reset-controller.h>
 
 #include "clk-factors.h"
 
@@ -51,6 +52,8 @@
 	if (!gate)
 		goto err_free_fixed;
 
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
 	/* set up gate and fixed rate properties */
 	gate->reg = of_iomap(node, 0);
 	gate->bit_idx = SUNXI_OSC24M_GATE;
@@ -77,7 +80,7 @@
 err_free_fixed:
 	kfree(fixed);
 }
-CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-osc-clk", sun4i_osc_clk_setup);
+CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-a10-osc-clk", sun4i_osc_clk_setup);
 
 
 
@@ -249,7 +252,38 @@
 	*n = DIV_ROUND_UP(div, (*k+1));
 }
 
+/**
+ * sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6
+ * PLL6 rate is calculated as follows
+ * rate = parent_rate * n * (k + 1) / 2
+ * parent_rate is always 24Mhz
+ */
 
+static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate,
+				       u8 *n, u8 *k, u8 *m, u8 *p)
+{
+	u8 div;
+
+	/*
+	 * We always have 24MHz / 2, so we can just say that our
+	 * parent clock is 12MHz.
+	 */
+	parent_rate = parent_rate / 2;
+
+	/* Normalize value to a parent_rate multiple (24M / 2) */
+	div = *freq / parent_rate;
+	*freq = parent_rate * div;
+
+	/* we were called to round the frequency, we can now return */
+	if (n == NULL)
+		return;
+
+	*k = div / 32;
+	if (*k > 3)
+		*k = 3;
+
+	*n = DIV_ROUND_UP(div, (*k+1));
+}
 
 /**
  * sun4i_get_apb1_factors() - calculates m, p factors for APB1
@@ -265,7 +299,7 @@
 	if (parent_rate < *freq)
 		*freq = parent_rate;
 
-	parent_rate = (parent_rate + (*freq - 1)) / *freq;
+	parent_rate = DIV_ROUND_UP(parent_rate, *freq);
 
 	/* Invalid rate! */
 	if (parent_rate > 32)
@@ -296,7 +330,7 @@
 
 /**
  * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks
- * MMC rate is calculated as follows
+ * MOD0 rate is calculated as follows
  * rate = (parent_rate >> p) / (m + 1);
  */
 
@@ -310,7 +344,7 @@
 	if (*freq > parent_rate)
 		*freq = parent_rate;
 
-	div = parent_rate / *freq;
+	div = DIV_ROUND_UP(parent_rate, *freq);
 
 	if (div < 16)
 		calcp = 0;
@@ -351,7 +385,7 @@
 	if (*freq > parent_rate)
 		*freq = parent_rate;
 
-	div = parent_rate / *freq;
+	div = DIV_ROUND_UP(parent_rate, *freq);
 
 	if (div < 32)
 		calcp = 0;
@@ -377,6 +411,102 @@
 
 
 /**
+ * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module
+ *
+ * This clock looks something like this
+ *                               ________________________
+ *  MII TX clock from PHY >-----|___________    _________|----> to GMAC core
+ *  GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY
+ *  Ext. 125MHz RGMII TX clk >--|__divider__/            |
+ *                              |________________________|
+ *
+ * The external 125 MHz reference is optional, i.e. GMAC can use its
+ * internal TX clock just fine. The A31 GMAC clock module does not have
+ * the divider controls for the external reference.
+ *
+ * To keep it simple, let the GMAC use either the MII TX clock for MII mode,
+ * and its internal TX clock for GMII and RGMII modes. The GMAC driver should
+ * select the appropriate source and gate/ungate the output to the PHY.
+ *
+ * Only the GMAC should use this clock. Altering the clock so that it doesn't
+ * match the GMAC's operation parameters will result in the GMAC not being
+ * able to send traffic out. The GMAC driver should set the clock rate and
+ * enable/disable this clock to configure the required state. The clock
+ * driver then responds by auto-reparenting the clock.
+ */
+
+#define SUN7I_A20_GMAC_GPIT	2
+#define SUN7I_A20_GMAC_MASK	0x3
+#define SUN7I_A20_GMAC_PARENTS	2
+
+static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
+{
+	struct clk *clk;
+	struct clk_mux *mux;
+	struct clk_gate *gate;
+	const char *clk_name = node->name;
+	const char *parents[SUN7I_A20_GMAC_PARENTS];
+	void *reg;
+
+	if (of_property_read_string(node, "clock-output-names", &clk_name))
+		return;
+
+	/* allocate mux and gate clock structs */
+	mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
+	if (!mux)
+		return;
+
+	gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+	if (!gate)
+		goto free_mux;
+
+	/* gmac clock requires exactly 2 parents */
+	parents[0] = of_clk_get_parent_name(node, 0);
+	parents[1] = of_clk_get_parent_name(node, 1);
+	if (!parents[0] || !parents[1])
+		goto free_gate;
+
+	reg = of_iomap(node, 0);
+	if (!reg)
+		goto free_gate;
+
+	/* set up gate and fixed rate properties */
+	gate->reg = reg;
+	gate->bit_idx = SUN7I_A20_GMAC_GPIT;
+	gate->lock = &clk_lock;
+	mux->reg = reg;
+	mux->mask = SUN7I_A20_GMAC_MASK;
+	mux->flags = CLK_MUX_INDEX_BIT;
+	mux->lock = &clk_lock;
+
+	clk = clk_register_composite(NULL, clk_name,
+			parents, SUN7I_A20_GMAC_PARENTS,
+			&mux->hw, &clk_mux_ops,
+			NULL, NULL,
+			&gate->hw, &clk_gate_ops,
+			0);
+
+	if (IS_ERR(clk))
+		goto iounmap_reg;
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	clk_register_clkdev(clk, clk_name, NULL);
+
+	return;
+
+iounmap_reg:
+	iounmap(reg);
+free_gate:
+	kfree(gate);
+free_mux:
+	kfree(mux);
+}
+CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
+		sun7i_a20_gmac_clk_setup);
+
+
+
+/**
  * sunxi_factors_clk_setup() - Setup function for factor clocks
  */
 
@@ -387,6 +517,7 @@
 	int mux;
 	struct clk_factors_config *table;
 	void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
+	const char *name;
 };
 
 static struct clk_factors_config sun4i_pll1_config = {
@@ -416,6 +547,13 @@
 	.kwidth = 2,
 };
 
+static struct clk_factors_config sun6i_a31_pll6_config = {
+	.nshift	= 8,
+	.nwidth = 5,
+	.kshift = 4,
+	.kwidth = 2,
+};
+
 static struct clk_factors_config sun4i_apb1_config = {
 	.mshift = 0,
 	.mwidth = 5,
@@ -451,10 +589,30 @@
 	.getter = sun6i_a31_get_pll1_factors,
 };
 
+static const struct factors_data sun7i_a20_pll4_data __initconst = {
+	.enable = 31,
+	.table = &sun4i_pll5_config,
+	.getter = sun4i_get_pll5_factors,
+};
+
 static const struct factors_data sun4i_pll5_data __initconst = {
 	.enable = 31,
 	.table = &sun4i_pll5_config,
 	.getter = sun4i_get_pll5_factors,
+	.name = "pll5",
+};
+
+static const struct factors_data sun4i_pll6_data __initconst = {
+	.enable = 31,
+	.table = &sun4i_pll5_config,
+	.getter = sun4i_get_pll5_factors,
+	.name = "pll6",
+};
+
+static const struct factors_data sun6i_a31_pll6_data __initconst = {
+	.enable = 31,
+	.table = &sun6i_a31_pll6_config,
+	.getter = sun6i_a31_get_pll6_factors,
 };
 
 static const struct factors_data sun4i_apb1_data __initconst = {
@@ -497,14 +655,14 @@
 	       (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
 		i++;
 
-	/* Nodes should be providing the name via clock-output-names
-	 * but originally our dts didn't, and so we used node->name.
-	 * The new, better nodes look like clk@deadbeef, so we pull the
-	 * name just in this case */
-	if (!strcmp("clk", clk_name)) {
-		of_property_read_string_index(node, "clock-output-names",
-					      0, &clk_name);
-	}
+	/*
+	 * some factor clocks, such as pll5 and pll6, may have multiple
+	 * outputs, and have their name designated in factors_data
+	 */
+	if (data->name)
+		clk_name = data->name;
+	else
+		of_property_read_string(node, "clock-output-names", &clk_name);
 
 	factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
 	if (!factors)
@@ -601,6 +759,8 @@
 	       (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
 		i++;
 
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
 	clk = clk_register_mux(NULL, clk_name, parents, i,
 			       CLK_SET_RATE_NO_REPARENT, reg,
 			       data->shift, SUNXI_MUX_GATE_WIDTH,
@@ -660,6 +820,8 @@
 
 	clk_parent = of_clk_get_parent_name(node, 0);
 
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
 	clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
 				   reg, data->shift, data->width,
 				   data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0,
@@ -673,6 +835,59 @@
 
 
 /**
+ * sunxi_gates_reset... - reset bits in leaf gate clk registers handling
+ */
+
+struct gates_reset_data {
+	void __iomem			*reg;
+	spinlock_t			*lock;
+	struct reset_controller_dev	rcdev;
+};
+
+static int sunxi_gates_reset_assert(struct reset_controller_dev *rcdev,
+			      unsigned long id)
+{
+	struct gates_reset_data *data = container_of(rcdev,
+						     struct gates_reset_data,
+						     rcdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(data->lock, flags);
+
+	reg = readl(data->reg);
+	writel(reg & ~BIT(id), data->reg);
+
+	spin_unlock_irqrestore(data->lock, flags);
+
+	return 0;
+}
+
+static int sunxi_gates_reset_deassert(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	struct gates_reset_data *data = container_of(rcdev,
+						     struct gates_reset_data,
+						     rcdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(data->lock, flags);
+
+	reg = readl(data->reg);
+	writel(reg | BIT(id), data->reg);
+
+	spin_unlock_irqrestore(data->lock, flags);
+
+	return 0;
+}
+
+static struct reset_control_ops sunxi_gates_reset_ops = {
+	.assert		= sunxi_gates_reset_assert,
+	.deassert	= sunxi_gates_reset_deassert,
+};
+
+/**
  * sunxi_gates_clk_setup() - Setup function for leaf gates on clocks
  */
 
@@ -680,6 +895,7 @@
 
 struct gates_data {
 	DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);
+	u32 reset_mask;
 };
 
 static const struct gates_data sun4i_axi_gates_data __initconst = {
@@ -746,10 +962,21 @@
 	.mask = { 0xff80ff },
 };
 
+static const struct gates_data sun4i_a10_usb_gates_data __initconst = {
+	.mask = {0x1C0},
+	.reset_mask = 0x07,
+};
+
+static const struct gates_data sun5i_a13_usb_gates_data __initconst = {
+	.mask = {0x140},
+	.reset_mask = 0x03,
+};
+
 static void __init sunxi_gates_clk_setup(struct device_node *node,
 					 struct gates_data *data)
 {
 	struct clk_onecell_data *clk_data;
+	struct gates_reset_data *reset_data;
 	const char *clk_parent;
 	const char *clk_name;
 	void *reg;
@@ -793,6 +1020,21 @@
 	clk_data->clk_num = i;
 
 	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	/* Register a reset controler for gates with reset bits */
+	if (data->reset_mask == 0)
+		return;
+
+	reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
+	if (!reset_data)
+		return;
+
+	reset_data->reg = reg;
+	reset_data->lock = &clk_lock;
+	reset_data->rcdev.nr_resets = __fls(data->reset_mask) + 1;
+	reset_data->rcdev.ops = &sunxi_gates_reset_ops;
+	reset_data->rcdev.of_node = node;
+	reset_controller_register(&reset_data->rcdev);
 }
 
 
@@ -832,7 +1074,7 @@
 };
 
 static const struct divs_data pll6_divs_data __initconst = {
-	.factors = &sun4i_pll5_data,
+	.factors = &sun4i_pll6_data,
 	.div = {
 		{ .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */
 		{ .fixed = 2 }, /* P, other */
@@ -854,7 +1096,7 @@
 					struct divs_data *data)
 {
 	struct clk_onecell_data *clk_data;
-	const char *parent  = node->name;
+	const char *parent;
 	const char *clk_name;
 	struct clk **clks, *pclk;
 	struct clk_hw *gate_hw, *rate_hw;
@@ -868,6 +1110,7 @@
 
 	/* Set up factor clock that we will be dividing */
 	pclk = sunxi_factors_clk_setup(node, data->factors);
+	parent = __clk_get_name(pclk);
 
 	reg = of_iomap(node, 0);
 
@@ -970,56 +1213,60 @@
 
 /* Matches for factors clocks */
 static const struct of_device_id clk_factors_match[] __initconst = {
-	{.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,},
+	{.compatible = "allwinner,sun4i-a10-pll1-clk", .data = &sun4i_pll1_data,},
 	{.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
-	{.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,},
-	{.compatible = "allwinner,sun4i-mod0-clk", .data = &sun4i_mod0_data,},
+	{.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,},
+	{.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,},
+	{.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,},
+	{.compatible = "allwinner,sun4i-a10-mod0-clk", .data = &sun4i_mod0_data,},
 	{.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,},
 	{}
 };
 
 /* Matches for divider clocks */
 static const struct of_device_id clk_div_match[] __initconst = {
-	{.compatible = "allwinner,sun4i-axi-clk", .data = &sun4i_axi_data,},
-	{.compatible = "allwinner,sun4i-ahb-clk", .data = &sun4i_ahb_data,},
-	{.compatible = "allwinner,sun4i-apb0-clk", .data = &sun4i_apb0_data,},
+	{.compatible = "allwinner,sun4i-a10-axi-clk", .data = &sun4i_axi_data,},
+	{.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,},
+	{.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,},
 	{.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,},
 	{}
 };
 
 /* Matches for divided outputs */
 static const struct of_device_id clk_divs_match[] __initconst = {
-	{.compatible = "allwinner,sun4i-pll5-clk", .data = &pll5_divs_data,},
-	{.compatible = "allwinner,sun4i-pll6-clk", .data = &pll6_divs_data,},
+	{.compatible = "allwinner,sun4i-a10-pll5-clk", .data = &pll5_divs_data,},
+	{.compatible = "allwinner,sun4i-a10-pll6-clk", .data = &pll6_divs_data,},
 	{}
 };
 
 /* Matches for mux clocks */
 static const struct of_device_id clk_mux_match[] __initconst = {
-	{.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,},
-	{.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &sun4i_apb1_mux_data,},
+	{.compatible = "allwinner,sun4i-a10-cpu-clk", .data = &sun4i_cpu_mux_data,},
+	{.compatible = "allwinner,sun4i-a10-apb1-mux-clk", .data = &sun4i_apb1_mux_data,},
 	{.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,},
 	{}
 };
 
 /* Matches for gate clocks */
 static const struct of_device_id clk_gates_match[] __initconst = {
-	{.compatible = "allwinner,sun4i-axi-gates-clk", .data = &sun4i_axi_gates_data,},
-	{.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,},
+	{.compatible = "allwinner,sun4i-a10-axi-gates-clk", .data = &sun4i_axi_gates_data,},
+	{.compatible = "allwinner,sun4i-a10-ahb-gates-clk", .data = &sun4i_ahb_gates_data,},
 	{.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,},
 	{.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
 	{.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,},
 	{.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,},
-	{.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
+	{.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
 	{.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,},
 	{.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
 	{.compatible = "allwinner,sun7i-a20-apb0-gates-clk", .data = &sun7i_a20_apb0_gates_data,},
-	{.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &sun4i_apb1_gates_data,},
+	{.compatible = "allwinner,sun4i-a10-apb1-gates-clk", .data = &sun4i_apb1_gates_data,},
 	{.compatible = "allwinner,sun5i-a10s-apb1-gates-clk", .data = &sun5i_a10s_apb1_gates_data,},
 	{.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
 	{.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,},
 	{.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,},
 	{.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
+	{.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,},
+	{.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,},
 	{}
 };
 
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
index 356e9b8..9e899c18 100644
--- a/drivers/clk/tegra/clk-periph.c
+++ b/drivers/clk/tegra/clk-periph.c
@@ -130,7 +130,7 @@
 	.disable = clk_periph_disable,
 };
 
-const struct clk_ops tegra_clk_periph_no_gate_ops = {
+static const struct clk_ops tegra_clk_periph_no_gate_ops = {
 	.get_parent = clk_periph_get_parent,
 	.set_parent = clk_periph_set_parent,
 	.recalc_rate = clk_periph_recalc_rate,
diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c
index 776ee45..028b337 100644
--- a/drivers/clk/ti/clk-33xx.c
+++ b/drivers/clk/ti/clk-33xx.c
@@ -34,7 +34,6 @@
 	DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"),
 	DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"),
 	DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"),
-	DT_CLK("cpu0", NULL, "dpll_mpu_ck"),
 	DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"),
 	DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"),
 	DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"),
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c
index a15e445..e6aa10d 100644
--- a/drivers/clk/ti/divider.c
+++ b/drivers/clk/ti/divider.c
@@ -112,7 +112,7 @@
 		return parent_rate;
 	}
 
-	return parent_rate / div;
+	return DIV_ROUND_UP(parent_rate, div);
 }
 
 /*
@@ -182,7 +182,7 @@
 		}
 		parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
 				MULT_ROUND_UP(rate, i));
-		now = parent_rate / i;
+		now = DIV_ROUND_UP(parent_rate, i);
 		if (now <= rate && now > best) {
 			bestdiv = i;
 			best = now;
@@ -205,7 +205,7 @@
 	int div;
 	div = ti_clk_divider_bestdiv(hw, rate, prate);
 
-	return *prate / div;
+	return DIV_ROUND_UP(*prate, div);
 }
 
 static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -216,7 +216,7 @@
 	unsigned long flags = 0;
 	u32 val;
 
-	div = parent_rate / rate;
+	div = DIV_ROUND_UP(parent_rate, rate);
 	value = _get_val(divider, div);
 
 	if (value > div_mask(divider))
diff --git a/drivers/clk/ux500/u8500_of_clk.c b/drivers/clk/ux500/u8500_of_clk.c
index cdeff29..7b55ef8 100644
--- a/drivers/clk/ux500/u8500_of_clk.c
+++ b/drivers/clk/ux500/u8500_of_clk.c
@@ -29,7 +29,8 @@
 #define PRCC_KCLK_STORE(clk, base, bit)        \
 	prcc_kclk[(base * PRCC_PERIPHS_PER_CLUSTER) + bit] = clk
 
-struct clk *ux500_twocell_get(struct of_phandle_args *clkspec, void *data)
+static struct clk *ux500_twocell_get(struct of_phandle_args *clkspec,
+				     void *data)
 {
 	struct clk **clk_data = data;
 	unsigned int base, bit;
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c
index c812b93..52c09af 100644
--- a/drivers/clk/zynq/clkc.c
+++ b/drivers/clk/zynq/clkc.c
@@ -149,7 +149,7 @@
 	clks[fclk] = clk_register_gate(NULL, clk_name,
 			div1_name, CLK_SET_RATE_PARENT, fclk_gate_reg,
 			0, CLK_GATE_SET_TO_DISABLE, fclk_gate_lock);
-	enable_reg = readl(fclk_gate_reg) & 1;
+	enable_reg = clk_readl(fclk_gate_reg) & 1;
 	if (enable && !enable_reg) {
 		if (clk_prepare_enable(clks[fclk]))
 			pr_warn("%s: FCLK%u enable failed\n", __func__,
@@ -278,7 +278,7 @@
 			SLCR_IOPLL_CTRL, 4, 1, 0, &iopll_lock);
 
 	/* CPU clocks */
-	tmp = readl(SLCR_621_TRUE) & 1;
+	tmp = clk_readl(SLCR_621_TRUE) & 1;
 	clk = clk_register_mux(NULL, "cpu_mux", cpu_parents, 4,
 			CLK_SET_RATE_NO_REPARENT, SLCR_ARM_CLK_CTRL, 4, 2, 0,
 			&armclk_lock);
diff --git a/drivers/clk/zynq/pll.c b/drivers/clk/zynq/pll.c
index 3226f54..cec9759 100644
--- a/drivers/clk/zynq/pll.c
+++ b/drivers/clk/zynq/pll.c
@@ -90,7 +90,7 @@
 	 * makes probably sense to redundantly save fbdiv in the struct
 	 * zynq_pll to save the IO access.
 	 */
-	fbdiv = (readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >>
+	fbdiv = (clk_readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >>
 			PLLCTRL_FBDIV_SHIFT;
 
 	return parent_rate * fbdiv;
@@ -112,7 +112,7 @@
 
 	spin_lock_irqsave(clk->lock, flags);
 
-	reg = readl(clk->pll_ctrl);
+	reg = clk_readl(clk->pll_ctrl);
 
 	spin_unlock_irqrestore(clk->lock, flags);
 
@@ -138,10 +138,10 @@
 	/* Power up PLL and wait for lock */
 	spin_lock_irqsave(clk->lock, flags);
 
-	reg = readl(clk->pll_ctrl);
+	reg = clk_readl(clk->pll_ctrl);
 	reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK);
-	writel(reg, clk->pll_ctrl);
-	while (!(readl(clk->pll_status) & (1 << clk->lockbit)))
+	clk_writel(reg, clk->pll_ctrl);
+	while (!(clk_readl(clk->pll_status) & (1 << clk->lockbit)))
 		;
 
 	spin_unlock_irqrestore(clk->lock, flags);
@@ -168,9 +168,9 @@
 	/* shut down PLL */
 	spin_lock_irqsave(clk->lock, flags);
 
-	reg = readl(clk->pll_ctrl);
+	reg = clk_readl(clk->pll_ctrl);
 	reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK;
-	writel(reg, clk->pll_ctrl);
+	clk_writel(reg, clk->pll_ctrl);
 
 	spin_unlock_irqrestore(clk->lock, flags);
 }
@@ -225,9 +225,9 @@
 
 	spin_lock_irqsave(pll->lock, flags);
 
-	reg = readl(pll->pll_ctrl);
+	reg = clk_readl(pll->pll_ctrl);
 	reg &= ~PLLCTRL_BPQUAL_MASK;
-	writel(reg, pll->pll_ctrl);
+	clk_writel(reg, pll->pll_ctrl);
 
 	spin_unlock_irqrestore(pll->lock, flags);
 
diff --git a/include/dt-bindings/clock/hi3620-clock.h b/include/dt-bindings/clock/hi3620-clock.h
index 6eaa6a4..21b9d0e 100644
--- a/include/dt-bindings/clock/hi3620-clock.h
+++ b/include/dt-bindings/clock/hi3620-clock.h
@@ -147,6 +147,11 @@
 #define HI3620_MMC_CLK3		217
 #define HI3620_MCU_CLK		218
 
+#define HI3620_SD_CIUCLK	0
+#define HI3620_MMC_CIUCLK1	1
+#define HI3620_MMC_CIUCLK2	2
+#define HI3620_MMC_CIUCLK3	3
+
 #define HI3620_NR_CLKS		219
 
 #endif	/* __DTS_HI3620_CLOCK_H */
diff --git a/include/dt-bindings/clock/hip04-clock.h b/include/dt-bindings/clock/hip04-clock.h
new file mode 100644
index 0000000..695e61c
--- /dev/null
+++ b/include/dt-bindings/clock/hip04-clock.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013-2014 Hisilicon Limited.
+ * Copyright (c) 2013-2014 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef __DTS_HIP04_CLOCK_H
+#define __DTS_HIP04_CLOCK_H
+
+#define HIP04_NONE_CLOCK	0
+
+/* fixed rate & fixed factor clocks */
+#define HIP04_OSC50M		1
+#define HIP04_CLK_50M		2
+#define HIP04_CLK_168M		3
+
+#define HIP04_NR_CLKS		64
+
+#endif	/* __DTS_HIP04_CLOCK_H */
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 939533d..5119174 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -32,6 +32,7 @@
 #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
 
 struct clk_hw;
+struct dentry;
 
 /**
  * struct clk_ops -  Callback operations for hardware clocks; these are to
@@ -127,6 +128,12 @@
  *		separately via calls to .set_parent and .set_rate.
  *		Returns 0 on success, -EERROR otherwise.
  *
+ * @debug_init:	Set up type-specific debugfs entries for this clock.  This
+ *		is called once, after the debugfs directory entry for this
+ *		clock has been created.  The dentry pointer representing that
+ *		directory is provided as an argument.  Called with
+ *		prepare_lock held.  Returns 0 on success, -EERROR otherwise.
+ *
  *
  * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
  * implementations to split any work between atomic (enable) and sleepable
@@ -165,6 +172,7 @@
 	unsigned long	(*recalc_accuracy)(struct clk_hw *hw,
 					   unsigned long parent_accuracy);
 	void		(*init)(struct clk_hw *hw);
+	int		(*debug_init)(struct clk_hw *hw, struct dentry *dentry);
 };
 
 /**
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 0dd9114..fb5e097 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -78,8 +78,22 @@
 	unsigned long		new_rate;
 };
 
+/**
+ * clk_notifier_register: register a clock rate-change notifier callback
+ * @clk: clock whose rate we are interested in
+ * @nb: notifier block with callback function pointer
+ *
+ * ProTip: debugging across notifier chains can be frustrating. Make sure that
+ * your notifier callback function prints a nice big warning in case of
+ * failure.
+ */
 int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
 
+/**
+ * clk_notifier_unregister: unregister a clock rate-change notifier callback
+ * @clk: clock whose rate we are no longer interested in
+ * @nb: notifier block which will be unregistered
+ */
 int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
 
 /**