Merge tag 'sunxi-clocks-for-4.7' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into clk-next

Pull Allwinner clock driver updates from Maxime Ripard:

As usual, a bunch of clocks patches for 4.7, mostly fixes and cleanups, and
display-related clocks.

* tag 'sunxi-clocks-for-4.7' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux:
  clk: sunxi: Let divs clocks read the base factor clock name from devicetree
  clk: sunxi: Add TCON channel1 clock
  clk: sunxi: Add PLL3 clock
  dt-bindings: clk: sun5i: add DRAM gates compatible
  clk: sunxi: Use resource_size
  clk: sunxi: Add sun6i/8i display support
  clk: sunxi: mod1 clock should modify it's parent
diff --git a/Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt b/Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt
new file mode 100644
index 0000000..8968371
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt
@@ -0,0 +1,35 @@
+Marvell Armada AP806 System Controller
+======================================
+
+The AP806 is one of the two core HW blocks of the Marvell Armada 7K/8K
+SoCs. It contains a system controller, which provides a number
+registers giving access to numerous features: clocks, pin-muxing and
+many other SoC configuration items. This DT binding allows to describe
+this system controller.
+
+The Device Tree node representing the AP806 system controller provides
+a number of clocks:
+
+ - 0: clock of CPU cluster 0
+ - 1: clock of CPU cluster 1
+ - 2: fixed PLL at 1200 Mhz
+ - 3: MSS clock, derived from the fixed PLL
+
+Required properties:
+
+ - compatible: must be:
+     "marvell,ap806-system-controller", "syscon"
+ - reg: register area of the AP806 system controller
+ - #clock-cells: must be set to 1
+ - clock-output-names: must be defined to:
+    "ap-cpu-cluster-0", "ap-cpu-cluster-1", "ap-fixed", "ap-mss"
+
+Example:
+
+	syscon: system-controller@6f4000 {
+		compatible = "marvell,ap806-system-controller", "syscon";
+		#clock-cells = <1>;
+		clock-output-names = "ap-cpu-cluster-0", "ap-cpu-cluster-1",
+				     "ap-fixed", "ap-mss";
+		reg = <0x6f4000 0x1000>;
+	};
diff --git a/Documentation/devicetree/bindings/clock/artpec6.txt b/Documentation/devicetree/bindings/clock/artpec6.txt
new file mode 100644
index 0000000..dff9cdf
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/artpec6.txt
@@ -0,0 +1,41 @@
+* Clock bindings for Axis ARTPEC-6 chip
+
+The bindings are based on the clock provider binding in
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+External clocks:
+----------------
+
+There are two external inputs to the main clock controller which should be
+provided using the common clock bindings.
+- "sys_refclk": External 50 Mhz oscillator (required)
+- "i2s_refclk": Alternate audio reference clock (optional).
+
+Main clock controller
+---------------------
+
+Required properties:
+- #clock-cells: Should be <1>
+  See dt-bindings/clock/axis,artpec6-clkctrl.h for the list of valid identifiers.
+- compatible: Should be "axis,artpec6-clkctrl"
+- reg: Must contain the base address and length of the system controller
+- clocks:  Must contain a phandle entry for each clock in clock-names
+- clock-names: Must include the external oscillator ("sys_refclk"). Optional
+  ones are the audio reference clock ("i2s_refclk") and the audio fractional
+  dividers ("frac_clk0" and "frac_clk1").
+
+Examples:
+
+ext_clk: ext_clk {
+	#clock-cells = <0>;
+	compatible = "fixed-clock";
+	clock-frequency = <50000000>;
+};
+
+clkctrl: clkctrl@f8000000 {
+	#clock-cells = <1>;
+	compatible = "axis,artpec6-clkctrl";
+	reg = <0xf8000000 0x48>;
+	clocks = <&ext_clk>;
+	clock-names = "sys_refclk";
+};
diff --git a/Documentation/devicetree/bindings/clock/oxnas,stdclk.txt b/Documentation/devicetree/bindings/clock/oxnas,stdclk.txt
new file mode 100644
index 0000000..208cca6
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/oxnas,stdclk.txt
@@ -0,0 +1,35 @@
+Oxford Semiconductor OXNAS SoC Family Standard Clocks
+================================================
+
+Please also refer to clock-bindings.txt in this directory for common clock
+bindings usage.
+
+Required properties:
+- compatible: Should be "oxsemi,ox810se-stdclk"
+- #clock-cells: 1, see below
+
+Parent node should have the following properties :
+- compatible: Should be "oxsemi,ox810se-sys-ctrl", "syscon", "simple-mfd"
+
+For OX810SE, the clock indices are :
+ - 0: LEON
+ - 1: DMA_SGDMA
+ - 2: CIPHER
+ - 3: SATA
+ - 4: AUDIO
+ - 5: USBMPH
+ - 6: ETHA
+ - 7: PCIA
+ - 8: NAND
+
+example:
+
+sys: sys-ctrl@000000 {
+	compatible = "oxsemi,ox810se-sys-ctrl", "syscon", "simple-mfd";
+	reg = <0x000000 0x100000>;
+
+	stdclk: stdclk {
+		compatible = "oxsemi,ox810se-stdclk";
+		#clock-cells = <1>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt
new file mode 100644
index 0000000..3888dd3
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt
@@ -0,0 +1,62 @@
+* Rockchip RK3399 Clock and Reset Unit
+
+The RK3399 clock controller generates and supplies clock to various
+controllers within the SoC and also implements a reset controller for SoC
+peripherals.
+
+Required Properties:
+
+- compatible: PMU for CRU should be "rockchip,rk3399-pmucru"
+- compatible: CRU should be "rockchip,rk3399-cru"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in the dt-bindings/clock/rk3399-cru.h headers and can be
+used in device tree sources. Similar macros exist for the reset sources in
+these files.
+
+External clocks:
+
+There are several clocks that are generated outside the SoC. It is expected
+that they are defined using standard clock bindings with following
+clock-output-names:
+ - "xin24m" - crystal input - required,
+ - "xin32k" - rtc clock - optional,
+ - "clkin_gmac" - external GMAC clock - optional,
+ - "clkin_i2s" - external I2S clock - optional,
+ - "pclkin_cif" - external ISP clock - optional,
+ - "clk_usbphy0_480m" - output clock of the pll in the usbphy0
+ - "clk_usbphy1_480m" - output clock of the pll in the usbphy1
+
+Example: Clock controller node:
+
+	pmucru: pmu-clock-controller@ff750000 {
+		compatible = "rockchip,rk3399-pmucru";
+		reg = <0x0 0xff750000 0x0 0x1000>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+	cru: clock-controller@ff760000 {
+		compatible = "rockchip,rk3399-cru";
+		reg = <0x0 0xff760000 0x0 0x1000>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+Example: UART controller node that consumes the clock generated by the clock
+  controller:
+
+	uart0: serial@ff1a0000 {
+		compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
+		reg = <0x0 0xff180000 0x0 0x100>;
+		clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
+		clock-names = "baudclk", "apb_pclk";
+		interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+	};
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 73b98df..108d455 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -236,6 +236,7 @@
 CLOCK
   devm_clk_get()
   devm_clk_put()
+  devm_clk_hw_register()
 
 DMA
   dmam_alloc_coherent()
diff --git a/MAINTAINERS b/MAINTAINERS
index 03e00c7..05aeee0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -973,7 +973,7 @@
 L:	linux-arm-kernel@axis.com
 F:	arch/arm/mach-artpec
 F:	arch/arm/boot/dts/artpec6*
-F:	drivers/clk/clk-artpec6.c
+F:	drivers/clk/axis
 
 ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT
 M:	Nicolas Ferre <nicolas.ferre@atmel.com>
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 16f7d33..2dd371d 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -197,10 +197,17 @@
 	---help---
 	  Support for the Marvell PXA SoC.
 
+config COMMON_CLK_OXNAS
+	bool "Clock driver for the OXNAS SoC Family"
+	select MFD_SYSCON
+	---help---
+	  Support for the OXNAS SoC Family clocks.
+
 source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/hisilicon/Kconfig"
 source "drivers/clk/mvebu/Kconfig"
 source "drivers/clk/qcom/Kconfig"
+source "drivers/clk/renesas/Kconfig"
 source "drivers/clk/samsung/Kconfig"
 source "drivers/clk/tegra/Kconfig"
 source "drivers/clk/ti/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 46869d6..4ef71a1 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -33,6 +33,7 @@
 obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
 obj-$(CONFIG_ARCH_NOMADIK)		+= clk-nomadik.o
 obj-$(CONFIG_ARCH_NSPIRE)		+= clk-nspire.o
+obj-$(CONFIG_COMMON_CLK_OXNAS)		+= clk-oxnas.o
 obj-$(CONFIG_COMMON_CLK_PALMAS)		+= clk-palmas.o
 obj-$(CONFIG_CLK_QORIQ)			+= clk-qoriq.o
 obj-$(CONFIG_COMMON_CLK_RK808)		+= clk-rk808.o
@@ -51,6 +52,7 @@
 obj-$(CONFIG_COMMON_CLK_XGENE)		+= clk-xgene.o
 obj-$(CONFIG_COMMON_CLK_PWM)		+= clk-pwm.o
 obj-$(CONFIG_COMMON_CLK_AT91)		+= at91/
+obj-$(CONFIG_ARCH_ARTPEC)		+= axis/
 obj-y					+= bcm/
 obj-$(CONFIG_ARCH_BERLIN)		+= berlin/
 obj-$(CONFIG_ARCH_HISI)			+= hisilicon/
@@ -61,7 +63,7 @@
 ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_ARCH_MMP)			+= mmp/
 endif
-obj-$(CONFIG_PLAT_ORION)		+= mvebu/
+obj-y					+= mvebu/
 obj-$(CONFIG_ARCH_MESON)		+= meson/
 obj-$(CONFIG_ARCH_MXS)			+= mxs/
 obj-$(CONFIG_MACH_PISTACHIO)		+= pistachio/
diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c
index 819f584..8e20c8a 100644
--- a/drivers/clk/at91/clk-h32mx.c
+++ b/drivers/clk/at91/clk-h32mx.c
@@ -114,7 +114,7 @@
 	h32mxclk->regmap = regmap;
 
 	clk = clk_register(NULL, &h32mxclk->hw);
-	if (!clk) {
+	if (IS_ERR(clk)) {
 		kfree(h32mxclk);
 		return;
 	}
diff --git a/drivers/clk/axis/Makefile b/drivers/clk/axis/Makefile
new file mode 100644
index 0000000..628c9d3
--- /dev/null
+++ b/drivers/clk/axis/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MACH_ARTPEC6)	+= clk-artpec6.o
diff --git a/drivers/clk/axis/clk-artpec6.c b/drivers/clk/axis/clk-artpec6.c
new file mode 100644
index 0000000..ffc988b
--- /dev/null
+++ b/drivers/clk/axis/clk-artpec6.c
@@ -0,0 +1,242 @@
+/*
+ * ARTPEC-6 clock initialization
+ *
+ * Copyright 2015-2016 Axis Comunications AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <dt-bindings/clock/axis,artpec6-clkctrl.h>
+
+#define NUM_I2S_CLOCKS 2
+
+struct artpec6_clkctrl_drvdata {
+	struct clk *clk_table[ARTPEC6_CLK_NUMCLOCKS];
+	void __iomem *syscon_base;
+	struct clk_onecell_data clk_data;
+	spinlock_t i2scfg_lock;
+};
+
+static struct artpec6_clkctrl_drvdata *clkdata;
+
+static const char *const i2s_clk_names[NUM_I2S_CLOCKS] = {
+	"i2s0",
+	"i2s1",
+};
+
+static const int i2s_clk_indexes[NUM_I2S_CLOCKS] = {
+	ARTPEC6_CLK_I2S0_CLK,
+	ARTPEC6_CLK_I2S1_CLK,
+};
+
+static void of_artpec6_clkctrl_setup(struct device_node *np)
+{
+	int i;
+	const char *sys_refclk_name;
+	u32 pll_mode, pll_m, pll_n;
+	struct clk **clks;
+
+	/* Mandatory parent clock. */
+	i = of_property_match_string(np, "clock-names", "sys_refclk");
+	if (i < 0)
+		return;
+
+	sys_refclk_name = of_clk_get_parent_name(np, i);
+
+	clkdata = kzalloc(sizeof(*clkdata), GFP_KERNEL);
+	if (!clkdata)
+		return;
+
+	clks = clkdata->clk_table;
+
+	for (i = 0; i < ARTPEC6_CLK_NUMCLOCKS; ++i)
+		clks[i] = ERR_PTR(-EPROBE_DEFER);
+
+	clkdata->syscon_base = of_iomap(np, 0);
+	BUG_ON(clkdata->syscon_base == NULL);
+
+	/* Read PLL1 factors configured by boot strap pins. */
+	pll_mode = (readl(clkdata->syscon_base) >> 6) & 3;
+	switch (pll_mode) {
+	case 0:		/* DDR3-2133 mode */
+		pll_m = 4;
+		pll_n = 85;
+		break;
+	case 1:		/* DDR3-1866 mode */
+		pll_m = 6;
+		pll_n = 112;
+		break;
+	case 2:		/* DDR3-1600 mode */
+		pll_m = 4;
+		pll_n = 64;
+		break;
+	case 3:		/* DDR3-1333 mode */
+		pll_m = 8;
+		pll_n = 106;
+		break;
+	}
+
+	clks[ARTPEC6_CLK_CPU] =
+	    clk_register_fixed_factor(NULL, "cpu", sys_refclk_name, 0, pll_n,
+				      pll_m);
+	clks[ARTPEC6_CLK_CPU_PERIPH] =
+	    clk_register_fixed_factor(NULL, "cpu_periph", "cpu", 0, 1, 2);
+
+	/* EPROBE_DEFER on the apb_clock is not handled in amba devices. */
+	clks[ARTPEC6_CLK_UART_PCLK] =
+	    clk_register_fixed_factor(NULL, "uart_pclk", "cpu", 0, 1, 8);
+	clks[ARTPEC6_CLK_UART_REFCLK] =
+	    clk_register_fixed_rate(NULL, "uart_ref", sys_refclk_name, 0,
+				    50000000);
+
+	clks[ARTPEC6_CLK_SPI_PCLK] =
+	    clk_register_fixed_factor(NULL, "spi_pclk", "cpu", 0, 1, 8);
+	clks[ARTPEC6_CLK_SPI_SSPCLK] =
+	    clk_register_fixed_rate(NULL, "spi_sspclk", sys_refclk_name, 0,
+				    50000000);
+
+	clks[ARTPEC6_CLK_DBG_PCLK] =
+	    clk_register_fixed_factor(NULL, "dbg_pclk", "cpu", 0, 1, 8);
+
+	clkdata->clk_data.clks = clkdata->clk_table;
+	clkdata->clk_data.clk_num = ARTPEC6_CLK_NUMCLOCKS;
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clkdata->clk_data);
+}
+
+CLK_OF_DECLARE(artpec6_clkctrl, "axis,artpec6-clkctrl",
+	       of_artpec6_clkctrl_setup);
+
+static int artpec6_clkctrl_probe(struct platform_device *pdev)
+{
+	int propidx;
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct clk **clks = clkdata->clk_table;
+	const char *sys_refclk_name;
+	const char *i2s_refclk_name = NULL;
+	const char *frac_clk_name[2] = { NULL, NULL };
+	const char *i2s_mux_parents[2];
+	u32 muxreg;
+	int i;
+	int err = 0;
+
+	/* Mandatory parent clock. */
+	propidx = of_property_match_string(np, "clock-names", "sys_refclk");
+	if (propidx < 0)
+		return -EINVAL;
+
+	sys_refclk_name = of_clk_get_parent_name(np, propidx);
+
+	/* Find clock names of optional parent clocks. */
+	propidx = of_property_match_string(np, "clock-names", "i2s_refclk");
+	if (propidx >= 0)
+		i2s_refclk_name = of_clk_get_parent_name(np, propidx);
+
+	propidx = of_property_match_string(np, "clock-names", "frac_clk0");
+	if (propidx >= 0)
+		frac_clk_name[0] = of_clk_get_parent_name(np, propidx);
+	propidx = of_property_match_string(np, "clock-names", "frac_clk1");
+	if (propidx >= 0)
+		frac_clk_name[1] = of_clk_get_parent_name(np, propidx);
+
+	spin_lock_init(&clkdata->i2scfg_lock);
+
+	clks[ARTPEC6_CLK_NAND_CLKA] =
+	    clk_register_fixed_factor(dev, "nand_clka", "cpu", 0, 1, 8);
+	clks[ARTPEC6_CLK_NAND_CLKB] =
+	    clk_register_fixed_rate(dev, "nand_clkb", sys_refclk_name, 0,
+				    100000000);
+	clks[ARTPEC6_CLK_ETH_ACLK] =
+	    clk_register_fixed_factor(dev, "eth_aclk", "cpu", 0, 1, 4);
+	clks[ARTPEC6_CLK_DMA_ACLK] =
+	    clk_register_fixed_factor(dev, "dma_aclk", "cpu", 0, 1, 4);
+	clks[ARTPEC6_CLK_PTP_REF] =
+	    clk_register_fixed_rate(dev, "ptp_ref", sys_refclk_name, 0,
+				    100000000);
+	clks[ARTPEC6_CLK_SD_PCLK] =
+	    clk_register_fixed_rate(dev, "sd_pclk", sys_refclk_name, 0,
+				    100000000);
+	clks[ARTPEC6_CLK_SD_IMCLK] =
+	    clk_register_fixed_rate(dev, "sd_imclk", sys_refclk_name, 0,
+				    100000000);
+	clks[ARTPEC6_CLK_I2S_HST] =
+	    clk_register_fixed_factor(dev, "i2s_hst", "cpu", 0, 1, 8);
+
+	for (i = 0; i < NUM_I2S_CLOCKS; ++i) {
+		if (i2s_refclk_name && frac_clk_name[i]) {
+			i2s_mux_parents[0] = frac_clk_name[i];
+			i2s_mux_parents[1] = i2s_refclk_name;
+
+			clks[i2s_clk_indexes[i]] =
+			    clk_register_mux(dev, i2s_clk_names[i],
+					     i2s_mux_parents, 2,
+					     CLK_SET_RATE_NO_REPARENT |
+					     CLK_SET_RATE_PARENT,
+					     clkdata->syscon_base + 0x14, i, 1,
+					     0, &clkdata->i2scfg_lock);
+		} else if (frac_clk_name[i]) {
+			/* Lock the mux for internal clock reference. */
+			muxreg = readl(clkdata->syscon_base + 0x14);
+			muxreg &= ~BIT(i);
+			writel(muxreg, clkdata->syscon_base + 0x14);
+			clks[i2s_clk_indexes[i]] =
+			    clk_register_fixed_factor(dev, i2s_clk_names[i],
+						      frac_clk_name[i], 0, 1,
+						      1);
+		} else if (i2s_refclk_name) {
+			/* Lock the mux for external clock reference. */
+			muxreg = readl(clkdata->syscon_base + 0x14);
+			muxreg |= BIT(i);
+			writel(muxreg, clkdata->syscon_base + 0x14);
+			clks[i2s_clk_indexes[i]] =
+			    clk_register_fixed_factor(dev, i2s_clk_names[i],
+						      i2s_refclk_name, 0, 1, 1);
+		}
+	}
+
+	clks[ARTPEC6_CLK_I2C] =
+	    clk_register_fixed_rate(dev, "i2c", sys_refclk_name, 0, 100000000);
+
+	clks[ARTPEC6_CLK_SYS_TIMER] =
+	    clk_register_fixed_rate(dev, "timer", sys_refclk_name, 0,
+				    100000000);
+	clks[ARTPEC6_CLK_FRACDIV_IN] =
+	    clk_register_fixed_rate(dev, "fracdiv_in", sys_refclk_name, 0,
+				    600000000);
+
+	for (i = 0; i < ARTPEC6_CLK_NUMCLOCKS; ++i) {
+		if (IS_ERR(clks[i]) && PTR_ERR(clks[i]) != -EPROBE_DEFER) {
+			dev_err(dev,
+				"Failed to register clock at index %d err=%ld\n",
+				i, PTR_ERR(clks[i]));
+			err = PTR_ERR(clks[i]);
+		}
+	}
+
+	return err;
+}
+
+static const struct of_device_id artpec_clkctrl_of_match[] = {
+	{ .compatible = "axis,artpec6-clkctrl" },
+	{}
+};
+
+static struct platform_driver artpec6_clkctrl_driver = {
+	.probe = artpec6_clkctrl_probe,
+	.driver = {
+		   .name = "artpec6_clkctrl",
+		   .of_match_table = artpec_clkctrl_of_match,
+	},
+};
+
+builtin_platform_driver(artpec6_clkctrl_driver);
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index c74ed3f..7a79708 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -12,9 +12,6 @@
  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /**
@@ -40,6 +37,7 @@
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/clk/bcm2835.h>
+#include <linux/debugfs.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -51,6 +49,7 @@
 #define CM_GNRICCTL		0x000
 #define CM_GNRICDIV		0x004
 # define CM_DIV_FRAC_BITS	12
+# define CM_DIV_FRAC_MASK	GENMASK(CM_DIV_FRAC_BITS - 1, 0)
 
 #define CM_VPUCTL		0x008
 #define CM_VPUDIV		0x00c
@@ -118,6 +117,8 @@
 #define CM_SDCCTL		0x1a8
 #define CM_SDCDIV		0x1ac
 #define CM_ARMCTL		0x1b0
+#define CM_AVEOCTL		0x1b8
+#define CM_AVEODIV		0x1bc
 #define CM_EMMCCTL		0x1c0
 #define CM_EMMCDIV		0x1c4
 
@@ -128,6 +129,7 @@
 # define CM_GATE			BIT(CM_GATE_BIT)
 # define CM_BUSY			BIT(7)
 # define CM_BUSYD			BIT(8)
+# define CM_FRAC			BIT(9)
 # define CM_SRC_SHIFT			0
 # define CM_SRC_BITS			4
 # define CM_SRC_MASK			0xf
@@ -297,11 +299,11 @@
 struct bcm2835_cprman {
 	struct device *dev;
 	void __iomem *regs;
-	spinlock_t regs_lock;
+	spinlock_t regs_lock; /* spinlock for all clocks */
 	const char *osc_name;
 
 	struct clk_onecell_data onecell;
-	struct clk *clks[BCM2835_CLOCK_COUNT];
+	struct clk *clks[];
 };
 
 static inline void cprman_write(struct bcm2835_cprman *cprman, u32 reg, u32 val)
@@ -314,6 +316,27 @@
 	return readl(cprman->regs + reg);
 }
 
+static int bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base,
+				  struct debugfs_reg32 *regs, size_t nregs,
+				  struct dentry *dentry)
+{
+	struct dentry *regdump;
+	struct debugfs_regset32 *regset;
+
+	regset = devm_kzalloc(cprman->dev, sizeof(*regset), GFP_KERNEL);
+	if (!regset)
+		return -ENOMEM;
+
+	regset->regs = regs;
+	regset->nregs = nregs;
+	regset->base = cprman->regs + base;
+
+	regdump = debugfs_create_regset32("regdump", S_IRUGO, dentry,
+					  regset);
+
+	return regdump ? 0 : -ENOMEM;
+}
+
 /*
  * These are fixed clocks. They're probably not all root clocks and it may
  * be possible to turn them on and off but until this is mapped out better
@@ -377,132 +400,27 @@
 static const struct bcm2835_pll_ana_bits bcm2835_ana_default = {
 	.mask0 = 0,
 	.set0 = 0,
-	.mask1 = ~(A2W_PLL_KI_MASK | A2W_PLL_KP_MASK),
+	.mask1 = (u32)~(A2W_PLL_KI_MASK | A2W_PLL_KP_MASK),
 	.set1 = (2 << A2W_PLL_KI_SHIFT) | (8 << A2W_PLL_KP_SHIFT),
-	.mask3 = ~A2W_PLL_KA_MASK,
+	.mask3 = (u32)~A2W_PLL_KA_MASK,
 	.set3 = (2 << A2W_PLL_KA_SHIFT),
 	.fb_prediv_mask = BIT(14),
 };
 
 static const struct bcm2835_pll_ana_bits bcm2835_ana_pllh = {
-	.mask0 = ~(A2W_PLLH_KA_MASK | A2W_PLLH_KI_LOW_MASK),
+	.mask0 = (u32)~(A2W_PLLH_KA_MASK | A2W_PLLH_KI_LOW_MASK),
 	.set0 = (2 << A2W_PLLH_KA_SHIFT) | (2 << A2W_PLLH_KI_LOW_SHIFT),
-	.mask1 = ~(A2W_PLLH_KI_HIGH_MASK | A2W_PLLH_KP_MASK),
+	.mask1 = (u32)~(A2W_PLLH_KI_HIGH_MASK | A2W_PLLH_KP_MASK),
 	.set1 = (6 << A2W_PLLH_KP_SHIFT),
 	.mask3 = 0,
 	.set3 = 0,
 	.fb_prediv_mask = BIT(11),
 };
 
-/*
- * PLLA is the auxiliary PLL, used to drive the CCP2 (Compact Camera
- * Port 2) transmitter clock.
- *
- * It is in the PX LDO power domain, which is on when the AUDIO domain
- * is on.
- */
-static const struct bcm2835_pll_data bcm2835_plla_data = {
-	.name = "plla",
-	.cm_ctrl_reg = CM_PLLA,
-	.a2w_ctrl_reg = A2W_PLLA_CTRL,
-	.frac_reg = A2W_PLLA_FRAC,
-	.ana_reg_base = A2W_PLLA_ANA0,
-	.reference_enable_mask = A2W_XOSC_CTRL_PLLA_ENABLE,
-	.lock_mask = CM_LOCK_FLOCKA,
-
-	.ana = &bcm2835_ana_default,
-
-	.min_rate = 600000000u,
-	.max_rate = 2400000000u,
-	.max_fb_rate = BCM2835_MAX_FB_RATE,
-};
-
-/* PLLB is used for the ARM's clock. */
-static const struct bcm2835_pll_data bcm2835_pllb_data = {
-	.name = "pllb",
-	.cm_ctrl_reg = CM_PLLB,
-	.a2w_ctrl_reg = A2W_PLLB_CTRL,
-	.frac_reg = A2W_PLLB_FRAC,
-	.ana_reg_base = A2W_PLLB_ANA0,
-	.reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
-	.lock_mask = CM_LOCK_FLOCKB,
-
-	.ana = &bcm2835_ana_default,
-
-	.min_rate = 600000000u,
-	.max_rate = 3000000000u,
-	.max_fb_rate = BCM2835_MAX_FB_RATE,
-};
-
-/*
- * PLLC is the core PLL, used to drive the core VPU clock.
- *
- * It is in the PX LDO power domain, which is on when the AUDIO domain
- * is on.
-*/
-static const struct bcm2835_pll_data bcm2835_pllc_data = {
-	.name = "pllc",
-	.cm_ctrl_reg = CM_PLLC,
-	.a2w_ctrl_reg = A2W_PLLC_CTRL,
-	.frac_reg = A2W_PLLC_FRAC,
-	.ana_reg_base = A2W_PLLC_ANA0,
-	.reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE,
-	.lock_mask = CM_LOCK_FLOCKC,
-
-	.ana = &bcm2835_ana_default,
-
-	.min_rate = 600000000u,
-	.max_rate = 3000000000u,
-	.max_fb_rate = BCM2835_MAX_FB_RATE,
-};
-
-/*
- * PLLD is the display PLL, used to drive DSI display panels.
- *
- * It is in the PX LDO power domain, which is on when the AUDIO domain
- * is on.
- */
-static const struct bcm2835_pll_data bcm2835_plld_data = {
-	.name = "plld",
-	.cm_ctrl_reg = CM_PLLD,
-	.a2w_ctrl_reg = A2W_PLLD_CTRL,
-	.frac_reg = A2W_PLLD_FRAC,
-	.ana_reg_base = A2W_PLLD_ANA0,
-	.reference_enable_mask = A2W_XOSC_CTRL_DDR_ENABLE,
-	.lock_mask = CM_LOCK_FLOCKD,
-
-	.ana = &bcm2835_ana_default,
-
-	.min_rate = 600000000u,
-	.max_rate = 2400000000u,
-	.max_fb_rate = BCM2835_MAX_FB_RATE,
-};
-
-/*
- * PLLH is used to supply the pixel clock or the AUX clock for the TV
- * encoder.
- *
- * It is in the HDMI power domain.
- */
-static const struct bcm2835_pll_data bcm2835_pllh_data = {
-	"pllh",
-	.cm_ctrl_reg = CM_PLLH,
-	.a2w_ctrl_reg = A2W_PLLH_CTRL,
-	.frac_reg = A2W_PLLH_FRAC,
-	.ana_reg_base = A2W_PLLH_ANA0,
-	.reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE,
-	.lock_mask = CM_LOCK_FLOCKH,
-
-	.ana = &bcm2835_ana_pllh,
-
-	.min_rate = 600000000u,
-	.max_rate = 3000000000u,
-	.max_fb_rate = BCM2835_MAX_FB_RATE,
-};
-
 struct bcm2835_pll_divider_data {
 	const char *name;
-	const struct bcm2835_pll_data *source_pll;
+	const char *source_pll;
+
 	u32 cm_reg;
 	u32 a2w_reg;
 
@@ -511,124 +429,6 @@
 	u32 fixed_divider;
 };
 
-static const struct bcm2835_pll_divider_data bcm2835_plla_core_data = {
-	.name = "plla_core",
-	.source_pll = &bcm2835_plla_data,
-	.cm_reg = CM_PLLA,
-	.a2w_reg = A2W_PLLA_CORE,
-	.load_mask = CM_PLLA_LOADCORE,
-	.hold_mask = CM_PLLA_HOLDCORE,
-	.fixed_divider = 1,
-};
-
-static const struct bcm2835_pll_divider_data bcm2835_plla_per_data = {
-	.name = "plla_per",
-	.source_pll = &bcm2835_plla_data,
-	.cm_reg = CM_PLLA,
-	.a2w_reg = A2W_PLLA_PER,
-	.load_mask = CM_PLLA_LOADPER,
-	.hold_mask = CM_PLLA_HOLDPER,
-	.fixed_divider = 1,
-};
-
-static const struct bcm2835_pll_divider_data bcm2835_pllb_arm_data = {
-	.name = "pllb_arm",
-	.source_pll = &bcm2835_pllb_data,
-	.cm_reg = CM_PLLB,
-	.a2w_reg = A2W_PLLB_ARM,
-	.load_mask = CM_PLLB_LOADARM,
-	.hold_mask = CM_PLLB_HOLDARM,
-	.fixed_divider = 1,
-};
-
-static const struct bcm2835_pll_divider_data bcm2835_pllc_core0_data = {
-	.name = "pllc_core0",
-	.source_pll = &bcm2835_pllc_data,
-	.cm_reg = CM_PLLC,
-	.a2w_reg = A2W_PLLC_CORE0,
-	.load_mask = CM_PLLC_LOADCORE0,
-	.hold_mask = CM_PLLC_HOLDCORE0,
-	.fixed_divider = 1,
-};
-
-static const struct bcm2835_pll_divider_data bcm2835_pllc_core1_data = {
-	.name = "pllc_core1", .source_pll = &bcm2835_pllc_data,
-	.cm_reg = CM_PLLC, A2W_PLLC_CORE1,
-	.load_mask = CM_PLLC_LOADCORE1,
-	.hold_mask = CM_PLLC_HOLDCORE1,
-	.fixed_divider = 1,
-};
-
-static const struct bcm2835_pll_divider_data bcm2835_pllc_core2_data = {
-	.name = "pllc_core2",
-	.source_pll = &bcm2835_pllc_data,
-	.cm_reg = CM_PLLC,
-	.a2w_reg = A2W_PLLC_CORE2,
-	.load_mask = CM_PLLC_LOADCORE2,
-	.hold_mask = CM_PLLC_HOLDCORE2,
-	.fixed_divider = 1,
-};
-
-static const struct bcm2835_pll_divider_data bcm2835_pllc_per_data = {
-	.name = "pllc_per",
-	.source_pll = &bcm2835_pllc_data,
-	.cm_reg = CM_PLLC,
-	.a2w_reg = A2W_PLLC_PER,
-	.load_mask = CM_PLLC_LOADPER,
-	.hold_mask = CM_PLLC_HOLDPER,
-	.fixed_divider = 1,
-};
-
-static const struct bcm2835_pll_divider_data bcm2835_plld_core_data = {
-	.name = "plld_core",
-	.source_pll = &bcm2835_plld_data,
-	.cm_reg = CM_PLLD,
-	.a2w_reg = A2W_PLLD_CORE,
-	.load_mask = CM_PLLD_LOADCORE,
-	.hold_mask = CM_PLLD_HOLDCORE,
-	.fixed_divider = 1,
-};
-
-static const struct bcm2835_pll_divider_data bcm2835_plld_per_data = {
-	.name = "plld_per",
-	.source_pll = &bcm2835_plld_data,
-	.cm_reg = CM_PLLD,
-	.a2w_reg = A2W_PLLD_PER,
-	.load_mask = CM_PLLD_LOADPER,
-	.hold_mask = CM_PLLD_HOLDPER,
-	.fixed_divider = 1,
-};
-
-static const struct bcm2835_pll_divider_data bcm2835_pllh_rcal_data = {
-	.name = "pllh_rcal",
-	.source_pll = &bcm2835_pllh_data,
-	.cm_reg = CM_PLLH,
-	.a2w_reg = A2W_PLLH_RCAL,
-	.load_mask = CM_PLLH_LOADRCAL,
-	.hold_mask = 0,
-	.fixed_divider = 10,
-};
-
-static const struct bcm2835_pll_divider_data bcm2835_pllh_aux_data = {
-	.name = "pllh_aux",
-	.source_pll = &bcm2835_pllh_data,
-	.cm_reg = CM_PLLH,
-	.a2w_reg = A2W_PLLH_AUX,
-	.load_mask = CM_PLLH_LOADAUX,
-	.hold_mask = 0,
-	.fixed_divider = 10,
-};
-
-static const struct bcm2835_pll_divider_data bcm2835_pllh_pix_data = {
-	.name = "pllh_pix",
-	.source_pll = &bcm2835_pllh_data,
-	.cm_reg = CM_PLLH,
-	.a2w_reg = A2W_PLLH_PIX,
-	.load_mask = CM_PLLH_LOADPIX,
-	.hold_mask = 0,
-	.fixed_divider = 10,
-};
-
 struct bcm2835_clock_data {
 	const char *name;
 
@@ -644,187 +444,14 @@
 	u32 frac_bits;
 
 	bool is_vpu_clock;
+	bool is_mash_clock;
 };
 
-static const char *const bcm2835_clock_per_parents[] = {
-	"gnd",
-	"xosc",
-	"testdebug0",
-	"testdebug1",
-	"plla_per",
-	"pllc_per",
-	"plld_per",
-	"pllh_aux",
-};
+struct bcm2835_gate_data {
+	const char *name;
+	const char *parent;
 
-static const char *const bcm2835_clock_vpu_parents[] = {
-	"gnd",
-	"xosc",
-	"testdebug0",
-	"testdebug1",
-	"plla_core",
-	"pllc_core0",
-	"plld_core",
-	"pllh_aux",
-	"pllc_core1",
-	"pllc_core2",
-};
-
-static const char *const bcm2835_clock_osc_parents[] = {
-	"gnd",
-	"xosc",
-	"testdebug0",
-	"testdebug1"
-};
-
-/*
- * Used for a 1Mhz clock for the system clocksource, and also used by
- * the watchdog timer and the camera pulse generator.
- */
-static const struct bcm2835_clock_data bcm2835_clock_timer_data = {
-	.name = "timer",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents),
-	.parents = bcm2835_clock_osc_parents,
-	.ctl_reg = CM_TIMERCTL,
-	.div_reg = CM_TIMERDIV,
-	.int_bits = 6,
-	.frac_bits = 12,
-};
-
-/* One Time Programmable Memory clock.  Maximum 10Mhz. */
-static const struct bcm2835_clock_data bcm2835_clock_otp_data = {
-	.name = "otp",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents),
-	.parents = bcm2835_clock_osc_parents,
-	.ctl_reg = CM_OTPCTL,
-	.div_reg = CM_OTPDIV,
-	.int_bits = 4,
-	.frac_bits = 0,
-};
-
-/*
- * VPU clock.  This doesn't have an enable bit, since it drives the
- * bus for everything else, and is special so it doesn't need to be
- * gated for rate changes.  It is also known as "clk_audio" in various
- * hardware documentation.
- */
-static const struct bcm2835_clock_data bcm2835_clock_vpu_data = {
-	.name = "vpu",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents),
-	.parents = bcm2835_clock_vpu_parents,
-	.ctl_reg = CM_VPUCTL,
-	.div_reg = CM_VPUDIV,
-	.int_bits = 12,
-	.frac_bits = 8,
-	.is_vpu_clock = true,
-};
-
-static const struct bcm2835_clock_data bcm2835_clock_v3d_data = {
-	.name = "v3d",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents),
-	.parents = bcm2835_clock_vpu_parents,
-	.ctl_reg = CM_V3DCTL,
-	.div_reg = CM_V3DDIV,
-	.int_bits = 4,
-	.frac_bits = 8,
-};
-
-static const struct bcm2835_clock_data bcm2835_clock_isp_data = {
-	.name = "isp",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents),
-	.parents = bcm2835_clock_vpu_parents,
-	.ctl_reg = CM_ISPCTL,
-	.div_reg = CM_ISPDIV,
-	.int_bits = 4,
-	.frac_bits = 8,
-};
-
-static const struct bcm2835_clock_data bcm2835_clock_h264_data = {
-	.name = "h264",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents),
-	.parents = bcm2835_clock_vpu_parents,
-	.ctl_reg = CM_H264CTL,
-	.div_reg = CM_H264DIV,
-	.int_bits = 4,
-	.frac_bits = 8,
-};
-
-/* TV encoder clock.  Only operating frequency is 108Mhz.  */
-static const struct bcm2835_clock_data bcm2835_clock_vec_data = {
-	.name = "vec",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
-	.parents = bcm2835_clock_per_parents,
-	.ctl_reg = CM_VECCTL,
-	.div_reg = CM_VECDIV,
-	.int_bits = 4,
-	.frac_bits = 0,
-};
-
-static const struct bcm2835_clock_data bcm2835_clock_uart_data = {
-	.name = "uart",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
-	.parents = bcm2835_clock_per_parents,
-	.ctl_reg = CM_UARTCTL,
-	.div_reg = CM_UARTDIV,
-	.int_bits = 10,
-	.frac_bits = 12,
-};
-
-/* HDMI state machine */
-static const struct bcm2835_clock_data bcm2835_clock_hsm_data = {
-	.name = "hsm",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
-	.parents = bcm2835_clock_per_parents,
-	.ctl_reg = CM_HSMCTL,
-	.div_reg = CM_HSMDIV,
-	.int_bits = 4,
-	.frac_bits = 8,
-};
-
-/*
- * Secondary SDRAM clock.  Used for low-voltage modes when the PLL in
- * the SDRAM controller can't be used.
- */
-static const struct bcm2835_clock_data bcm2835_clock_sdram_data = {
-	.name = "sdram",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents),
-	.parents = bcm2835_clock_vpu_parents,
-	.ctl_reg = CM_SDCCTL,
-	.div_reg = CM_SDCDIV,
-	.int_bits = 6,
-	.frac_bits = 0,
-};
-
-/* Clock for the temperature sensor.  Generally run at 2Mhz, max 5Mhz. */
-static const struct bcm2835_clock_data bcm2835_clock_tsens_data = {
-	.name = "tsens",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents),
-	.parents = bcm2835_clock_osc_parents,
-	.ctl_reg = CM_TSENSCTL,
-	.div_reg = CM_TSENSDIV,
-	.int_bits = 5,
-	.frac_bits = 0,
-};
-
-/* Arasan EMMC clock */
-static const struct bcm2835_clock_data bcm2835_clock_emmc_data = {
-	.name = "emmc",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
-	.parents = bcm2835_clock_per_parents,
-	.ctl_reg = CM_EMMCCTL,
-	.div_reg = CM_EMMCDIV,
-	.int_bits = 4,
-	.frac_bits = 8,
-};
-
-static const struct bcm2835_clock_data bcm2835_clock_pwm_data = {
-	.name = "pwm",
-	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
-	.parents = bcm2835_clock_per_parents,
-	.ctl_reg = CM_PWMCTL,
-	.div_reg = CM_PWMDIV,
-	.int_bits = 12,
-	.frac_bits = 12,
+	u32 ctl_reg;
 };
 
 struct bcm2835_pll {
@@ -910,8 +537,14 @@
 	struct bcm2835_cprman *cprman = pll->cprman;
 	const struct bcm2835_pll_data *data = pll->data;
 
-	cprman_write(cprman, data->cm_ctrl_reg, CM_PLL_ANARST);
-	cprman_write(cprman, data->a2w_ctrl_reg, A2W_PLL_CTRL_PWRDN);
+	spin_lock(&cprman->regs_lock);
+	cprman_write(cprman, data->cm_ctrl_reg,
+		     cprman_read(cprman, data->cm_ctrl_reg) |
+		     CM_PLL_ANARST);
+	cprman_write(cprman, data->a2w_ctrl_reg,
+		     cprman_read(cprman, data->a2w_ctrl_reg) |
+		     A2W_PLL_CTRL_PWRDN);
+	spin_unlock(&cprman->regs_lock);
 }
 
 static int bcm2835_pll_on(struct clk_hw *hw)
@@ -921,6 +554,10 @@
 	const struct bcm2835_pll_data *data = pll->data;
 	ktime_t timeout;
 
+	cprman_write(cprman, data->a2w_ctrl_reg,
+		     cprman_read(cprman, data->a2w_ctrl_reg) &
+		     ~A2W_PLL_CTRL_PWRDN);
+
 	/* Take the PLL out of reset. */
 	cprman_write(cprman, data->cm_ctrl_reg,
 		     cprman_read(cprman, data->cm_ctrl_reg) & ~CM_PLL_ANARST);
@@ -1030,6 +667,36 @@
 	return 0;
 }
 
+static int bcm2835_pll_debug_init(struct clk_hw *hw,
+				  struct dentry *dentry)
+{
+	struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
+	struct bcm2835_cprman *cprman = pll->cprman;
+	const struct bcm2835_pll_data *data = pll->data;
+	struct debugfs_reg32 *regs;
+
+	regs = devm_kzalloc(cprman->dev, 7 * sizeof(*regs), GFP_KERNEL);
+	if (!regs)
+		return -ENOMEM;
+
+	regs[0].name = "cm_ctrl";
+	regs[0].offset = data->cm_ctrl_reg;
+	regs[1].name = "a2w_ctrl";
+	regs[1].offset = data->a2w_ctrl_reg;
+	regs[2].name = "frac";
+	regs[2].offset = data->frac_reg;
+	regs[3].name = "ana0";
+	regs[3].offset = data->ana_reg_base + 0 * 4;
+	regs[4].name = "ana1";
+	regs[4].offset = data->ana_reg_base + 1 * 4;
+	regs[5].name = "ana2";
+	regs[5].offset = data->ana_reg_base + 2 * 4;
+	regs[6].name = "ana3";
+	regs[6].offset = data->ana_reg_base + 3 * 4;
+
+	return bcm2835_debugfs_regset(cprman, 0, regs, 7, dentry);
+}
+
 static const struct clk_ops bcm2835_pll_clk_ops = {
 	.is_prepared = bcm2835_pll_is_on,
 	.prepare = bcm2835_pll_on,
@@ -1037,6 +704,7 @@
 	.recalc_rate = bcm2835_pll_get_rate,
 	.set_rate = bcm2835_pll_set_rate,
 	.round_rate = bcm2835_pll_round_rate,
+	.debug_init = bcm2835_pll_debug_init,
 };
 
 struct bcm2835_pll_divider {
@@ -1079,10 +747,12 @@
 	struct bcm2835_cprman *cprman = divider->cprman;
 	const struct bcm2835_pll_divider_data *data = divider->data;
 
+	spin_lock(&cprman->regs_lock);
 	cprman_write(cprman, data->cm_reg,
 		     (cprman_read(cprman, data->cm_reg) &
 		      ~data->load_mask) | data->hold_mask);
 	cprman_write(cprman, data->a2w_reg, A2W_PLL_CHANNEL_DISABLE);
+	spin_unlock(&cprman->regs_lock);
 }
 
 static int bcm2835_pll_divider_on(struct clk_hw *hw)
@@ -1091,12 +761,14 @@
 	struct bcm2835_cprman *cprman = divider->cprman;
 	const struct bcm2835_pll_divider_data *data = divider->data;
 
+	spin_lock(&cprman->regs_lock);
 	cprman_write(cprman, data->a2w_reg,
 		     cprman_read(cprman, data->a2w_reg) &
 		     ~A2W_PLL_CHANNEL_DISABLE);
 
 	cprman_write(cprman, data->cm_reg,
 		     cprman_read(cprman, data->cm_reg) & ~data->hold_mask);
+	spin_unlock(&cprman->regs_lock);
 
 	return 0;
 }
@@ -1124,6 +796,26 @@
 	return 0;
 }
 
+static int bcm2835_pll_divider_debug_init(struct clk_hw *hw,
+					  struct dentry *dentry)
+{
+	struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw);
+	struct bcm2835_cprman *cprman = divider->cprman;
+	const struct bcm2835_pll_divider_data *data = divider->data;
+	struct debugfs_reg32 *regs;
+
+	regs = devm_kzalloc(cprman->dev, 7 * sizeof(*regs), GFP_KERNEL);
+	if (!regs)
+		return -ENOMEM;
+
+	regs[0].name = "cm";
+	regs[0].offset = data->cm_reg;
+	regs[1].name = "a2w";
+	regs[1].offset = data->a2w_reg;
+
+	return bcm2835_debugfs_regset(cprman, 0, regs, 2, dentry);
+}
+
 static const struct clk_ops bcm2835_pll_divider_clk_ops = {
 	.is_prepared = bcm2835_pll_divider_is_on,
 	.prepare = bcm2835_pll_divider_on,
@@ -1131,6 +823,7 @@
 	.recalc_rate = bcm2835_pll_divider_get_rate,
 	.set_rate = bcm2835_pll_divider_set_rate,
 	.round_rate = bcm2835_pll_divider_round_rate,
+	.debug_init = bcm2835_pll_divider_debug_init,
 };
 
 /*
@@ -1170,7 +863,7 @@
 		GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
 	u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
 	u64 rem;
-	u32 div;
+	u32 div, mindiv, maxdiv;
 
 	rem = do_div(temp, rate);
 	div = temp;
@@ -1180,10 +873,23 @@
 		div += unused_frac_mask + 1;
 	div &= ~unused_frac_mask;
 
-	/* Clamp to the limits. */
-	div = max(div, unused_frac_mask + 1);
-	div = min_t(u32, div, GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1,
-				      CM_DIV_FRAC_BITS - data->frac_bits));
+	/* different clamping limits apply for a mash clock */
+	if (data->is_mash_clock) {
+		/* clamp to min divider of 2 */
+		mindiv = 2 << CM_DIV_FRAC_BITS;
+		/* clamp to the highest possible integer divider */
+		maxdiv = (BIT(data->int_bits) - 1) << CM_DIV_FRAC_BITS;
+	} else {
+		/* clamp to min divider of 1 */
+		mindiv = 1 << CM_DIV_FRAC_BITS;
+		/* clamp to the highest possible fractional divider */
+		maxdiv = GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1,
+				 CM_DIV_FRAC_BITS - data->frac_bits);
+	}
+
+	/* apply the clamping  limits */
+	div = max_t(u32, div, mindiv);
+	div = min_t(u32, div, maxdiv);
 
 	return div;
 }
@@ -1277,14 +983,31 @@
 	struct bcm2835_cprman *cprman = clock->cprman;
 	const struct bcm2835_clock_data *data = clock->data;
 	u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false);
+	u32 ctl;
+
+	spin_lock(&cprman->regs_lock);
+
+	/*
+	 * Setting up frac support
+	 *
+	 * In principle it is recommended to stop/start the clock first,
+	 * but as we set CLK_SET_RATE_GATE during registration of the
+	 * clock this requirement should be take care of by the
+	 * clk-framework.
+	 */
+	ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC;
+	ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
+	cprman_write(cprman, data->ctl_reg, ctl);
 
 	cprman_write(cprman, data->div_reg, div);
 
+	spin_unlock(&cprman->regs_lock);
+
 	return 0;
 }
 
 static int bcm2835_clock_determine_rate(struct clk_hw *hw,
-		struct clk_rate_request *req)
+					struct clk_rate_request *req)
 {
 	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
 	struct clk_hw *parent, *best_parent = NULL;
@@ -1342,6 +1065,30 @@
 	return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
 }
 
+static struct debugfs_reg32 bcm2835_debugfs_clock_reg32[] = {
+	{
+		.name = "ctl",
+		.offset = 0,
+	},
+	{
+		.name = "div",
+		.offset = 4,
+	},
+};
+
+static int bcm2835_clock_debug_init(struct clk_hw *hw,
+				    struct dentry *dentry)
+{
+	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+	struct bcm2835_cprman *cprman = clock->cprman;
+	const struct bcm2835_clock_data *data = clock->data;
+
+	return bcm2835_debugfs_regset(
+		cprman, data->ctl_reg,
+		bcm2835_debugfs_clock_reg32,
+		ARRAY_SIZE(bcm2835_debugfs_clock_reg32),
+		dentry);
+}
 
 static const struct clk_ops bcm2835_clock_clk_ops = {
 	.is_prepared = bcm2835_clock_is_on,
@@ -1352,6 +1099,7 @@
 	.determine_rate = bcm2835_clock_determine_rate,
 	.set_parent = bcm2835_clock_set_parent,
 	.get_parent = bcm2835_clock_get_parent,
+	.debug_init = bcm2835_clock_debug_init,
 };
 
 static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
@@ -1370,6 +1118,7 @@
 	.determine_rate = bcm2835_clock_determine_rate,
 	.set_parent = bcm2835_clock_set_parent,
 	.get_parent = bcm2835_clock_get_parent,
+	.debug_init = bcm2835_clock_debug_init,
 };
 
 static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman,
@@ -1418,7 +1167,7 @@
 
 	memset(&init, 0, sizeof(init));
 
-	init.parent_names = &data->source_pll->name;
+	init.parent_names = &data->source_pll;
 	init.num_parents = 1;
 	init.name = divider_name;
 	init.ops = &bcm2835_pll_divider_clk_ops;
@@ -1501,14 +1250,559 @@
 	return devm_clk_register(cprman->dev, &clock->hw);
 }
 
+static struct clk *bcm2835_register_gate(struct bcm2835_cprman *cprman,
+					 const struct bcm2835_gate_data *data)
+{
+	return clk_register_gate(cprman->dev, data->name, data->parent,
+				 CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE,
+				 cprman->regs + data->ctl_reg,
+				 CM_GATE_BIT, 0, &cprman->regs_lock);
+}
+
+typedef struct clk *(*bcm2835_clk_register)(struct bcm2835_cprman *cprman,
+					    const void *data);
+struct bcm2835_clk_desc {
+	bcm2835_clk_register clk_register;
+	const void *data;
+};
+
+/* assignment helper macros for different clock types */
+#define _REGISTER(f, ...) { .clk_register = (bcm2835_clk_register)f, \
+			    .data = __VA_ARGS__ }
+#define REGISTER_PLL(...)	_REGISTER(&bcm2835_register_pll,	\
+					  &(struct bcm2835_pll_data)	\
+					  {__VA_ARGS__})
+#define REGISTER_PLL_DIV(...)	_REGISTER(&bcm2835_register_pll_divider, \
+					  &(struct bcm2835_pll_divider_data) \
+					  {__VA_ARGS__})
+#define REGISTER_CLK(...)	_REGISTER(&bcm2835_register_clock,	\
+					  &(struct bcm2835_clock_data)	\
+					  {__VA_ARGS__})
+#define REGISTER_GATE(...)	_REGISTER(&bcm2835_register_gate,	\
+					  &(struct bcm2835_gate_data)	\
+					  {__VA_ARGS__})
+
+/* parent mux arrays plus helper macros */
+
+/* main oscillator parent mux */
+static const char *const bcm2835_clock_osc_parents[] = {
+	"gnd",
+	"xosc",
+	"testdebug0",
+	"testdebug1"
+};
+
+#define REGISTER_OSC_CLK(...)	REGISTER_CLK(				\
+	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents),	\
+	.parents = bcm2835_clock_osc_parents,				\
+	__VA_ARGS__)
+
+/* main peripherial parent mux */
+static const char *const bcm2835_clock_per_parents[] = {
+	"gnd",
+	"xosc",
+	"testdebug0",
+	"testdebug1",
+	"plla_per",
+	"pllc_per",
+	"plld_per",
+	"pllh_aux",
+};
+
+#define REGISTER_PER_CLK(...)	REGISTER_CLK(				\
+	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),	\
+	.parents = bcm2835_clock_per_parents,				\
+	__VA_ARGS__)
+
+/* main vpu parent mux */
+static const char *const bcm2835_clock_vpu_parents[] = {
+	"gnd",
+	"xosc",
+	"testdebug0",
+	"testdebug1",
+	"plla_core",
+	"pllc_core0",
+	"plld_core",
+	"pllh_aux",
+	"pllc_core1",
+	"pllc_core2",
+};
+
+#define REGISTER_VPU_CLK(...)	REGISTER_CLK(				\
+	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents),	\
+	.parents = bcm2835_clock_vpu_parents,				\
+	__VA_ARGS__)
+
+/*
+ * the real definition of all the pll, pll_dividers and clocks
+ * these make use of the above REGISTER_* macros
+ */
+static const struct bcm2835_clk_desc clk_desc_array[] = {
+	/* the PLL + PLL dividers */
+
+	/*
+	 * PLLA is the auxiliary PLL, used to drive the CCP2
+	 * (Compact Camera Port 2) transmitter clock.
+	 *
+	 * It is in the PX LDO power domain, which is on when the
+	 * AUDIO domain is on.
+	 */
+	[BCM2835_PLLA]		= REGISTER_PLL(
+		.name = "plla",
+		.cm_ctrl_reg = CM_PLLA,
+		.a2w_ctrl_reg = A2W_PLLA_CTRL,
+		.frac_reg = A2W_PLLA_FRAC,
+		.ana_reg_base = A2W_PLLA_ANA0,
+		.reference_enable_mask = A2W_XOSC_CTRL_PLLA_ENABLE,
+		.lock_mask = CM_LOCK_FLOCKA,
+
+		.ana = &bcm2835_ana_default,
+
+		.min_rate = 600000000u,
+		.max_rate = 2400000000u,
+		.max_fb_rate = BCM2835_MAX_FB_RATE),
+	[BCM2835_PLLA_CORE]	= REGISTER_PLL_DIV(
+		.name = "plla_core",
+		.source_pll = "plla",
+		.cm_reg = CM_PLLA,
+		.a2w_reg = A2W_PLLA_CORE,
+		.load_mask = CM_PLLA_LOADCORE,
+		.hold_mask = CM_PLLA_HOLDCORE,
+		.fixed_divider = 1),
+	[BCM2835_PLLA_PER]	= REGISTER_PLL_DIV(
+		.name = "plla_per",
+		.source_pll = "plla",
+		.cm_reg = CM_PLLA,
+		.a2w_reg = A2W_PLLA_PER,
+		.load_mask = CM_PLLA_LOADPER,
+		.hold_mask = CM_PLLA_HOLDPER,
+		.fixed_divider = 1),
+	[BCM2835_PLLA_DSI0]	= REGISTER_PLL_DIV(
+		.name = "plla_dsi0",
+		.source_pll = "plla",
+		.cm_reg = CM_PLLA,
+		.a2w_reg = A2W_PLLA_DSI0,
+		.load_mask = CM_PLLA_LOADDSI0,
+		.hold_mask = CM_PLLA_HOLDDSI0,
+		.fixed_divider = 1),
+	[BCM2835_PLLA_CCP2]	= REGISTER_PLL_DIV(
+		.name = "plla_ccp2",
+		.source_pll = "plla",
+		.cm_reg = CM_PLLA,
+		.a2w_reg = A2W_PLLA_CCP2,
+		.load_mask = CM_PLLA_LOADCCP2,
+		.hold_mask = CM_PLLA_HOLDCCP2,
+		.fixed_divider = 1),
+
+	/* PLLB is used for the ARM's clock. */
+	[BCM2835_PLLB]		= REGISTER_PLL(
+		.name = "pllb",
+		.cm_ctrl_reg = CM_PLLB,
+		.a2w_ctrl_reg = A2W_PLLB_CTRL,
+		.frac_reg = A2W_PLLB_FRAC,
+		.ana_reg_base = A2W_PLLB_ANA0,
+		.reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
+		.lock_mask = CM_LOCK_FLOCKB,
+
+		.ana = &bcm2835_ana_default,
+
+		.min_rate = 600000000u,
+		.max_rate = 3000000000u,
+		.max_fb_rate = BCM2835_MAX_FB_RATE),
+	[BCM2835_PLLB_ARM]	= REGISTER_PLL_DIV(
+		.name = "pllb_arm",
+		.source_pll = "pllb",
+		.cm_reg = CM_PLLB,
+		.a2w_reg = A2W_PLLB_ARM,
+		.load_mask = CM_PLLB_LOADARM,
+		.hold_mask = CM_PLLB_HOLDARM,
+		.fixed_divider = 1),
+
+	/*
+	 * PLLC is the core PLL, used to drive the core VPU clock.
+	 *
+	 * It is in the PX LDO power domain, which is on when the
+	 * AUDIO domain is on.
+	 */
+	[BCM2835_PLLC]		= REGISTER_PLL(
+		.name = "pllc",
+		.cm_ctrl_reg = CM_PLLC,
+		.a2w_ctrl_reg = A2W_PLLC_CTRL,
+		.frac_reg = A2W_PLLC_FRAC,
+		.ana_reg_base = A2W_PLLC_ANA0,
+		.reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE,
+		.lock_mask = CM_LOCK_FLOCKC,
+
+		.ana = &bcm2835_ana_default,
+
+		.min_rate = 600000000u,
+		.max_rate = 3000000000u,
+		.max_fb_rate = BCM2835_MAX_FB_RATE),
+	[BCM2835_PLLC_CORE0]	= REGISTER_PLL_DIV(
+		.name = "pllc_core0",
+		.source_pll = "pllc",
+		.cm_reg = CM_PLLC,
+		.a2w_reg = A2W_PLLC_CORE0,
+		.load_mask = CM_PLLC_LOADCORE0,
+		.hold_mask = CM_PLLC_HOLDCORE0,
+		.fixed_divider = 1),
+	[BCM2835_PLLC_CORE1]	= REGISTER_PLL_DIV(
+		.name = "pllc_core1",
+		.source_pll = "pllc",
+		.cm_reg = CM_PLLC,
+		.a2w_reg = A2W_PLLC_CORE1,
+		.load_mask = CM_PLLC_LOADCORE1,
+		.hold_mask = CM_PLLC_HOLDCORE1,
+		.fixed_divider = 1),
+	[BCM2835_PLLC_CORE2]	= REGISTER_PLL_DIV(
+		.name = "pllc_core2",
+		.source_pll = "pllc",
+		.cm_reg = CM_PLLC,
+		.a2w_reg = A2W_PLLC_CORE2,
+		.load_mask = CM_PLLC_LOADCORE2,
+		.hold_mask = CM_PLLC_HOLDCORE2,
+		.fixed_divider = 1),
+	[BCM2835_PLLC_PER]	= REGISTER_PLL_DIV(
+		.name = "pllc_per",
+		.source_pll = "pllc",
+		.cm_reg = CM_PLLC,
+		.a2w_reg = A2W_PLLC_PER,
+		.load_mask = CM_PLLC_LOADPER,
+		.hold_mask = CM_PLLC_HOLDPER,
+		.fixed_divider = 1),
+
+	/*
+	 * PLLD is the display PLL, used to drive DSI display panels.
+	 *
+	 * It is in the PX LDO power domain, which is on when the
+	 * AUDIO domain is on.
+	 */
+	[BCM2835_PLLD]		= REGISTER_PLL(
+		.name = "plld",
+		.cm_ctrl_reg = CM_PLLD,
+		.a2w_ctrl_reg = A2W_PLLD_CTRL,
+		.frac_reg = A2W_PLLD_FRAC,
+		.ana_reg_base = A2W_PLLD_ANA0,
+		.reference_enable_mask = A2W_XOSC_CTRL_DDR_ENABLE,
+		.lock_mask = CM_LOCK_FLOCKD,
+
+		.ana = &bcm2835_ana_default,
+
+		.min_rate = 600000000u,
+		.max_rate = 2400000000u,
+		.max_fb_rate = BCM2835_MAX_FB_RATE),
+	[BCM2835_PLLD_CORE]	= REGISTER_PLL_DIV(
+		.name = "plld_core",
+		.source_pll = "plld",
+		.cm_reg = CM_PLLD,
+		.a2w_reg = A2W_PLLD_CORE,
+		.load_mask = CM_PLLD_LOADCORE,
+		.hold_mask = CM_PLLD_HOLDCORE,
+		.fixed_divider = 1),
+	[BCM2835_PLLD_PER]	= REGISTER_PLL_DIV(
+		.name = "plld_per",
+		.source_pll = "plld",
+		.cm_reg = CM_PLLD,
+		.a2w_reg = A2W_PLLD_PER,
+		.load_mask = CM_PLLD_LOADPER,
+		.hold_mask = CM_PLLD_HOLDPER,
+		.fixed_divider = 1),
+	[BCM2835_PLLD_DSI0]	= REGISTER_PLL_DIV(
+		.name = "plld_dsi0",
+		.source_pll = "plld",
+		.cm_reg = CM_PLLD,
+		.a2w_reg = A2W_PLLD_DSI0,
+		.load_mask = CM_PLLD_LOADDSI0,
+		.hold_mask = CM_PLLD_HOLDDSI0,
+		.fixed_divider = 1),
+	[BCM2835_PLLD_DSI1]	= REGISTER_PLL_DIV(
+		.name = "plld_dsi1",
+		.source_pll = "plld",
+		.cm_reg = CM_PLLD,
+		.a2w_reg = A2W_PLLD_DSI1,
+		.load_mask = CM_PLLD_LOADDSI1,
+		.hold_mask = CM_PLLD_HOLDDSI1,
+		.fixed_divider = 1),
+
+	/*
+	 * PLLH is used to supply the pixel clock or the AUX clock for the
+	 * TV encoder.
+	 *
+	 * It is in the HDMI power domain.
+	 */
+	[BCM2835_PLLH]		= REGISTER_PLL(
+		"pllh",
+		.cm_ctrl_reg = CM_PLLH,
+		.a2w_ctrl_reg = A2W_PLLH_CTRL,
+		.frac_reg = A2W_PLLH_FRAC,
+		.ana_reg_base = A2W_PLLH_ANA0,
+		.reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE,
+		.lock_mask = CM_LOCK_FLOCKH,
+
+		.ana = &bcm2835_ana_pllh,
+
+		.min_rate = 600000000u,
+		.max_rate = 3000000000u,
+		.max_fb_rate = BCM2835_MAX_FB_RATE),
+	[BCM2835_PLLH_RCAL]	= REGISTER_PLL_DIV(
+		.name = "pllh_rcal",
+		.source_pll = "pllh",
+		.cm_reg = CM_PLLH,
+		.a2w_reg = A2W_PLLH_RCAL,
+		.load_mask = CM_PLLH_LOADRCAL,
+		.hold_mask = 0,
+		.fixed_divider = 10),
+	[BCM2835_PLLH_AUX]	= REGISTER_PLL_DIV(
+		.name = "pllh_aux",
+		.source_pll = "pllh",
+		.cm_reg = CM_PLLH,
+		.a2w_reg = A2W_PLLH_AUX,
+		.load_mask = CM_PLLH_LOADAUX,
+		.hold_mask = 0,
+		.fixed_divider = 10),
+	[BCM2835_PLLH_PIX]	= REGISTER_PLL_DIV(
+		.name = "pllh_pix",
+		.source_pll = "pllh",
+		.cm_reg = CM_PLLH,
+		.a2w_reg = A2W_PLLH_PIX,
+		.load_mask = CM_PLLH_LOADPIX,
+		.hold_mask = 0,
+		.fixed_divider = 10),
+
+	/* the clocks */
+
+	/* clocks with oscillator parent mux */
+
+	/* One Time Programmable Memory clock.  Maximum 10Mhz. */
+	[BCM2835_CLOCK_OTP]	= REGISTER_OSC_CLK(
+		.name = "otp",
+		.ctl_reg = CM_OTPCTL,
+		.div_reg = CM_OTPDIV,
+		.int_bits = 4,
+		.frac_bits = 0),
+	/*
+	 * Used for a 1Mhz clock for the system clocksource, and also used
+	 * bythe watchdog timer and the camera pulse generator.
+	 */
+	[BCM2835_CLOCK_TIMER]	= REGISTER_OSC_CLK(
+		.name = "timer",
+		.ctl_reg = CM_TIMERCTL,
+		.div_reg = CM_TIMERDIV,
+		.int_bits = 6,
+		.frac_bits = 12),
+	/*
+	 * Clock for the temperature sensor.
+	 * Generally run at 2Mhz, max 5Mhz.
+	 */
+	[BCM2835_CLOCK_TSENS]	= REGISTER_OSC_CLK(
+		.name = "tsens",
+		.ctl_reg = CM_TSENSCTL,
+		.div_reg = CM_TSENSDIV,
+		.int_bits = 5,
+		.frac_bits = 0),
+	[BCM2835_CLOCK_TEC]	= REGISTER_OSC_CLK(
+		.name = "tec",
+		.ctl_reg = CM_TECCTL,
+		.div_reg = CM_TECDIV,
+		.int_bits = 6,
+		.frac_bits = 0),
+
+	/* clocks with vpu parent mux */
+	[BCM2835_CLOCK_H264]	= REGISTER_VPU_CLK(
+		.name = "h264",
+		.ctl_reg = CM_H264CTL,
+		.div_reg = CM_H264DIV,
+		.int_bits = 4,
+		.frac_bits = 8),
+	[BCM2835_CLOCK_ISP]	= REGISTER_VPU_CLK(
+		.name = "isp",
+		.ctl_reg = CM_ISPCTL,
+		.div_reg = CM_ISPDIV,
+		.int_bits = 4,
+		.frac_bits = 8),
+
+	/*
+	 * Secondary SDRAM clock.  Used for low-voltage modes when the PLL
+	 * in the SDRAM controller can't be used.
+	 */
+	[BCM2835_CLOCK_SDRAM]	= REGISTER_VPU_CLK(
+		.name = "sdram",
+		.ctl_reg = CM_SDCCTL,
+		.div_reg = CM_SDCDIV,
+		.int_bits = 6,
+		.frac_bits = 0),
+	[BCM2835_CLOCK_V3D]	= REGISTER_VPU_CLK(
+		.name = "v3d",
+		.ctl_reg = CM_V3DCTL,
+		.div_reg = CM_V3DDIV,
+		.int_bits = 4,
+		.frac_bits = 8),
+	/*
+	 * VPU clock.  This doesn't have an enable bit, since it drives
+	 * the bus for everything else, and is special so it doesn't need
+	 * to be gated for rate changes.  It is also known as "clk_audio"
+	 * in various hardware documentation.
+	 */
+	[BCM2835_CLOCK_VPU]	= REGISTER_VPU_CLK(
+		.name = "vpu",
+		.ctl_reg = CM_VPUCTL,
+		.div_reg = CM_VPUDIV,
+		.int_bits = 12,
+		.frac_bits = 8,
+		.is_vpu_clock = true),
+
+	/* clocks with per parent mux */
+	[BCM2835_CLOCK_AVEO]	= REGISTER_PER_CLK(
+		.name = "aveo",
+		.ctl_reg = CM_AVEOCTL,
+		.div_reg = CM_AVEODIV,
+		.int_bits = 4,
+		.frac_bits = 0),
+	[BCM2835_CLOCK_CAM0]	= REGISTER_PER_CLK(
+		.name = "cam0",
+		.ctl_reg = CM_CAM0CTL,
+		.div_reg = CM_CAM0DIV,
+		.int_bits = 4,
+		.frac_bits = 8),
+	[BCM2835_CLOCK_CAM1]	= REGISTER_PER_CLK(
+		.name = "cam1",
+		.ctl_reg = CM_CAM1CTL,
+		.div_reg = CM_CAM1DIV,
+		.int_bits = 4,
+		.frac_bits = 8),
+	[BCM2835_CLOCK_DFT]	= REGISTER_PER_CLK(
+		.name = "dft",
+		.ctl_reg = CM_DFTCTL,
+		.div_reg = CM_DFTDIV,
+		.int_bits = 5,
+		.frac_bits = 0),
+	[BCM2835_CLOCK_DPI]	= REGISTER_PER_CLK(
+		.name = "dpi",
+		.ctl_reg = CM_DPICTL,
+		.div_reg = CM_DPIDIV,
+		.int_bits = 4,
+		.frac_bits = 8),
+
+	/* Arasan EMMC clock */
+	[BCM2835_CLOCK_EMMC]	= REGISTER_PER_CLK(
+		.name = "emmc",
+		.ctl_reg = CM_EMMCCTL,
+		.div_reg = CM_EMMCDIV,
+		.int_bits = 4,
+		.frac_bits = 8),
+
+	/* General purpose (GPIO) clocks */
+	[BCM2835_CLOCK_GP0]	= REGISTER_PER_CLK(
+		.name = "gp0",
+		.ctl_reg = CM_GP0CTL,
+		.div_reg = CM_GP0DIV,
+		.int_bits = 12,
+		.frac_bits = 12,
+		.is_mash_clock = true),
+	[BCM2835_CLOCK_GP1]	= REGISTER_PER_CLK(
+		.name = "gp1",
+		.ctl_reg = CM_GP1CTL,
+		.div_reg = CM_GP1DIV,
+		.int_bits = 12,
+		.frac_bits = 12,
+		.is_mash_clock = true),
+	[BCM2835_CLOCK_GP2]	= REGISTER_PER_CLK(
+		.name = "gp2",
+		.ctl_reg = CM_GP2CTL,
+		.div_reg = CM_GP2DIV,
+		.int_bits = 12,
+		.frac_bits = 12),
+
+	/* HDMI state machine */
+	[BCM2835_CLOCK_HSM]	= REGISTER_PER_CLK(
+		.name = "hsm",
+		.ctl_reg = CM_HSMCTL,
+		.div_reg = CM_HSMDIV,
+		.int_bits = 4,
+		.frac_bits = 8),
+	[BCM2835_CLOCK_PCM]	= REGISTER_PER_CLK(
+		.name = "pcm",
+		.ctl_reg = CM_PCMCTL,
+		.div_reg = CM_PCMDIV,
+		.int_bits = 12,
+		.frac_bits = 12,
+		.is_mash_clock = true),
+	[BCM2835_CLOCK_PWM]	= REGISTER_PER_CLK(
+		.name = "pwm",
+		.ctl_reg = CM_PWMCTL,
+		.div_reg = CM_PWMDIV,
+		.int_bits = 12,
+		.frac_bits = 12,
+		.is_mash_clock = true),
+	[BCM2835_CLOCK_SLIM]	= REGISTER_PER_CLK(
+		.name = "slim",
+		.ctl_reg = CM_SLIMCTL,
+		.div_reg = CM_SLIMDIV,
+		.int_bits = 12,
+		.frac_bits = 12,
+		.is_mash_clock = true),
+	[BCM2835_CLOCK_SMI]	= REGISTER_PER_CLK(
+		.name = "smi",
+		.ctl_reg = CM_SMICTL,
+		.div_reg = CM_SMIDIV,
+		.int_bits = 4,
+		.frac_bits = 8),
+	[BCM2835_CLOCK_UART]	= REGISTER_PER_CLK(
+		.name = "uart",
+		.ctl_reg = CM_UARTCTL,
+		.div_reg = CM_UARTDIV,
+		.int_bits = 10,
+		.frac_bits = 12),
+
+	/* TV encoder clock.  Only operating frequency is 108Mhz.  */
+	[BCM2835_CLOCK_VEC]	= REGISTER_PER_CLK(
+		.name = "vec",
+		.ctl_reg = CM_VECCTL,
+		.div_reg = CM_VECDIV,
+		.int_bits = 4,
+		.frac_bits = 0),
+
+	/* dsi clocks */
+	[BCM2835_CLOCK_DSI0E]	= REGISTER_PER_CLK(
+		.name = "dsi0e",
+		.ctl_reg = CM_DSI0ECTL,
+		.div_reg = CM_DSI0EDIV,
+		.int_bits = 4,
+		.frac_bits = 8),
+	[BCM2835_CLOCK_DSI1E]	= REGISTER_PER_CLK(
+		.name = "dsi1e",
+		.ctl_reg = CM_DSI1ECTL,
+		.div_reg = CM_DSI1EDIV,
+		.int_bits = 4,
+		.frac_bits = 8),
+
+	/* the gates */
+
+	/*
+	 * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if
+	 * you have the debug bit set in the power manager, which we
+	 * don't bother exposing) are individual gates off of the
+	 * non-stop vpu clock.
+	 */
+	[BCM2835_CLOCK_PERI_IMAGE] = REGISTER_GATE(
+		.name = "peri_image",
+		.parent = "vpu",
+		.ctl_reg = CM_PERIICTL),
+};
+
 static int bcm2835_clk_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct clk **clks;
 	struct bcm2835_cprman *cprman;
 	struct resource *res;
+	const struct bcm2835_clk_desc *desc;
+	const size_t asize = ARRAY_SIZE(clk_desc_array);
+	size_t i;
 
-	cprman = devm_kzalloc(dev, sizeof(*cprman), GFP_KERNEL);
+	cprman = devm_kzalloc(dev,
+			      sizeof(*cprman) + asize * sizeof(*clks),
+			      GFP_KERNEL);
 	if (!cprman)
 		return -ENOMEM;
 
@@ -1525,80 +1819,15 @@
 
 	platform_set_drvdata(pdev, cprman);
 
-	cprman->onecell.clk_num = BCM2835_CLOCK_COUNT;
+	cprman->onecell.clk_num = asize;
 	cprman->onecell.clks = cprman->clks;
 	clks = cprman->clks;
 
-	clks[BCM2835_PLLA] = bcm2835_register_pll(cprman, &bcm2835_plla_data);
-	clks[BCM2835_PLLB] = bcm2835_register_pll(cprman, &bcm2835_pllb_data);
-	clks[BCM2835_PLLC] = bcm2835_register_pll(cprman, &bcm2835_pllc_data);
-	clks[BCM2835_PLLD] = bcm2835_register_pll(cprman, &bcm2835_plld_data);
-	clks[BCM2835_PLLH] = bcm2835_register_pll(cprman, &bcm2835_pllh_data);
-
-	clks[BCM2835_PLLA_CORE] =
-		bcm2835_register_pll_divider(cprman, &bcm2835_plla_core_data);
-	clks[BCM2835_PLLA_PER] =
-		bcm2835_register_pll_divider(cprman, &bcm2835_plla_per_data);
-	clks[BCM2835_PLLC_CORE0] =
-		bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core0_data);
-	clks[BCM2835_PLLC_CORE1] =
-		bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core1_data);
-	clks[BCM2835_PLLC_CORE2] =
-		bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core2_data);
-	clks[BCM2835_PLLC_PER] =
-		bcm2835_register_pll_divider(cprman, &bcm2835_pllc_per_data);
-	clks[BCM2835_PLLD_CORE] =
-		bcm2835_register_pll_divider(cprman, &bcm2835_plld_core_data);
-	clks[BCM2835_PLLD_PER] =
-		bcm2835_register_pll_divider(cprman, &bcm2835_plld_per_data);
-	clks[BCM2835_PLLH_RCAL] =
-		bcm2835_register_pll_divider(cprman, &bcm2835_pllh_rcal_data);
-	clks[BCM2835_PLLH_AUX] =
-		bcm2835_register_pll_divider(cprman, &bcm2835_pllh_aux_data);
-	clks[BCM2835_PLLH_PIX] =
-		bcm2835_register_pll_divider(cprman, &bcm2835_pllh_pix_data);
-
-	clks[BCM2835_CLOCK_TIMER] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_timer_data);
-	clks[BCM2835_CLOCK_OTP] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_otp_data);
-	clks[BCM2835_CLOCK_TSENS] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_tsens_data);
-	clks[BCM2835_CLOCK_VPU] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_vpu_data);
-	clks[BCM2835_CLOCK_V3D] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_v3d_data);
-	clks[BCM2835_CLOCK_ISP] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_isp_data);
-	clks[BCM2835_CLOCK_H264] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_h264_data);
-	clks[BCM2835_CLOCK_V3D] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_v3d_data);
-	clks[BCM2835_CLOCK_SDRAM] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_sdram_data);
-	clks[BCM2835_CLOCK_UART] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_uart_data);
-	clks[BCM2835_CLOCK_VEC] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_vec_data);
-	clks[BCM2835_CLOCK_HSM] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_hsm_data);
-	clks[BCM2835_CLOCK_EMMC] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_emmc_data);
-
-	/*
-	 * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if
-	 * you have the debug bit set in the power manager, which we
-	 * don't bother exposing) are individual gates off of the
-	 * non-stop vpu clock.
-	 */
-	clks[BCM2835_CLOCK_PERI_IMAGE] =
-		clk_register_gate(dev, "peri_image", "vpu",
-				  CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE,
-				  cprman->regs + CM_PERIICTL, CM_GATE_BIT,
-				  0, &cprman->regs_lock);
-
-	clks[BCM2835_CLOCK_PWM] =
-		bcm2835_register_clock(cprman, &bcm2835_clock_pwm_data);
+	for (i = 0; i < asize; i++) {
+		desc = &clk_desc_array[i];
+		if (desc->clk_register && desc->data)
+			clks[i] = desc->clk_register(cprman, desc->data);
+	}
 
 	return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
 				   &cprman->onecell);
diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c
index ff4ef4f..1f60b02 100644
--- a/drivers/clk/clk-clps711x.c
+++ b/drivers/clk/clk-clps711x.c
@@ -107,16 +107,15 @@
 	writel(tmp, base + CLPS711X_SYSCON1);
 
 	clps711x_clk->clks[CLPS711X_CLK_DUMMY] =
-		clk_register_fixed_rate(NULL, "dummy", NULL, CLK_IS_ROOT, 0);
+		clk_register_fixed_rate(NULL, "dummy", NULL, 0, 0);
 	clps711x_clk->clks[CLPS711X_CLK_CPU] =
-		clk_register_fixed_rate(NULL, "cpu", NULL, CLK_IS_ROOT, f_cpu);
+		clk_register_fixed_rate(NULL, "cpu", NULL, 0, f_cpu);
 	clps711x_clk->clks[CLPS711X_CLK_BUS] =
-		clk_register_fixed_rate(NULL, "bus", NULL, CLK_IS_ROOT, f_bus);
+		clk_register_fixed_rate(NULL, "bus", NULL, 0, f_bus);
 	clps711x_clk->clks[CLPS711X_CLK_PLL] =
-		clk_register_fixed_rate(NULL, "pll", NULL, CLK_IS_ROOT, f_pll);
+		clk_register_fixed_rate(NULL, "pll", NULL, 0, f_pll);
 	clps711x_clk->clks[CLPS711X_CLK_TIMERREF] =
-		clk_register_fixed_rate(NULL, "timer_ref", NULL, CLK_IS_ROOT,
-					f_tim);
+		clk_register_fixed_rate(NULL, "timer_ref", NULL, 0, f_tim);
 	clps711x_clk->clks[CLPS711X_CLK_TIMER1] =
 		clk_register_divider_table(NULL, "timer1", "timer_ref", 0,
 					   base + CLPS711X_SYSCON1, 5, 1, 0,
@@ -126,10 +125,9 @@
 					   base + CLPS711X_SYSCON1, 7, 1, 0,
 					   timer_div_table, &clps711x_clk->lock);
 	clps711x_clk->clks[CLPS711X_CLK_PWM] =
-		clk_register_fixed_rate(NULL, "pwm", NULL, CLK_IS_ROOT, f_pwm);
+		clk_register_fixed_rate(NULL, "pwm", NULL, 0, f_pwm);
 	clps711x_clk->clks[CLPS711X_CLK_SPIREF] =
-		clk_register_fixed_rate(NULL, "spi_ref", NULL, CLK_IS_ROOT,
-					f_spi);
+		clk_register_fixed_rate(NULL, "spi_ref", NULL, 0, f_spi);
 	clps711x_clk->clks[CLPS711X_CLK_SPI] =
 		clk_register_divider_table(NULL, "spi", "spi_ref", 0,
 					   base + CLPS711X_SYSCON1, 16, 2, 0,
@@ -137,8 +135,7 @@
 	clps711x_clk->clks[CLPS711X_CLK_UART] =
 		clk_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10);
 	clps711x_clk->clks[CLPS711X_CLK_TICK] =
-		clk_register_fixed_rate(NULL, "tick", NULL, CLK_IS_ROOT, 64);
-
+		clk_register_fixed_rate(NULL, "tick", NULL, 0, 64);
 	for (i = 0; i < CLPS711X_CLK_MAX; i++)
 		if (IS_ERR(clps711x_clk->clks[i]))
 			pr_err("clk %i: register failed with %ld\n",
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index b0f3b84..00269de 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -151,6 +151,33 @@
 	return rate_ops->set_rate(rate_hw, rate, parent_rate);
 }
 
+static int clk_composite_set_rate_and_parent(struct clk_hw *hw,
+					     unsigned long rate,
+					     unsigned long parent_rate,
+					     u8 index)
+{
+	struct clk_composite *composite = to_clk_composite(hw);
+	const struct clk_ops *rate_ops = composite->rate_ops;
+	const struct clk_ops *mux_ops = composite->mux_ops;
+	struct clk_hw *rate_hw = composite->rate_hw;
+	struct clk_hw *mux_hw = composite->mux_hw;
+	unsigned long temp_rate;
+
+	__clk_hw_set_clk(rate_hw, hw);
+	__clk_hw_set_clk(mux_hw, hw);
+
+	temp_rate = rate_ops->recalc_rate(rate_hw, parent_rate);
+	if (temp_rate > rate) {
+		rate_ops->set_rate(rate_hw, rate, parent_rate);
+		mux_ops->set_parent(mux_hw, index);
+	} else {
+		mux_ops->set_parent(mux_hw, index);
+		rate_ops->set_rate(rate_hw, rate, parent_rate);
+	}
+
+	return 0;
+}
+
 static int clk_composite_is_enabled(struct clk_hw *hw)
 {
 	struct clk_composite *composite = to_clk_composite(hw);
@@ -184,17 +211,18 @@
 	gate_ops->disable(gate_hw);
 }
 
-struct clk *clk_register_composite(struct device *dev, const char *name,
+struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name,
 			const char * const *parent_names, int num_parents,
 			struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
 			struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
 			struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
 			unsigned long flags)
 {
-	struct clk *clk;
+	struct clk_hw *hw;
 	struct clk_init_data init;
 	struct clk_composite *composite;
 	struct clk_ops *clk_composite_ops;
+	int ret;
 
 	composite = kzalloc(sizeof(*composite), GFP_KERNEL);
 	if (!composite)
@@ -204,12 +232,13 @@
 	init.flags = flags | CLK_IS_BASIC;
 	init.parent_names = parent_names;
 	init.num_parents = num_parents;
+	hw = &composite->hw;
 
 	clk_composite_ops = &composite->ops;
 
 	if (mux_hw && mux_ops) {
 		if (!mux_ops->get_parent) {
-			clk = ERR_PTR(-EINVAL);
+			hw = ERR_PTR(-EINVAL);
 			goto err;
 		}
 
@@ -224,7 +253,7 @@
 
 	if (rate_hw && rate_ops) {
 		if (!rate_ops->recalc_rate) {
-			clk = ERR_PTR(-EINVAL);
+			hw = ERR_PTR(-EINVAL);
 			goto err;
 		}
 		clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
@@ -250,10 +279,16 @@
 		composite->rate_ops = rate_ops;
 	}
 
+	if (mux_hw && mux_ops && rate_hw && rate_ops) {
+		if (mux_ops->set_parent && rate_ops->set_rate)
+			clk_composite_ops->set_rate_and_parent =
+			clk_composite_set_rate_and_parent;
+	}
+
 	if (gate_hw && gate_ops) {
 		if (!gate_ops->is_enabled || !gate_ops->enable ||
 		    !gate_ops->disable) {
-			clk = ERR_PTR(-EINVAL);
+			hw = ERR_PTR(-EINVAL);
 			goto err;
 		}
 
@@ -267,24 +302,43 @@
 	init.ops = clk_composite_ops;
 	composite->hw.init = &init;
 
-	clk = clk_register(dev, &composite->hw);
-	if (IS_ERR(clk))
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
+		hw = ERR_PTR(ret);
 		goto err;
+	}
 
 	if (composite->mux_hw)
-		composite->mux_hw->clk = clk;
+		composite->mux_hw->clk = hw->clk;
 
 	if (composite->rate_hw)
-		composite->rate_hw->clk = clk;
+		composite->rate_hw->clk = hw->clk;
 
 	if (composite->gate_hw)
-		composite->gate_hw->clk = clk;
+		composite->gate_hw->clk = hw->clk;
 
-	return clk;
+	return hw;
 
 err:
 	kfree(composite);
-	return clk;
+	return hw;
+}
+
+struct clk *clk_register_composite(struct device *dev, const char *name,
+			const char * const *parent_names, int num_parents,
+			struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
+			struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
+			struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+			unsigned long flags)
+{
+	struct clk_hw *hw;
+
+	hw = clk_hw_register_composite(dev, name, parent_names, num_parents,
+			mux_hw, mux_ops, rate_hw, rate_ops, gate_hw, gate_ops,
+			flags);
+	if (IS_ERR(hw))
+		return ERR_CAST(hw);
+	return hw->clk;
 }
 
 void clk_unregister_composite(struct clk *clk)
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 00e035b..a0f55bc 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -426,15 +426,16 @@
 };
 EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
 
-static struct clk *_register_divider(struct device *dev, const char *name,
+static struct clk_hw *_register_divider(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 shift, u8 width,
 		u8 clk_divider_flags, const struct clk_div_table *table,
 		spinlock_t *lock)
 {
 	struct clk_divider *div;
-	struct clk *clk;
+	struct clk_hw *hw;
 	struct clk_init_data init;
+	int ret;
 
 	if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
 		if (width + shift > 16) {
@@ -467,12 +468,14 @@
 	div->table = table;
 
 	/* register the clock */
-	clk = clk_register(dev, &div->hw);
-
-	if (IS_ERR(clk))
+	hw = &div->hw;
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
 		kfree(div);
+		hw = ERR_PTR(ret);
+	}
 
-	return clk;
+	return hw;
 }
 
 /**
@@ -492,10 +495,37 @@
 		void __iomem *reg, u8 shift, u8 width,
 		u8 clk_divider_flags, spinlock_t *lock)
 {
+	struct clk_hw *hw;
+
+	hw =  _register_divider(dev, name, parent_name, flags, reg, shift,
+			width, clk_divider_flags, NULL, lock);
+	if (IS_ERR(hw))
+		return ERR_CAST(hw);
+	return hw->clk;
+}
+EXPORT_SYMBOL_GPL(clk_register_divider);
+
+/**
+ * clk_hw_register_divider - register a divider clock with the clock framework
+ * @dev: device registering this clock
+ * @name: name of this clock
+ * @parent_name: name of clock's parent
+ * @flags: framework-specific flags
+ * @reg: register address to adjust divider
+ * @shift: number of bits to shift the bitfield
+ * @width: width of the bitfield
+ * @clk_divider_flags: divider-specific flags for this clock
+ * @lock: shared register lock for this clock
+ */
+struct clk_hw *clk_hw_register_divider(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, spinlock_t *lock)
+{
 	return _register_divider(dev, name, parent_name, flags, reg, shift,
 			width, clk_divider_flags, NULL, lock);
 }
-EXPORT_SYMBOL_GPL(clk_register_divider);
+EXPORT_SYMBOL_GPL(clk_hw_register_divider);
 
 /**
  * clk_register_divider_table - register a table based divider clock with
@@ -517,10 +547,40 @@
 		u8 clk_divider_flags, const struct clk_div_table *table,
 		spinlock_t *lock)
 {
+	struct clk_hw *hw;
+
+	hw =  _register_divider(dev, name, parent_name, flags, reg, shift,
+			width, clk_divider_flags, table, lock);
+	if (IS_ERR(hw))
+		return ERR_CAST(hw);
+	return hw->clk;
+}
+EXPORT_SYMBOL_GPL(clk_register_divider_table);
+
+/**
+ * clk_hw_register_divider_table - register a table based divider clock with
+ * the clock framework
+ * @dev: device registering this clock
+ * @name: name of this clock
+ * @parent_name: name of clock's parent
+ * @flags: framework-specific flags
+ * @reg: register address to adjust divider
+ * @shift: number of bits to shift the bitfield
+ * @width: width of the bitfield
+ * @clk_divider_flags: divider-specific flags for this clock
+ * @table: array of divider/value pairs ending with a div set to 0
+ * @lock: shared register lock for this clock
+ */
+struct clk_hw *clk_hw_register_divider_table(struct device *dev,
+		const char *name, const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, const struct clk_div_table *table,
+		spinlock_t *lock)
+{
 	return _register_divider(dev, name, parent_name, flags, reg, shift,
 			width, clk_divider_flags, table, lock);
 }
-EXPORT_SYMBOL_GPL(clk_register_divider_table);
+EXPORT_SYMBOL_GPL(clk_hw_register_divider_table);
 
 void clk_unregister_divider(struct clk *clk)
 {
@@ -537,3 +597,18 @@
 	kfree(div);
 }
 EXPORT_SYMBOL_GPL(clk_unregister_divider);
+
+/**
+ * clk_hw_unregister_divider - unregister a clk divider
+ * @hw: hardware-specific clock data to unregister
+ */
+void clk_hw_unregister_divider(struct clk_hw *hw)
+{
+	struct clk_divider *div;
+
+	div = to_clk_divider(hw);
+
+	clk_hw_unregister(hw);
+	kfree(div);
+}
+EXPORT_SYMBOL_GPL(clk_hw_unregister_divider);
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index 053448e..75cd6c7 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -68,13 +68,14 @@
 };
 EXPORT_SYMBOL_GPL(clk_fixed_factor_ops);
 
-struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
-		const char *parent_name, unsigned long flags,
+struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
+		const char *name, const char *parent_name, unsigned long flags,
 		unsigned int mult, unsigned int div)
 {
 	struct clk_fixed_factor *fix;
 	struct clk_init_data init;
-	struct clk *clk;
+	struct clk_hw *hw;
+	int ret;
 
 	fix = kmalloc(sizeof(*fix), GFP_KERNEL);
 	if (!fix)
@@ -91,12 +92,28 @@
 	init.parent_names = &parent_name;
 	init.num_parents = 1;
 
-	clk = clk_register(dev, &fix->hw);
-
-	if (IS_ERR(clk))
+	hw = &fix->hw;
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
 		kfree(fix);
+		hw = ERR_PTR(ret);
+	}
 
-	return clk;
+	return hw;
+}
+EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor);
+
+struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		unsigned int mult, unsigned int div)
+{
+	struct clk_hw *hw;
+
+	hw = clk_hw_register_fixed_factor(dev, name, parent_name, flags, mult,
+					  div);
+	if (IS_ERR(hw))
+		return ERR_CAST(hw);
+	return hw->clk;
 }
 EXPORT_SYMBOL_GPL(clk_register_fixed_factor);
 
@@ -113,6 +130,17 @@
 }
 EXPORT_SYMBOL_GPL(clk_unregister_fixed_factor);
 
+void clk_hw_unregister_fixed_factor(struct clk_hw *hw)
+{
+	struct clk_fixed_factor *fix;
+
+	fix = to_clk_fixed_factor(hw);
+
+	clk_hw_unregister(hw);
+	kfree(fix);
+}
+EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_factor);
+
 #ifdef CONFIG_OF
 /**
  * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
index cd9dc92..8e4453e 100644
--- a/drivers/clk/clk-fixed-rate.c
+++ b/drivers/clk/clk-fixed-rate.c
@@ -45,8 +45,8 @@
 EXPORT_SYMBOL_GPL(clk_fixed_rate_ops);
 
 /**
- * clk_register_fixed_rate_with_accuracy - register fixed-rate clock with the
- *					   clock framework
+ * clk_hw_register_fixed_rate_with_accuracy - register fixed-rate clock with
+ * the clock framework
  * @dev: device that is registering this clock
  * @name: name of this clock
  * @parent_name: name of clock's parent
@@ -54,13 +54,14 @@
  * @fixed_rate: non-adjustable clock rate
  * @fixed_accuracy: non-adjustable clock rate
  */
-struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev,
+struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev,
 		const char *name, const char *parent_name, unsigned long flags,
 		unsigned long fixed_rate, unsigned long fixed_accuracy)
 {
 	struct clk_fixed_rate *fixed;
-	struct clk *clk;
+	struct clk_hw *hw;
 	struct clk_init_data init;
+	int ret;
 
 	/* allocate fixed-rate clock */
 	fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
@@ -79,22 +80,49 @@
 	fixed->hw.init = &init;
 
 	/* register the clock */
-	clk = clk_register(dev, &fixed->hw);
-	if (IS_ERR(clk))
+	hw = &fixed->hw;
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
 		kfree(fixed);
+		hw = ERR_PTR(ret);
+	}
 
-	return clk;
+	return hw;
+}
+EXPORT_SYMBOL_GPL(clk_hw_register_fixed_rate_with_accuracy);
+
+struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev,
+		const char *name, const char *parent_name, unsigned long flags,
+		unsigned long fixed_rate, unsigned long fixed_accuracy)
+{
+	struct clk_hw *hw;
+
+	hw = clk_hw_register_fixed_rate_with_accuracy(dev, name, parent_name,
+			flags, fixed_rate, fixed_accuracy);
+	if (IS_ERR(hw))
+		return ERR_CAST(hw);
+	return hw->clk;
 }
 EXPORT_SYMBOL_GPL(clk_register_fixed_rate_with_accuracy);
 
 /**
- * clk_register_fixed_rate - register fixed-rate clock with the clock framework
+ * clk_hw_register_fixed_rate - register fixed-rate clock with the clock
+ * framework
  * @dev: device that is registering this clock
  * @name: name of this clock
  * @parent_name: name of clock's parent
  * @flags: framework-specific flags
  * @fixed_rate: non-adjustable clock rate
  */
+struct clk_hw *clk_hw_register_fixed_rate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		unsigned long fixed_rate)
+{
+	return clk_hw_register_fixed_rate_with_accuracy(dev, name, parent_name,
+						     flags, fixed_rate, 0);
+}
+EXPORT_SYMBOL_GPL(clk_hw_register_fixed_rate);
+
 struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		unsigned long fixed_rate)
diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c
index 1abcd76..aab9046 100644
--- a/drivers/clk/clk-fractional-divider.c
+++ b/drivers/clk/clk-fractional-divider.c
@@ -116,14 +116,15 @@
 };
 EXPORT_SYMBOL_GPL(clk_fractional_divider_ops);
 
-struct clk *clk_register_fractional_divider(struct device *dev,
+struct clk_hw *clk_hw_register_fractional_divider(struct device *dev,
 		const char *name, const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
 		u8 clk_divider_flags, spinlock_t *lock)
 {
 	struct clk_fractional_divider *fd;
 	struct clk_init_data init;
-	struct clk *clk;
+	struct clk_hw *hw;
+	int ret;
 
 	fd = kzalloc(sizeof(*fd), GFP_KERNEL);
 	if (!fd)
@@ -146,10 +147,39 @@
 	fd->lock = lock;
 	fd->hw.init = &init;
 
-	clk = clk_register(dev, &fd->hw);
-	if (IS_ERR(clk))
+	hw = &fd->hw;
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
 		kfree(fd);
+		hw = ERR_PTR(ret);
+	}
 
-	return clk;
+	return hw;
+}
+EXPORT_SYMBOL_GPL(clk_hw_register_fractional_divider);
+
+struct clk *clk_register_fractional_divider(struct device *dev,
+		const char *name, const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
+		u8 clk_divider_flags, spinlock_t *lock)
+{
+	struct clk_hw *hw;
+
+	hw = clk_hw_register_fractional_divider(dev, name, parent_name, flags,
+			reg, mshift, mwidth, nshift, nwidth, clk_divider_flags,
+			lock);
+	if (IS_ERR(hw))
+		return ERR_CAST(hw);
+	return hw->clk;
 }
 EXPORT_SYMBOL_GPL(clk_register_fractional_divider);
+
+void clk_hw_unregister_fractional_divider(struct clk_hw *hw)
+{
+	struct clk_fractional_divider *fd;
+
+	fd = to_clk_fd(hw);
+
+	clk_hw_unregister(hw);
+	kfree(fd);
+}
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index d0d8ec8..4e691e3 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -110,7 +110,7 @@
 EXPORT_SYMBOL_GPL(clk_gate_ops);
 
 /**
- * clk_register_gate - register a gate clock with the clock framework
+ * clk_hw_register_gate - register a gate clock with the clock framework
  * @dev: device that is registering this clock
  * @name: name of this clock
  * @parent_name: name of this clock's parent
@@ -120,14 +120,15 @@
  * @clk_gate_flags: gate-specific flags for this clock
  * @lock: shared register lock for this clock
  */
-struct clk *clk_register_gate(struct device *dev, const char *name,
+struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 bit_idx,
 		u8 clk_gate_flags, spinlock_t *lock)
 {
 	struct clk_gate *gate;
-	struct clk *clk;
+	struct clk_hw *hw;
 	struct clk_init_data init;
+	int ret;
 
 	if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
 		if (bit_idx > 15) {
@@ -154,12 +155,29 @@
 	gate->lock = lock;
 	gate->hw.init = &init;
 
-	clk = clk_register(dev, &gate->hw);
-
-	if (IS_ERR(clk))
+	hw = &gate->hw;
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
 		kfree(gate);
+		hw = ERR_PTR(ret);
+	}
 
-	return clk;
+	return hw;
+}
+EXPORT_SYMBOL_GPL(clk_hw_register_gate);
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock)
+{
+	struct clk_hw *hw;
+
+	hw = clk_hw_register_gate(dev, name, parent_name, flags, reg,
+				  bit_idx, clk_gate_flags, lock);
+	if (IS_ERR(hw))
+		return ERR_CAST(hw);
+	return hw->clk;
 }
 EXPORT_SYMBOL_GPL(clk_register_gate);
 
@@ -178,3 +196,14 @@
 	kfree(gate);
 }
 EXPORT_SYMBOL_GPL(clk_unregister_gate);
+
+void clk_hw_unregister_gate(struct clk_hw *hw)
+{
+	struct clk_gate *gate;
+
+	gate = to_clk_gate(hw);
+
+	clk_hw_unregister(hw);
+	kfree(gate);
+}
+EXPORT_SYMBOL_GPL(clk_hw_unregister_gate);
diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
index 08f65ac..86b2457 100644
--- a/drivers/clk/clk-gpio.c
+++ b/drivers/clk/clk-gpio.c
@@ -94,13 +94,13 @@
 };
 EXPORT_SYMBOL_GPL(clk_gpio_mux_ops);
 
-static struct clk *clk_register_gpio(struct device *dev, const char *name,
+static struct clk_hw *clk_register_gpio(struct device *dev, const char *name,
 		const char * const *parent_names, u8 num_parents, unsigned gpio,
 		bool active_low, unsigned long flags,
 		const struct clk_ops *clk_gpio_ops)
 {
 	struct clk_gpio *clk_gpio;
-	struct clk *clk;
+	struct clk_hw *hw;
 	struct clk_init_data init = {};
 	unsigned long gpio_flags;
 	int err;
@@ -141,24 +141,26 @@
 	clk_gpio->gpiod = gpio_to_desc(gpio);
 	clk_gpio->hw.init = &init;
 
+	hw = &clk_gpio->hw;
 	if (dev)
-		clk = devm_clk_register(dev, &clk_gpio->hw);
+		err = devm_clk_hw_register(dev, hw);
 	else
-		clk = clk_register(NULL, &clk_gpio->hw);
+		err = clk_hw_register(NULL, hw);
 
-	if (!IS_ERR(clk))
-		return clk;
+	if (!err)
+		return hw;
 
 	if (!dev) {
 		gpiod_put(clk_gpio->gpiod);
 		kfree(clk_gpio);
 	}
 
-	return clk;
+	return ERR_PTR(err);
 }
 
 /**
- * clk_register_gpio_gate - register a gpio clock gate with the clock framework
+ * clk_hw_register_gpio_gate - register a gpio clock gate with the clock
+ * framework
  * @dev: device that is registering this clock
  * @name: name of this clock
  * @parent_name: name of this clock's parent
@@ -166,7 +168,7 @@
  * @active_low: true if gpio should be set to 0 to enable clock
  * @flags: clock flags
  */
-struct clk *clk_register_gpio_gate(struct device *dev, const char *name,
+struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name,
 		const char *parent_name, unsigned gpio, bool active_low,
 		unsigned long flags)
 {
@@ -175,10 +177,24 @@
 			(parent_name ? 1 : 0), gpio, active_low, flags,
 			&clk_gpio_gate_ops);
 }
+EXPORT_SYMBOL_GPL(clk_hw_register_gpio_gate);
+
+struct clk *clk_register_gpio_gate(struct device *dev, const char *name,
+		const char *parent_name, unsigned gpio, bool active_low,
+		unsigned long flags)
+{
+	struct clk_hw *hw;
+
+	hw = clk_hw_register_gpio_gate(dev, name, parent_name, gpio, active_low,
+				       flags);
+	if (IS_ERR(hw))
+		return ERR_CAST(hw);
+	return hw->clk;
+}
 EXPORT_SYMBOL_GPL(clk_register_gpio_gate);
 
 /**
- * clk_register_gpio_mux - register a gpio clock mux with the clock framework
+ * clk_hw_register_gpio_mux - register a gpio clock mux with the clock framework
  * @dev: device that is registering this clock
  * @name: name of this clock
  * @parent_names: names of this clock's parents
@@ -187,7 +203,7 @@
  * @active_low: true if gpio should be set to 0 to enable clock
  * @flags: clock flags
  */
-struct clk *clk_register_gpio_mux(struct device *dev, const char *name,
+struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name,
 		const char * const *parent_names, u8 num_parents, unsigned gpio,
 		bool active_low, unsigned long flags)
 {
@@ -199,6 +215,20 @@
 	return clk_register_gpio(dev, name, parent_names, num_parents,
 			gpio, active_low, flags, &clk_gpio_mux_ops);
 }
+EXPORT_SYMBOL_GPL(clk_hw_register_gpio_mux);
+
+struct clk *clk_register_gpio_mux(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents, unsigned gpio,
+		bool active_low, unsigned long flags)
+{
+	struct clk_hw *hw;
+
+	hw = clk_hw_register_gpio_mux(dev, name, parent_names, num_parents,
+			gpio, active_low, flags);
+	if (IS_ERR(hw))
+		return ERR_CAST(hw);
+	return hw->clk;
+}
 EXPORT_SYMBOL_GPL(clk_register_gpio_mux);
 
 static int gpio_clk_driver_probe(struct platform_device *pdev)
diff --git a/drivers/clk/clk-ls1x.c b/drivers/clk/clk-ls1x.c
index d4c6198..5097831 100644
--- a/drivers/clk/clk-ls1x.c
+++ b/drivers/clk/clk-ls1x.c
@@ -88,8 +88,7 @@
 {
 	struct clk *clk;
 
-	clk = clk_register_fixed_rate(NULL, "osc_33m_clk", NULL, CLK_IS_ROOT,
-				      OSC);
+	clk = clk_register_fixed_rate(NULL, "osc_33m_clk", NULL, 0, OSC);
 	clk_register_clkdev(clk, "osc_33m_clk", NULL);
 
 	/* clock derived from 33 MHz OSC clk */
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 252188f..16a3d57 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -113,16 +113,17 @@
 };
 EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
 
-struct clk *clk_register_mux_table(struct device *dev, const char *name,
+struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
 		const char * const *parent_names, u8 num_parents,
 		unsigned long flags,
 		void __iomem *reg, u8 shift, u32 mask,
 		u8 clk_mux_flags, u32 *table, spinlock_t *lock)
 {
 	struct clk_mux *mux;
-	struct clk *clk;
+	struct clk_hw *hw;
 	struct clk_init_data init;
 	u8 width = 0;
+	int ret;
 
 	if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
 		width = fls(mask) - ffs(mask) + 1;
@@ -157,12 +158,31 @@
 	mux->table = table;
 	mux->hw.init = &init;
 
-	clk = clk_register(dev, &mux->hw);
-
-	if (IS_ERR(clk))
+	hw = &mux->hw;
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
 		kfree(mux);
+		hw = ERR_PTR(ret);
+	}
 
-	return clk;
+	return hw;
+}
+EXPORT_SYMBOL_GPL(clk_hw_register_mux_table);
+
+struct clk *clk_register_mux_table(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags,
+		void __iomem *reg, u8 shift, u32 mask,
+		u8 clk_mux_flags, u32 *table, spinlock_t *lock)
+{
+	struct clk_hw *hw;
+
+	hw = clk_hw_register_mux_table(dev, name, parent_names, num_parents,
+				       flags, reg, shift, mask, clk_mux_flags,
+				       table, lock);
+	if (IS_ERR(hw))
+		return ERR_CAST(hw);
+	return hw->clk;
 }
 EXPORT_SYMBOL_GPL(clk_register_mux_table);
 
@@ -180,6 +200,20 @@
 }
 EXPORT_SYMBOL_GPL(clk_register_mux);
 
+struct clk_hw *clk_hw_register_mux(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_mux_flags, spinlock_t *lock)
+{
+	u32 mask = BIT(width) - 1;
+
+	return clk_hw_register_mux_table(dev, name, parent_names, num_parents,
+				      flags, reg, shift, mask, clk_mux_flags,
+				      NULL, lock);
+}
+EXPORT_SYMBOL_GPL(clk_hw_register_mux);
+
 void clk_unregister_mux(struct clk *clk)
 {
 	struct clk_mux *mux;
@@ -195,3 +229,14 @@
 	kfree(mux);
 }
 EXPORT_SYMBOL_GPL(clk_unregister_mux);
+
+void clk_hw_unregister_mux(struct clk_hw *hw)
+{
+	struct clk_mux *mux;
+
+	mux = to_clk_mux(hw);
+
+	clk_hw_unregister(hw);
+	kfree(mux);
+}
+EXPORT_SYMBOL_GPL(clk_hw_unregister_mux);
diff --git a/drivers/clk/clk-nspire.c b/drivers/clk/clk-nspire.c
index a378db7..64f196a 100644
--- a/drivers/clk/clk-nspire.c
+++ b/drivers/clk/clk-nspire.c
@@ -125,8 +125,7 @@
 
 	of_property_read_string(node, "clock-output-names", &clk_name);
 
-	clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT,
-			info.base_clock);
+	clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, info.base_clock);
 	if (!IS_ERR(clk))
 		of_clk_add_provider(node, of_clk_src_simple_get, clk);
 	else
diff --git a/drivers/clk/clk-oxnas.c b/drivers/clk/clk-oxnas.c
new file mode 100644
index 0000000..efba7d4
--- /dev/null
+++ b/drivers/clk/clk-oxnas.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2010 Broadcom
+ * Copyright (C) 2012 Stephen Warren
+ * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/stringify.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+/* Standard regmap gate clocks */
+struct clk_oxnas {
+	struct clk_hw hw;
+	signed char bit;
+	struct regmap *regmap;
+};
+
+/* Regmap offsets */
+#define CLK_STAT_REGOFFSET	0x24
+#define CLK_SET_REGOFFSET	0x2c
+#define CLK_CLR_REGOFFSET	0x30
+
+static inline struct clk_oxnas *to_clk_oxnas(struct clk_hw *hw)
+{
+	return container_of(hw, struct clk_oxnas, hw);
+}
+
+static int oxnas_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_oxnas *std = to_clk_oxnas(hw);
+	int ret;
+	unsigned int val;
+
+	ret = regmap_read(std->regmap, CLK_STAT_REGOFFSET, &val);
+	if (ret < 0)
+		return ret;
+
+	return val & BIT(std->bit);
+}
+
+static int oxnas_clk_enable(struct clk_hw *hw)
+{
+	struct clk_oxnas *std = to_clk_oxnas(hw);
+
+	regmap_write(std->regmap, CLK_SET_REGOFFSET, BIT(std->bit));
+
+	return 0;
+}
+
+static void oxnas_clk_disable(struct clk_hw *hw)
+{
+	struct clk_oxnas *std = to_clk_oxnas(hw);
+
+	regmap_write(std->regmap, CLK_CLR_REGOFFSET, BIT(std->bit));
+}
+
+static const struct clk_ops oxnas_clk_ops = {
+	.enable = oxnas_clk_enable,
+	.disable = oxnas_clk_disable,
+	.is_enabled = oxnas_clk_is_enabled,
+};
+
+static const char *const oxnas_clk_parents[] = {
+	"oscillator",
+};
+
+static const char *const eth_parents[] = {
+	"gmacclk",
+};
+
+#define DECLARE_STD_CLKP(__clk, __parent)			\
+static const struct clk_init_data clk_##__clk##_init = {	\
+	.name = __stringify(__clk),				\
+	.ops = &oxnas_clk_ops,					\
+	.parent_names = __parent,				\
+	.num_parents = ARRAY_SIZE(__parent),			\
+}
+
+#define DECLARE_STD_CLK(__clk) DECLARE_STD_CLKP(__clk, oxnas_clk_parents)
+
+/* Hardware Bit - Clock association */
+struct clk_oxnas_init_data {
+	unsigned long bit;
+	const struct clk_init_data *clk_init;
+};
+
+/* Clk init data declaration */
+DECLARE_STD_CLK(leon);
+DECLARE_STD_CLK(dma_sgdma);
+DECLARE_STD_CLK(cipher);
+DECLARE_STD_CLK(sata);
+DECLARE_STD_CLK(audio);
+DECLARE_STD_CLK(usbmph);
+DECLARE_STD_CLKP(etha, eth_parents);
+DECLARE_STD_CLK(pciea);
+DECLARE_STD_CLK(nand);
+
+/* Table index is clock indice */
+static const struct clk_oxnas_init_data clk_oxnas_init[] = {
+	[0] = {0, &clk_leon_init},
+	[1] = {1, &clk_dma_sgdma_init},
+	[2] = {2, &clk_cipher_init},
+	/* Skip & Do not touch to DDR clock */
+	[3] = {4, &clk_sata_init},
+	[4] = {5, &clk_audio_init},
+	[5] = {6, &clk_usbmph_init},
+	[6] = {7, &clk_etha_init},
+	[7] = {8, &clk_pciea_init},
+	[8] = {9, &clk_nand_init},
+};
+
+struct clk_oxnas_data {
+	struct clk_oxnas clk_oxnas[ARRAY_SIZE(clk_oxnas_init)];
+	struct clk_onecell_data onecell_data[ARRAY_SIZE(clk_oxnas_init)];
+	struct clk *clks[ARRAY_SIZE(clk_oxnas_init)];
+};
+
+static int oxnas_stdclk_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct clk_oxnas_data *clk_oxnas;
+	struct regmap *regmap;
+	int i;
+
+	clk_oxnas = devm_kzalloc(&pdev->dev, sizeof(*clk_oxnas), GFP_KERNEL);
+	if (!clk_oxnas)
+		return -ENOMEM;
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (!regmap) {
+		dev_err(&pdev->dev, "failed to have parent regmap\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(clk_oxnas_init); i++) {
+		struct clk_oxnas *_clk;
+
+		_clk = &clk_oxnas->clk_oxnas[i];
+		_clk->bit = clk_oxnas_init[i].bit;
+		_clk->hw.init = clk_oxnas_init[i].clk_init;
+		_clk->regmap = regmap;
+
+		clk_oxnas->clks[i] =
+			devm_clk_register(&pdev->dev, &_clk->hw);
+		if (WARN_ON(IS_ERR(clk_oxnas->clks[i])))
+			return PTR_ERR(clk_oxnas->clks[i]);
+	}
+
+	clk_oxnas->onecell_data->clks = clk_oxnas->clks;
+	clk_oxnas->onecell_data->clk_num = ARRAY_SIZE(clk_oxnas_init);
+
+	return of_clk_add_provider(np, of_clk_src_onecell_get,
+				   clk_oxnas->onecell_data);
+}
+
+static int oxnas_stdclk_remove(struct platform_device *pdev)
+{
+	of_clk_del_provider(pdev->dev.of_node);
+
+	return 0;
+}
+
+static const struct of_device_id oxnas_stdclk_dt_ids[] = {
+	{ .compatible = "oxsemi,ox810se-stdclk" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, oxnas_stdclk_dt_ids);
+
+static struct platform_driver oxnas_stdclk_driver = {
+	.probe = oxnas_stdclk_probe,
+	.remove = oxnas_stdclk_remove,
+	.driver	= {
+		.name = "oxnas-stdclk",
+		.of_match_table = oxnas_stdclk_dt_ids,
+	},
+};
+
+module_platform_driver(oxnas_stdclk_driver);
diff --git a/drivers/clk/clk-palmas.c b/drivers/clk/clk-palmas.c
index 9c0b8e6..8328863 100644
--- a/drivers/clk/clk-palmas.c
+++ b/drivers/clk/clk-palmas.c
@@ -132,7 +132,7 @@
 	.init = {
 		.name = "clk32kg",
 		.ops = &palmas_clks_ops,
-		.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED,
+		.flags = CLK_IGNORE_UNUSED,
 	},
 	.desc = {
 		.clk_name = "clk32kg",
@@ -148,7 +148,7 @@
 	.init = {
 		.name = "clk32kgaudio",
 		.ops = &palmas_clks_ops,
-		.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED,
+		.flags = CLK_IGNORE_UNUSED,
 	},
 	.desc = {
 		.clk_name = "clk32kgaudio",
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c
index 7bc1c45..58566a17 100644
--- a/drivers/clk/clk-qoriq.c
+++ b/drivers/clk/clk-qoriq.c
@@ -869,14 +869,15 @@
 	}
 }
 
-static struct clk *sysclk_from_fixed(struct device_node *node, const char *name)
+static struct clk __init
+*sysclk_from_fixed(struct device_node *node, const char *name)
 {
 	u32 rate;
 
 	if (of_property_read_u32(node, "clock-frequency", &rate))
 		return ERR_PTR(-ENODEV);
 
-	return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);
+	return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
 }
 
 static struct clk *sysclk_from_parent(const char *name)
diff --git a/drivers/clk/clk-rk808.c b/drivers/clk/clk-rk808.c
index 0fee2f4..7438303 100644
--- a/drivers/clk/clk-rk808.c
+++ b/drivers/clk/clk-rk808.c
@@ -106,7 +106,6 @@
 	if (!clk_table)
 		return -ENOMEM;
 
-	init.flags = CLK_IS_ROOT;
 	init.parent_names = NULL;
 	init.num_parents = 0;
 	init.name = "rk808-clkout1";
diff --git a/drivers/clk/clk-tango4.c b/drivers/clk/clk-tango4.c
index 004ab7d..eef75e3 100644
--- a/drivers/clk/clk-tango4.c
+++ b/drivers/clk/clk-tango4.c
@@ -4,17 +4,19 @@
 #include <linux/init.h>
 #include <linux/io.h>
 
-static struct clk *out[2];
-static struct clk_onecell_data clk_data = { out, 2 };
+#define CLK_COUNT 4 /* cpu_clk, sys_clk, usb_clk, sdio_clk */
+static struct clk *clks[CLK_COUNT];
+static struct clk_onecell_data clk_data = { clks, CLK_COUNT };
 
-#define SYSCLK_CTRL	0x20
-#define CPUCLK_CTRL	0x24
-#define LEGACY_DIV	0x3c
+#define SYSCLK_DIV	0x20
+#define CPUCLK_DIV	0x24
+#define DIV_BYPASS	BIT(23)
 
-#define PLL_N(val)	(((val) >>  0) & 0x7f)
-#define PLL_K(val)	(((val) >> 13) & 0x7)
-#define PLL_M(val)	(((val) >> 16) & 0x7)
-#define DIV_INDEX(val)	(((val) >>  8) & 0xf)
+/*** CLKGEN_PLL ***/
+#define extract_pll_n(val)	((val >>  0) & ((1u << 7) - 1))
+#define extract_pll_k(val)	((val >> 13) & ((1u << 3) - 1))
+#define extract_pll_m(val)	((val >> 16) & ((1u << 3) - 1))
+#define extract_pll_isel(val)	((val >> 24) & ((1u << 3) - 1))
 
 static void __init make_pll(int idx, const char *parent, void __iomem *base)
 {
@@ -22,40 +24,61 @@
 	u32 val, mul, div;
 
 	sprintf(name, "pll%d", idx);
-	val = readl_relaxed(base + idx*8);
-	mul =  PLL_N(val) + 1;
-	div = (PLL_M(val) + 1) << PLL_K(val);
+	val = readl(base + idx * 8);
+	mul =  extract_pll_n(val) + 1;
+	div = (extract_pll_m(val) + 1) << extract_pll_k(val);
 	clk_register_fixed_factor(NULL, name, parent, 0, mul, div);
+	if (extract_pll_isel(val) != 1)
+		panic("%s: input not set to XTAL_IN\n", name);
 }
 
-static int __init get_div(void __iomem *base)
+static void __init make_cd(int idx, void __iomem *base)
 {
-	u8 sysclk_tab[16] = { 2, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4 };
-	int idx = DIV_INDEX(readl_relaxed(base + LEGACY_DIV));
+	char name[8];
+	u32 val, mul, div;
 
-	return sysclk_tab[idx];
+	sprintf(name, "cd%d", idx);
+	val = readl(base + idx * 8);
+	mul =  1 << 27;
+	div = (2 << 27) + val;
+	clk_register_fixed_factor(NULL, name, "pll2", 0, mul, div);
+	if (val > 0xf0000000)
+		panic("%s: unsupported divider %x\n", name, val);
 }
 
 static void __init tango4_clkgen_setup(struct device_node *np)
 {
-	int div, ret;
+	struct clk **pp = clk_data.clks;
 	void __iomem *base = of_iomap(np, 0);
 	const char *parent = of_clk_get_parent_name(np, 0);
 
 	if (!base)
-		panic("%s: invalid address\n", np->full_name);
+		panic("%s: invalid address\n", np->name);
+
+	if (readl(base + CPUCLK_DIV) & DIV_BYPASS)
+		panic("%s: unsupported cpuclk setup\n", np->name);
+
+	if (readl(base + SYSCLK_DIV) & DIV_BYPASS)
+		panic("%s: unsupported sysclk setup\n", np->name);
+
+	writel(0x100, base + CPUCLK_DIV); /* disable frequency ramping */
 
 	make_pll(0, parent, base);
 	make_pll(1, parent, base);
+	make_pll(2, parent, base);
+	make_cd(2, base + 0x80);
+	make_cd(6, base + 0x80);
 
-	out[0] = clk_register_divider(NULL, "cpuclk", "pll0", 0,
-			base + CPUCLK_CTRL, 8, 8, CLK_DIVIDER_ONE_BASED, NULL);
+	pp[0] = clk_register_divider(NULL, "cpu_clk", "pll0", 0,
+			base + CPUCLK_DIV, 8, 8, CLK_DIVIDER_ONE_BASED, NULL);
+	pp[1] = clk_register_fixed_factor(NULL, "sys_clk", "pll1", 0, 1, 4);
+	pp[2] = clk_register_fixed_factor(NULL,  "usb_clk", "cd2", 0, 1, 2);
+	pp[3] = clk_register_fixed_factor(NULL, "sdio_clk", "cd6", 0, 1, 2);
 
-	div = readl_relaxed(base + SYSCLK_CTRL) & BIT(23) ? get_div(base) : 4;
-	out[1] = clk_register_fixed_factor(NULL, "sysclk", "pll1", 0, 1, div);
+	if (IS_ERR(pp[0]) || IS_ERR(pp[1]) || IS_ERR(pp[2]) || IS_ERR(pp[3]))
+		panic("%s: clk registration failed\n", np->name);
 
-	ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
-	if (IS_ERR(out[0]) || IS_ERR(out[1]) || ret < 0)
-		panic("%s: clk registration failed\n", np->full_name);
+	if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data))
+		panic("%s: clk provider registration failed\n", np->name);
 }
 CLK_OF_DECLARE(tango4_clkgen, "sigma,tango4-clkgen", tango4_clkgen_setup);
diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c
index 8e5ed64..697c667 100644
--- a/drivers/clk/clk-twl6040.c
+++ b/drivers/clk/clk-twl6040.c
@@ -74,7 +74,6 @@
 static struct clk_init_data wm831x_clkout_init = {
 	.name = "mcpdm_fclk",
 	.ops = &twl6040_mcpdm_ops,
-	.flags = CLK_IS_ROOT,
 };
 
 static int twl6040_clk_probe(struct platform_device *pdev)
diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c
index 43f9d15..88def4b 100644
--- a/drivers/clk/clk-wm831x.c
+++ b/drivers/clk/clk-wm831x.c
@@ -58,7 +58,6 @@
 static struct clk_init_data wm831x_xtal_init = {
 	.name = "xtal",
 	.ops = &wm831x_xtal_ops,
-	.flags = CLK_IS_ROOT,
 };
 
 static const unsigned long wm831x_fll_auto_rates[] = {
diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c
index d73450b..3433132 100644
--- a/drivers/clk/clk-xgene.c
+++ b/drivers/clk/clk-xgene.c
@@ -198,7 +198,7 @@
 	of_property_read_string(np, "clock-output-names", &clk_name);
 	clk = xgene_register_clk_pll(NULL,
 			clk_name, of_clk_get_parent_name(np, 0),
-			CLK_IS_ROOT, reg, 0, pll_type, &clk_lock,
+			0, reg, 0, pll_type, &clk_lock,
 			version);
 	if (!IS_ERR(clk)) {
 		of_clk_add_provider(np, of_clk_src_simple_get, clk);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index fb74dc1..ba1c3647 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -574,6 +574,9 @@
 	if (WARN_ON(core->prepare_count == 0))
 		return;
 
+	if (WARN_ON(core->prepare_count == 1 && core->flags & CLK_IS_CRITICAL))
+		return;
+
 	if (--core->prepare_count > 0)
 		return;
 
@@ -679,6 +682,9 @@
 	if (WARN_ON(core->enable_count == 0))
 		return;
 
+	if (WARN_ON(core->enable_count == 1 && core->flags & CLK_IS_CRITICAL))
+		return;
+
 	if (--core->enable_count > 0)
 		return;
 
@@ -2397,6 +2403,11 @@
 	if (core->ops->init)
 		core->ops->init(core->hw);
 
+	if (core->flags & CLK_IS_CRITICAL) {
+		clk_core_prepare(core);
+		clk_core_enable(core);
+	}
+
 	kref_init(&core->ref);
 out:
 	clk_prepare_unlock();
@@ -2536,6 +2547,22 @@
 }
 EXPORT_SYMBOL_GPL(clk_register);
 
+/**
+ * clk_hw_register - register a clk_hw and return an error code
+ * @dev: device that is registering this clock
+ * @hw: link to hardware-specific clock data
+ *
+ * clk_hw_register is the primary interface for populating the clock tree with
+ * new clock nodes. It returns an integer equal to zero indicating success or
+ * less than zero indicating failure. Drivers must test for an error code after
+ * calling clk_hw_register().
+ */
+int clk_hw_register(struct device *dev, struct clk_hw *hw)
+{
+	return PTR_ERR_OR_ZERO(clk_register(dev, hw));
+}
+EXPORT_SYMBOL_GPL(clk_hw_register);
+
 /* Free memory allocated for a clock. */
 static void __clk_release(struct kref *ref)
 {
@@ -2637,11 +2664,26 @@
 }
 EXPORT_SYMBOL_GPL(clk_unregister);
 
+/**
+ * clk_hw_unregister - unregister a currently registered clk_hw
+ * @hw: hardware-specific clock data to unregister
+ */
+void clk_hw_unregister(struct clk_hw *hw)
+{
+	clk_unregister(hw->clk);
+}
+EXPORT_SYMBOL_GPL(clk_hw_unregister);
+
 static void devm_clk_release(struct device *dev, void *res)
 {
 	clk_unregister(*(struct clk **)res);
 }
 
+static void devm_clk_hw_release(struct device *dev, void *res)
+{
+	clk_hw_unregister(*(struct clk_hw **)res);
+}
+
 /**
  * devm_clk_register - resource managed clk_register()
  * @dev: device that is registering this clock
@@ -2672,6 +2714,36 @@
 }
 EXPORT_SYMBOL_GPL(devm_clk_register);
 
+/**
+ * devm_clk_hw_register - resource managed clk_hw_register()
+ * @dev: device that is registering this clock
+ * @hw: link to hardware-specific clock data
+ *
+ * Managed clk_hw_register(). Clocks returned from this function are
+ * automatically clk_hw_unregister()ed on driver detach. See clk_hw_register()
+ * for more information.
+ */
+int devm_clk_hw_register(struct device *dev, struct clk_hw *hw)
+{
+	struct clk_hw **hwp;
+	int ret;
+
+	hwp = devres_alloc(devm_clk_hw_release, sizeof(*hwp), GFP_KERNEL);
+	if (!hwp)
+		return -ENOMEM;
+
+	ret = clk_hw_register(dev, hw);
+	if (!ret) {
+		*hwp = hw;
+		devres_add(dev, hwp);
+	} else {
+		devres_free(hwp);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(devm_clk_hw_register);
+
 static int devm_clk_match(struct device *dev, void *res, void *data)
 {
 	struct clk *c = res;
@@ -2680,6 +2752,15 @@
 	return c == data;
 }
 
+static int devm_clk_hw_match(struct device *dev, void *res, void *data)
+{
+	struct clk_hw *hw = res;
+
+	if (WARN_ON(!hw))
+		return 0;
+	return hw == data;
+}
+
 /**
  * devm_clk_unregister - resource managed clk_unregister()
  * @clk: clock to unregister
@@ -2694,6 +2775,22 @@
 }
 EXPORT_SYMBOL_GPL(devm_clk_unregister);
 
+/**
+ * devm_clk_hw_unregister - resource managed clk_hw_unregister()
+ * @dev: device that is unregistering the hardware-specific clock data
+ * @hw: link to hardware-specific clock data
+ *
+ * Unregister a clk_hw registered with devm_clk_hw_register(). Normally
+ * this function will not need to be called and the resource management
+ * code will ensure that the resource is freed.
+ */
+void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw)
+{
+	WARN_ON(devres_release(dev, devm_clk_hw_release, devm_clk_hw_match,
+				hw));
+}
+EXPORT_SYMBOL_GPL(devm_clk_hw_unregister);
+
 /*
  * clkdev helpers
  */
@@ -2855,6 +2952,7 @@
 
 	struct device_node *node;
 	struct clk *(*get)(struct of_phandle_args *clkspec, void *data);
+	struct clk_hw *(*get_hw)(struct of_phandle_args *clkspec, void *data);
 	void *data;
 };
 
@@ -2871,6 +2969,12 @@
 }
 EXPORT_SYMBOL_GPL(of_clk_src_simple_get);
 
+struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data)
+{
+	return data;
+}
+EXPORT_SYMBOL_GPL(of_clk_hw_simple_get);
+
 struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
 {
 	struct clk_onecell_data *clk_data = data;
@@ -2885,6 +2989,21 @@
 }
 EXPORT_SYMBOL_GPL(of_clk_src_onecell_get);
 
+struct clk_hw *
+of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data)
+{
+	struct clk_hw_onecell_data *hw_data = data;
+	unsigned int idx = clkspec->args[0];
+
+	if (idx >= hw_data->num) {
+		pr_err("%s: invalid index %u\n", __func__, idx);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return hw_data->hws[idx];
+}
+EXPORT_SYMBOL_GPL(of_clk_hw_onecell_get);
+
 /**
  * of_clk_add_provider() - Register a clock provider for a node
  * @np: Device node pointer associated with clock provider
@@ -2921,6 +3040,41 @@
 EXPORT_SYMBOL_GPL(of_clk_add_provider);
 
 /**
+ * of_clk_add_hw_provider() - Register a clock provider for a node
+ * @np: Device node pointer associated with clock provider
+ * @get: callback for decoding clk_hw
+ * @data: context pointer for @get callback.
+ */
+int of_clk_add_hw_provider(struct device_node *np,
+			   struct clk_hw *(*get)(struct of_phandle_args *clkspec,
+						 void *data),
+			   void *data)
+{
+	struct of_clk_provider *cp;
+	int ret;
+
+	cp = kzalloc(sizeof(*cp), GFP_KERNEL);
+	if (!cp)
+		return -ENOMEM;
+
+	cp->node = of_node_get(np);
+	cp->data = data;
+	cp->get_hw = get;
+
+	mutex_lock(&of_clk_mutex);
+	list_add(&cp->link, &of_clk_providers);
+	mutex_unlock(&of_clk_mutex);
+	pr_debug("Added clk_hw provider from %s\n", np->full_name);
+
+	ret = of_clk_set_defaults(np, true);
+	if (ret < 0)
+		of_clk_del_provider(np);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(of_clk_add_hw_provider);
+
+/**
  * of_clk_del_provider() - Remove a previously registered clock provider
  * @np: Device node pointer associated with clock provider
  */
@@ -2941,11 +3095,32 @@
 }
 EXPORT_SYMBOL_GPL(of_clk_del_provider);
 
+static struct clk_hw *
+__of_clk_get_hw_from_provider(struct of_clk_provider *provider,
+			      struct of_phandle_args *clkspec)
+{
+	struct clk *clk;
+	struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
+
+	if (provider->get_hw) {
+		hw = provider->get_hw(clkspec, provider->data);
+	} else if (provider->get) {
+		clk = provider->get(clkspec, provider->data);
+		if (!IS_ERR(clk))
+			hw = __clk_get_hw(clk);
+		else
+			hw = ERR_CAST(clk);
+	}
+
+	return hw;
+}
+
 struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
 				       const char *dev_id, const char *con_id)
 {
 	struct of_clk_provider *provider;
 	struct clk *clk = ERR_PTR(-EPROBE_DEFER);
+	struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
 
 	if (!clkspec)
 		return ERR_PTR(-EINVAL);
@@ -2954,10 +3129,9 @@
 	mutex_lock(&of_clk_mutex);
 	list_for_each_entry(provider, &of_clk_providers, link) {
 		if (provider->node == clkspec->np)
-			clk = provider->get(clkspec, provider->data);
-		if (!IS_ERR(clk)) {
-			clk = __clk_create_clk(__clk_get_hw(clk), dev_id,
-					       con_id);
+			hw = __of_clk_get_hw_from_provider(provider, clkspec);
+		if (!IS_ERR(hw)) {
+			clk = __clk_create_clk(hw, dev_id, con_id);
 
 			if (!IS_ERR(clk) && !__clk_get(clk)) {
 				__clk_free_clk(clk);
@@ -3127,6 +3301,41 @@
 }
 
 /**
+ * of_clk_detect_critical() - set CLK_IS_CRITICAL flag from Device Tree
+ * @np: Device node pointer associated with clock provider
+ * @index: clock index
+ * @flags: pointer to clk_core->flags
+ *
+ * Detects if the clock-critical property exists and, if so, sets the
+ * corresponding CLK_IS_CRITICAL flag.
+ *
+ * Do not use this function. It exists only for legacy Device Tree
+ * bindings, such as the one-clock-per-node style that are outdated.
+ * Those bindings typically put all clock data into .dts and the Linux
+ * driver has no clock data, thus making it impossible to set this flag
+ * correctly from the driver. Only those drivers may call
+ * of_clk_detect_critical from their setup functions.
+ *
+ * Return: error code or zero on success
+ */
+int of_clk_detect_critical(struct device_node *np,
+					  int index, unsigned long *flags)
+{
+	struct property *prop;
+	const __be32 *cur;
+	uint32_t idx;
+
+	if (!np || !flags)
+		return -EINVAL;
+
+	of_property_for_each_u32(np, "clock-critical", prop, cur, idx)
+		if (index == idx)
+			*flags |= CLK_IS_CRITICAL;
+
+	return 0;
+}
+
+/**
  * of_clk_init() - Scan and init clock providers from the DT
  * @matches: array of compatible values and init functions for providers.
  *
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index eb20b94..89cc700 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -301,6 +301,20 @@
 }
 EXPORT_SYMBOL(clkdev_alloc);
 
+struct clk_lookup *
+clkdev_hw_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt, ...)
+{
+	struct clk_lookup *cl;
+	va_list ap;
+
+	va_start(ap, dev_fmt);
+	cl = vclkdev_alloc(hw, con_id, dev_fmt, ap);
+	va_end(ap);
+
+	return cl;
+}
+EXPORT_SYMBOL(clkdev_hw_alloc);
+
 /**
  * clkdev_create - allocate and add a clkdev lookup structure
  * @clk: struct clk to associate with all clk_lookups
@@ -324,6 +338,29 @@
 }
 EXPORT_SYMBOL_GPL(clkdev_create);
 
+/**
+ * clkdev_hw_create - allocate and add a clkdev lookup structure
+ * @hw: struct clk_hw to associate with all clk_lookups
+ * @con_id: connection ID string on device
+ * @dev_fmt: format string describing device name
+ *
+ * Returns a clk_lookup structure, which can be later unregistered and
+ * freed.
+ */
+struct clk_lookup *clkdev_hw_create(struct clk_hw *hw, const char *con_id,
+	const char *dev_fmt, ...)
+{
+	struct clk_lookup *cl;
+	va_list ap;
+
+	va_start(ap, dev_fmt);
+	cl = vclkdev_create(hw, con_id, dev_fmt, ap);
+	va_end(ap);
+
+	return cl;
+}
+EXPORT_SYMBOL_GPL(clkdev_hw_create);
+
 int clk_add_alias(const char *alias, const char *alias_dev_name,
 	const char *con_id, struct device *dev)
 {
@@ -404,28 +441,28 @@
 EXPORT_SYMBOL(clk_register_clkdev);
 
 /**
- * clk_register_clkdevs - register a set of clk_lookup for a struct clk
- * @clk: struct clk to associate with all clk_lookups
- * @cl: array of clk_lookup structures with con_id and dev_id pre-initialized
- * @num: number of clk_lookup structures to register
+ * clk_hw_register_clkdev - register one clock lookup for a struct clk_hw
+ * @hw: struct clk_hw to associate with all clk_lookups
+ * @con_id: connection ID string on device
+ * @dev_id: format string describing device name
  *
- * To make things easier for mass registration, we detect error clks
- * from a previous clk_register() call, and return the error code for
- * those.  This is to permit this function to be called immediately
- * after clk_register().
+ * con_id or dev_id may be NULL as a wildcard, just as in the rest of
+ * clkdev.
  */
-int clk_register_clkdevs(struct clk *clk, struct clk_lookup *cl, size_t num)
+int clk_hw_register_clkdev(struct clk_hw *hw, const char *con_id,
+	const char *dev_id)
 {
-	unsigned i;
+	struct clk_lookup *cl;
 
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	/*
+	 * Since dev_id can be NULL, and NULL is handled specially, we must
+	 * pass it as either a NULL format string, or with "%s".
+	 */
+	if (dev_id)
+		cl = __clk_register_clkdev(hw, con_id, "%s", dev_id);
+	else
+		cl = __clk_register_clkdev(hw, con_id, NULL);
 
-	for (i = 0; i < num; i++, cl++) {
-		cl->clk_hw = __clk_get_hw(clk);
-		__clkdev_add(cl);
-	}
-
-	return 0;
+	return cl ? 0 : -ENOMEM;
 }
-EXPORT_SYMBOL(clk_register_clkdevs);
+EXPORT_SYMBOL(clk_hw_register_clkdev);
diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
index 8935bff..db44a19 100644
--- a/drivers/clk/imx/clk-gate2.c
+++ b/drivers/clk/imx/clk-gate2.c
@@ -31,6 +31,7 @@
 	struct clk_hw hw;
 	void __iomem	*reg;
 	u8		bit_idx;
+	u8		cgr_val;
 	u8		flags;
 	spinlock_t	*lock;
 	unsigned int	*share_count;
@@ -50,7 +51,8 @@
 		goto out;
 
 	reg = readl(gate->reg);
-	reg |= 3 << gate->bit_idx;
+	reg &= ~(3 << gate->bit_idx);
+	reg |= gate->cgr_val << gate->bit_idx;
 	writel(reg, gate->reg);
 
 out:
@@ -125,7 +127,7 @@
 
 struct clk *clk_register_gate2(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
-		void __iomem *reg, u8 bit_idx,
+		void __iomem *reg, u8 bit_idx, u8 cgr_val,
 		u8 clk_gate2_flags, spinlock_t *lock,
 		unsigned int *share_count)
 {
@@ -140,6 +142,7 @@
 	/* struct clk_gate2 assignments */
 	gate->reg = reg;
 	gate->bit_idx = bit_idx;
+	gate->cgr_val = cgr_val;
 	gate->flags = clk_gate2_flags;
 	gate->lock = lock;
 	gate->share_count = share_count;
diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c
index fea125e..97e742a 100644
--- a/drivers/clk/imx/clk-imx6sx.c
+++ b/drivers/clk/imx/clk-imx6sx.c
@@ -134,6 +134,8 @@
 static u32 share_count_ssi1;
 static u32 share_count_ssi2;
 static u32 share_count_ssi3;
+static u32 share_count_sai1;
+static u32 share_count_sai2;
 
 static struct clk ** const uart_clks[] __initconst = {
 	&clks[IMX6SX_CLK_UART_IPG],
@@ -469,10 +471,10 @@
 	clks[IMX6SX_CLK_SSI3]         = imx_clk_gate2_shared("ssi3",          "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
 	clks[IMX6SX_CLK_UART_IPG]     = imx_clk_gate2("uart_ipg",      "ipg",               base + 0x7c, 24);
 	clks[IMX6SX_CLK_UART_SERIAL]  = imx_clk_gate2("uart_serial",   "uart_podf",         base + 0x7c, 26);
-	clks[IMX6SX_CLK_SAI1_IPG]     = imx_clk_gate2("sai1_ipg",      "ipg",               base + 0x7c, 28);
-	clks[IMX6SX_CLK_SAI2_IPG]     = imx_clk_gate2("sai2_ipg",      "ipg",               base + 0x7c, 30);
-	clks[IMX6SX_CLK_SAI1]         = imx_clk_gate2("sai1",          "ssi1_podf",         base + 0x7c, 28);
-	clks[IMX6SX_CLK_SAI2]         = imx_clk_gate2("sai2",          "ssi2_podf",         base + 0x7c, 30);
+	clks[IMX6SX_CLK_SAI1_IPG]     = imx_clk_gate2_shared("sai1_ipg", "ipg",             base + 0x7c, 28, &share_count_sai1);
+	clks[IMX6SX_CLK_SAI2_IPG]     = imx_clk_gate2_shared("sai2_ipg", "ipg",             base + 0x7c, 30, &share_count_sai2);
+	clks[IMX6SX_CLK_SAI1]         = imx_clk_gate2_shared("sai1",	"ssi1_podf",        base + 0x7c, 28, &share_count_sai1);
+	clks[IMX6SX_CLK_SAI2]         = imx_clk_gate2_shared("sai2",	"ssi2_podf",        base + 0x7c, 30, &share_count_sai2);
 
 	/* CCGR6 */
 	clks[IMX6SX_CLK_USBOH3]       = imx_clk_gate2("usboh3",        "ipg",               base + 0x80, 0);
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index fbb6a8c..7912be8 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -342,7 +342,7 @@
 
 static const char *clko2_sel[] = { "osc", "pll_sys_main_240m_clk",
 	"pll_sys_pfd0_392m_clk", "pll_sys_pfd1_166m_clk", "pll_sys_pfd4_clk",
-	"pll_audio_main_clk", "pll_video_main_clk", "osc_32k_clk", };
+	"pll_audio_main_clk", "pll_video_main_clk", "ckil", };
 
 static const char *lvds1_sel[] = { "pll_arm_main_clk",
 	"pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd1_332m_clk",
@@ -382,6 +382,7 @@
 
 	clks[IMX7D_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
 	clks[IMX7D_OSC_24M_CLK] = of_clk_get_by_name(ccm_node, "osc");
+	clks[IMX7D_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop");
 	base = of_iomap(np, 0);
diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c
index 0a94d96..3a1f244 100644
--- a/drivers/clk/imx/clk-vf610.c
+++ b/drivers/clk/imx/clk-vf610.c
@@ -10,6 +10,7 @@
 
 #include <linux/of_address.h>
 #include <linux/clk.h>
+#include <linux/syscore_ops.h>
 #include <dt-bindings/clock/vf610-clock.h>
 
 #include "clk.h"
@@ -40,6 +41,7 @@
 #define CCM_CCGR9		(ccm_base + 0x64)
 #define CCM_CCGR10		(ccm_base + 0x68)
 #define CCM_CCGR11		(ccm_base + 0x6c)
+#define CCM_CCGRx(x)		(CCM_CCGR0 + (x) * 4)
 #define CCM_CMEOR0		(ccm_base + 0x70)
 #define CCM_CMEOR1		(ccm_base + 0x74)
 #define CCM_CMEOR2		(ccm_base + 0x78)
@@ -115,10 +117,19 @@
 static struct clk *clk[VF610_CLK_END];
 static struct clk_onecell_data clk_data;
 
+static u32 cscmr1;
+static u32 cscmr2;
+static u32 cscdr1;
+static u32 cscdr2;
+static u32 cscdr3;
+static u32 ccgr[12];
+
 static unsigned int const clks_init_on[] __initconst = {
 	VF610_CLK_SYS_BUS,
 	VF610_CLK_DDR_SEL,
 	VF610_CLK_DAP,
+	VF610_CLK_DDRMC,
+	VF610_CLK_WKPU,
 };
 
 static struct clk * __init vf610_get_fixed_clock(
@@ -132,6 +143,43 @@
 	return clk;
 };
 
+static int vf610_clk_suspend(void)
+{
+	int i;
+
+	cscmr1 = readl_relaxed(CCM_CSCMR1);
+	cscmr2 = readl_relaxed(CCM_CSCMR2);
+
+	cscdr1 = readl_relaxed(CCM_CSCDR1);
+	cscdr2 = readl_relaxed(CCM_CSCDR2);
+	cscdr3 = readl_relaxed(CCM_CSCDR3);
+
+	for (i = 0; i < 12; i++)
+		ccgr[i] = readl_relaxed(CCM_CCGRx(i));
+
+	return 0;
+}
+
+static void vf610_clk_resume(void)
+{
+	int i;
+
+	writel_relaxed(cscmr1, CCM_CSCMR1);
+	writel_relaxed(cscmr2, CCM_CSCMR2);
+
+	writel_relaxed(cscdr1, CCM_CSCDR1);
+	writel_relaxed(cscdr2, CCM_CSCDR2);
+	writel_relaxed(cscdr3, CCM_CSCDR3);
+
+	for (i = 0; i < 12; i++)
+		writel_relaxed(ccgr[i], CCM_CCGRx(i));
+}
+
+static struct syscore_ops vf610_clk_syscore_ops = {
+	.suspend = vf610_clk_suspend,
+	.resume = vf610_clk_resume,
+};
+
 static void __init vf610_clocks_init(struct device_node *ccm_node)
 {
 	struct device_node *np;
@@ -233,6 +281,9 @@
 	clk[VF610_CLK_PLL4_MAIN_DIV] = clk_register_divider_table(NULL, "pll4_audio_div", "pll4_audio", 0, CCM_CACRR, 6, 3, 0, pll4_audio_div_table, &imx_ccm_lock);
 	clk[VF610_CLK_PLL6_MAIN_DIV] = imx_clk_divider("pll6_video_div", "pll6_video", CCM_CACRR, 21, 1);
 
+	clk[VF610_CLK_DDRMC] = imx_clk_gate2_cgr("ddrmc", "ddr_sel", CCM_CCGR6, CCM_CCGRx_CGn(14), 0x2);
+	clk[VF610_CLK_WKPU] = imx_clk_gate2_cgr("wkpu", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(10), 0x2);
+
 	clk[VF610_CLK_USBPHY0] = imx_clk_gate("usbphy0", "pll3_usb_otg", PLL3_CTRL, 6);
 	clk[VF610_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll7_usb_host", PLL7_CTRL, 6);
 
@@ -321,11 +372,14 @@
 	clk[VF610_CLK_DCU0_SEL] = imx_clk_mux("dcu0_sel", CCM_CSCMR1, 28, 1, dcu_sels, 2);
 	clk[VF610_CLK_DCU0_EN] = imx_clk_gate("dcu0_en", "dcu0_sel", CCM_CSCDR3, 19);
 	clk[VF610_CLK_DCU0_DIV] = imx_clk_divider("dcu0_div", "dcu0_en", CCM_CSCDR3, 16, 3);
-	clk[VF610_CLK_DCU0] = imx_clk_gate2("dcu0", "dcu0_div", CCM_CCGR3, CCM_CCGRx_CGn(8));
+	clk[VF610_CLK_DCU0] = imx_clk_gate2("dcu0", "ipg_bus", CCM_CCGR3, CCM_CCGRx_CGn(8));
 	clk[VF610_CLK_DCU1_SEL] = imx_clk_mux("dcu1_sel", CCM_CSCMR1, 29, 1, dcu_sels, 2);
 	clk[VF610_CLK_DCU1_EN] = imx_clk_gate("dcu1_en", "dcu1_sel", CCM_CSCDR3, 23);
 	clk[VF610_CLK_DCU1_DIV] = imx_clk_divider("dcu1_div", "dcu1_en", CCM_CSCDR3, 20, 3);
-	clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "dcu1_div", CCM_CCGR9, CCM_CCGRx_CGn(8));
+	clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(8));
+
+	clk[VF610_CLK_TCON0] = imx_clk_gate2("tcon0", "platform_bus", CCM_CCGR1, CCM_CCGRx_CGn(13));
+	clk[VF610_CLK_TCON1] = imx_clk_gate2("tcon1", "platform_bus", CCM_CCGR7, CCM_CCGRx_CGn(13));
 
 	clk[VF610_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", CCM_CSCMR1, 20, 2, esai_sels, 4);
 	clk[VF610_CLK_ESAI_EN] = imx_clk_gate("esai_en", "esai_sel", CCM_CSCDR2, 30);
@@ -409,6 +463,8 @@
 	for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
 		clk_prepare_enable(clk[clks_init_on[i]]);
 
+	register_syscore_ops(&vf610_clk_syscore_ops);
+
 	/* Add the clocks to provider list */
 	clk_data.clks = clk;
 	clk_data.clk_num = ARRAY_SIZE(clk);
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index d942f57..508d0fa 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -41,7 +41,7 @@
 
 struct clk *clk_register_gate2(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
-		void __iomem *reg, u8 bit_idx,
+		void __iomem *reg, u8 bit_idx, u8 cgr_val,
 		u8 clk_gate_flags, spinlock_t *lock,
 		unsigned int *share_count);
 
@@ -55,7 +55,7 @@
 		void __iomem *reg, u8 shift)
 {
 	return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
-			shift, 0, &imx_ccm_lock, NULL);
+			shift, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
 static inline struct clk *imx_clk_gate2_shared(const char *name,
@@ -63,7 +63,14 @@
 		unsigned int *share_count)
 {
 	return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
-			shift, 0, &imx_ccm_lock, share_count);
+			shift, 0x3, 0, &imx_ccm_lock, share_count);
+}
+
+static inline struct clk *imx_clk_gate2_cgr(const char *name, const char *parent,
+		void __iomem *reg, u8 shift, u8 cgr_val)
+{
+	return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+			shift, cgr_val, 0, &imx_ccm_lock, NULL);
 }
 
 struct clk *imx_clk_pfd(const char *name, const char *parent_name,
diff --git a/drivers/clk/mediatek/reset.c b/drivers/clk/mediatek/reset.c
index 9e9fe4b..309049d 100644
--- a/drivers/clk/mediatek/reset.c
+++ b/drivers/clk/mediatek/reset.c
@@ -57,7 +57,7 @@
 	return mtk_reset_deassert(rcdev, id);
 }
 
-static struct reset_control_ops mtk_reset_ops = {
+static const struct reset_control_ops mtk_reset_ops = {
 	.assert = mtk_reset_assert,
 	.deassert = mtk_reset_deassert,
 	.reset = mtk_reset,
diff --git a/drivers/clk/meson/meson8b-clkc.c b/drivers/clk/meson/meson8b-clkc.c
index 61f6d55..4d057b3 100644
--- a/drivers/clk/meson/meson8b-clkc.c
+++ b/drivers/clk/meson/meson8b-clkc.c
@@ -141,11 +141,11 @@
 };
 
 static const struct clk_conf meson8b_xtal_conf __initconst =
-	FIXED_RATE_P(MESON8B_REG_CTL0_ADDR, CLKID_XTAL, "xtal",
-		     CLK_IS_ROOT, PARM(0x00, 4, 7));
+	FIXED_RATE_P(MESON8B_REG_CTL0_ADDR, CLKID_XTAL, "xtal", 0,
+			PARM(0x00, 4, 7));
 
 static const struct clk_conf meson8b_clk_confs[] __initconst = {
-	FIXED_RATE(CLKID_ZERO, "zero", CLK_IS_ROOT, 0),
+	FIXED_RATE(CLKID_ZERO, "zero", 0, 0),
 	PLL(MESON8B_REG_PLL_FIXED, CLKID_PLL_FIXED, "fixed_pll",
 	    p_xtal, 0, &pll_confs),
 	PLL(MESON8B_REG_PLL_VID, CLKID_PLL_VID, "vid_pll",
diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c
index 38931db..383f6a4 100644
--- a/drivers/clk/mmp/clk-mmp2.c
+++ b/drivers/clk/mmp/clk-mmp2.c
@@ -99,23 +99,19 @@
 		return;
 	}
 
-	clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200);
+	clk = clk_register_fixed_rate(NULL, "clk32", NULL, 0, 3200);
 	clk_register_clkdev(clk, "clk32", NULL);
 
-	vctcxo = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT,
-				26000000);
+	vctcxo = clk_register_fixed_rate(NULL, "vctcxo", NULL, 0, 26000000);
 	clk_register_clkdev(vctcxo, "vctcxo", NULL);
 
-	clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT,
-				800000000);
+	clk = clk_register_fixed_rate(NULL, "pll1", NULL, 0, 800000000);
 	clk_register_clkdev(clk, "pll1", NULL);
 
-	clk = clk_register_fixed_rate(NULL, "usb_pll", NULL, CLK_IS_ROOT,
-				480000000);
+	clk = clk_register_fixed_rate(NULL, "usb_pll", NULL, 0, 480000000);
 	clk_register_clkdev(clk, "usb_pll", NULL);
 
-	clk = clk_register_fixed_rate(NULL, "pll2", NULL, CLK_IS_ROOT,
-				960000000);
+	clk = clk_register_fixed_rate(NULL, "pll2", NULL, 0, 960000000);
 	clk_register_clkdev(clk, "pll2", NULL);
 
 	clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1",
diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c
index 251533d..3a51fff 100644
--- a/drivers/clk/mmp/clk-of-mmp2.c
+++ b/drivers/clk/mmp/clk-of-mmp2.c
@@ -63,11 +63,11 @@
 };
 
 static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
-	{MMP2_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768},
-	{MMP2_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
-	{MMP2_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 800000000},
-	{MMP2_CLK_PLL2, "pll2", NULL, CLK_IS_ROOT, 960000000},
-	{MMP2_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000},
+	{MMP2_CLK_CLK32, "clk32", NULL, 0, 32768},
+	{MMP2_CLK_VCTCXO, "vctcxo", NULL, 0, 26000000},
+	{MMP2_CLK_PLL1, "pll1", NULL, 0, 800000000},
+	{MMP2_CLK_PLL2, "pll2", NULL, 0, 960000000},
+	{MMP2_CLK_USB_PLL, "usb_pll", NULL, 0, 480000000},
 };
 
 static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c
index 64eaf41..87f2317 100644
--- a/drivers/clk/mmp/clk-of-pxa168.c
+++ b/drivers/clk/mmp/clk-of-pxa168.c
@@ -56,10 +56,10 @@
 };
 
 static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
-	{PXA168_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768},
-	{PXA168_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
-	{PXA168_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000},
-	{PXA168_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000},
+	{PXA168_CLK_CLK32, "clk32", NULL, 0, 32768},
+	{PXA168_CLK_VCTCXO, "vctcxo", NULL, 0, 26000000},
+	{PXA168_CLK_PLL1, "pll1", NULL, 0, 624000000},
+	{PXA168_CLK_USB_PLL, "usb_pll", NULL, 0, 480000000},
 };
 
 static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
diff --git a/drivers/clk/mmp/clk-of-pxa1928.c b/drivers/clk/mmp/clk-of-pxa1928.c
index 433a5ae..e478ff4 100644
--- a/drivers/clk/mmp/clk-of-pxa1928.c
+++ b/drivers/clk/mmp/clk-of-pxa1928.c
@@ -34,12 +34,12 @@
 };
 
 static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
-	{0, "clk32", NULL, CLK_IS_ROOT, 32768},
-	{0, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
-	{0, "pll1_624", NULL, CLK_IS_ROOT, 624000000},
-	{0, "pll5p", NULL, CLK_IS_ROOT, 832000000},
-	{0, "pll5", NULL, CLK_IS_ROOT, 1248000000},
-	{0, "usb_pll", NULL, CLK_IS_ROOT, 480000000},
+	{0, "clk32", NULL, 0, 32768},
+	{0, "vctcxo", NULL, 0, 26000000},
+	{0, "pll1_624", NULL, 0, 624000000},
+	{0, "pll5p", NULL, 0, 832000000},
+	{0, "pll5", NULL, 0, 1248000000},
+	{0, "usb_pll", NULL, 0, 480000000},
 };
 
 static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
diff --git a/drivers/clk/mmp/clk-of-pxa910.c b/drivers/clk/mmp/clk-of-pxa910.c
index 13d6173..e22a67f 100644
--- a/drivers/clk/mmp/clk-of-pxa910.c
+++ b/drivers/clk/mmp/clk-of-pxa910.c
@@ -56,10 +56,10 @@
 };
 
 static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
-	{PXA910_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768},
-	{PXA910_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
-	{PXA910_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000},
-	{PXA910_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000},
+	{PXA910_CLK_CLK32, "clk32", NULL, 0, 32768},
+	{PXA910_CLK_VCTCXO, "vctcxo", NULL, 0, 26000000},
+	{PXA910_CLK_PLL1, "pll1", NULL, 0, 624000000},
+	{PXA910_CLK_USB_PLL, "usb_pll", NULL, 0, 480000000},
 };
 
 static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c
index 0dd83fb..a9ef920 100644
--- a/drivers/clk/mmp/clk-pxa168.c
+++ b/drivers/clk/mmp/clk-pxa168.c
@@ -92,15 +92,13 @@
 		return;
 	}
 
-	clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200);
+	clk = clk_register_fixed_rate(NULL, "clk32", NULL, 0, 3200);
 	clk_register_clkdev(clk, "clk32", NULL);
 
-	clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT,
-				26000000);
+	clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, 0, 26000000);
 	clk_register_clkdev(clk, "vctcxo", NULL);
 
-	clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT,
-				624000000);
+	clk = clk_register_fixed_rate(NULL, "pll1", NULL, 0, 624000000);
 	clk_register_clkdev(clk, "pll1", NULL);
 
 	clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1",
diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c
index e1d2ce2..a520cf7 100644
--- a/drivers/clk/mmp/clk-pxa910.c
+++ b/drivers/clk/mmp/clk-pxa910.c
@@ -97,15 +97,13 @@
 		return;
 	}
 
-	clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200);
+	clk = clk_register_fixed_rate(NULL, "clk32", NULL, 0, 3200);
 	clk_register_clkdev(clk, "clk32", NULL);
 
-	clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT,
-				26000000);
+	clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, 0, 26000000);
 	clk_register_clkdev(clk, "vctcxo", NULL);
 
-	clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT,
-				624000000);
+	clk = clk_register_fixed_rate(NULL, "pll1", NULL, 0, 624000000);
 	clk_register_clkdev(clk, "pll1", NULL);
 
 	clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1",
diff --git a/drivers/clk/mmp/reset.c b/drivers/clk/mmp/reset.c
index b54da1f..b4e4d6a 100644
--- a/drivers/clk/mmp/reset.c
+++ b/drivers/clk/mmp/reset.c
@@ -74,7 +74,7 @@
 	return 0;
 }
 
-static struct reset_control_ops mmp_clk_reset_ops = {
+static const struct reset_control_ops mmp_clk_reset_ops = {
 	.assert		= mmp_clk_reset_assert,
 	.deassert	= mmp_clk_reset_deassert,
 };
diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c
index 5428efb..3cd1af0 100644
--- a/drivers/clk/qcom/gcc-ipq4019.c
+++ b/drivers/clk/qcom/gcc-ipq4019.c
@@ -129,20 +129,10 @@
 };
 
 #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
-#define P_XO 0
-#define FE_PLL_200 1
-#define FE_PLL_500 2
-#define DDRC_PLL_666  3
-
-#define DDRC_PLL_666_SDCC  1
-#define FE_PLL_125_DLY 1
-
-#define FE_PLL_WCSS2G 1
-#define FE_PLL_WCSS5G 1
 
 static const struct freq_tbl ftbl_gcc_audio_pwm_clk[] = {
 	F(48000000, P_XO, 1, 0, 0),
-	F(200000000, FE_PLL_200, 1, 0, 0),
+	F(200000000, P_FEPLL200, 1, 0, 0),
 	{ }
 };
 
@@ -334,15 +324,15 @@
 };
 
 static const struct freq_tbl ftbl_gcc_blsp1_uart1_2_apps_clk[] = {
-	F(1843200, FE_PLL_200, 1, 144, 15625),
-	F(3686400, FE_PLL_200, 1, 288, 15625),
-	F(7372800, FE_PLL_200, 1, 576, 15625),
-	F(14745600, FE_PLL_200, 1, 1152, 15625),
-	F(16000000, FE_PLL_200, 1, 2, 25),
+	F(1843200, P_FEPLL200, 1, 144, 15625),
+	F(3686400, P_FEPLL200, 1, 288, 15625),
+	F(7372800, P_FEPLL200, 1, 576, 15625),
+	F(14745600, P_FEPLL200, 1, 1152, 15625),
+	F(16000000, P_FEPLL200, 1, 2, 25),
 	F(24000000, P_XO, 1, 1, 2),
-	F(32000000, FE_PLL_200, 1, 4, 25),
-	F(40000000, FE_PLL_200, 1, 1, 5),
-	F(46400000, FE_PLL_200, 1, 29, 125),
+	F(32000000, P_FEPLL200, 1, 4, 25),
+	F(40000000, P_FEPLL200, 1, 1, 5),
+	F(46400000, P_FEPLL200, 1, 29, 125),
 	F(48000000, P_XO, 1, 0, 0),
 	{ }
 };
@@ -410,9 +400,9 @@
 };
 
 static const struct freq_tbl ftbl_gcc_gp_clk[] = {
-	F(1250000,  FE_PLL_200, 1, 16, 0),
-	F(2500000,  FE_PLL_200, 1,  8, 0),
-	F(5000000,  FE_PLL_200, 1,  4, 0),
+	F(1250000,  P_FEPLL200, 1, 16, 0),
+	F(2500000,  P_FEPLL200, 1,  8, 0),
+	F(5000000,  P_FEPLL200, 1,  4, 0),
 	{ }
 };
 
@@ -512,11 +502,11 @@
 static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk[] = {
 	F(144000,    P_XO,			1,  3, 240),
 	F(400000,    P_XO,			1,  1, 0),
-	F(20000000,  FE_PLL_500,		1,  1, 25),
-	F(25000000,  FE_PLL_500,		1,  1, 20),
-	F(50000000,  FE_PLL_500,		1,  1, 10),
-	F(100000000, FE_PLL_500,		1,  1, 5),
-	F(193000000, DDRC_PLL_666_SDCC,		1,  0, 0),
+	F(20000000,  P_FEPLL500,		1,  1, 25),
+	F(25000000,  P_FEPLL500,		1,  1, 20),
+	F(50000000,  P_FEPLL500,		1,  1, 10),
+	F(100000000, P_FEPLL500,		1,  1, 5),
+	F(193000000, P_DDRPLL,		1,  0, 0),
 	{ }
 };
 
@@ -536,9 +526,9 @@
 
 static const struct freq_tbl ftbl_gcc_apps_clk[] = {
 	F(48000000, P_XO,	   1, 0, 0),
-	F(200000000, FE_PLL_200,   1, 0, 0),
-	F(500000000, FE_PLL_500,   1, 0, 0),
-	F(626000000, DDRC_PLL_666, 1, 0, 0),
+	F(200000000, P_FEPLL200,   1, 0, 0),
+	F(500000000, P_FEPLL500,   1, 0, 0),
+	F(626000000, P_DDRPLLAPSS, 1, 0, 0),
 	{ }
 };
 
@@ -557,7 +547,7 @@
 
 static const struct freq_tbl ftbl_gcc_apps_ahb_clk[] = {
 	F(48000000, P_XO,	   1, 0, 0),
-	F(100000000, FE_PLL_200,   2, 0, 0),
+	F(100000000, P_FEPLL200,   2, 0, 0),
 	{ }
 };
 
@@ -940,7 +930,7 @@
 };
 
 static const struct freq_tbl ftbl_gcc_usb30_mock_utmi_clk[] = {
-	F(2000000, FE_PLL_200, 10, 0, 0),
+	F(2000000, P_FEPLL200, 10, 0, 0),
 	{ }
 };
 
@@ -1007,7 +997,7 @@
 };
 
 static const struct freq_tbl ftbl_gcc_fephy_dly_clk[] = {
-	F(125000000, FE_PLL_125_DLY, 1, 0, 0),
+	F(125000000, P_FEPLL125DLY, 1, 0, 0),
 	{ }
 };
 
@@ -1027,7 +1017,7 @@
 
 static const struct freq_tbl ftbl_gcc_wcss2g_clk[] = {
 	F(48000000, P_XO, 1, 0, 0),
-	F(250000000, FE_PLL_WCSS2G, 1, 0, 0),
+	F(250000000, P_FEPLLWCSS2G, 1, 0, 0),
 	{ }
 };
 
@@ -1097,7 +1087,7 @@
 
 static const struct freq_tbl ftbl_gcc_wcss5g_clk[] = {
 	F(48000000, P_XO, 1, 0, 0),
-	F(250000000, FE_PLL_WCSS5G, 1, 0, 0),
+	F(250000000, P_FEPLLWCSS5G, 1, 0, 0),
 	{ }
 };
 
@@ -1325,6 +1315,16 @@
 
 static int gcc_ipq4019_probe(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
+
+	clk_register_fixed_rate(dev, "fepll125", "xo", 0, 200000000);
+	clk_register_fixed_rate(dev, "fepll125dly", "xo", 0, 200000000);
+	clk_register_fixed_rate(dev, "fepllwcss2g", "xo", 0, 200000000);
+	clk_register_fixed_rate(dev, "fepllwcss5g", "xo", 0, 200000000);
+	clk_register_fixed_rate(dev, "fepll200", "xo", 0, 200000000);
+	clk_register_fixed_rate(dev, "fepll500", "xo", 0, 200000000);
+	clk_register_fixed_rate(dev, "ddrpllapss", "xo", 0, 666000000);
+
 	return qcom_cc_probe(pdev, &gcc_ipq4019_desc);
 }
 
diff --git a/drivers/clk/qcom/reset.c b/drivers/clk/qcom/reset.c
index 6c977d3..0324d8d 100644
--- a/drivers/clk/qcom/reset.c
+++ b/drivers/clk/qcom/reset.c
@@ -55,7 +55,7 @@
 	return regmap_update_bits(rst->regmap, map->reg, mask, 0);
 }
 
-struct reset_control_ops qcom_reset_ops = {
+const struct reset_control_ops qcom_reset_ops = {
 	.reset = qcom_reset,
 	.assert = qcom_reset_assert,
 	.deassert = qcom_reset_deassert,
diff --git a/drivers/clk/qcom/reset.h b/drivers/clk/qcom/reset.h
index 0e11e21..cda8779 100644
--- a/drivers/clk/qcom/reset.h
+++ b/drivers/clk/qcom/reset.h
@@ -32,6 +32,6 @@
 #define to_qcom_reset_controller(r) \
 	container_of(r, struct qcom_reset_controller, rcdev);
 
-extern struct reset_control_ops qcom_reset_ops;
+extern const struct reset_control_ops qcom_reset_ops;
 
 #endif
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
new file mode 100644
index 0000000..2115ce4
--- /dev/null
+++ b/drivers/clk/renesas/Kconfig
@@ -0,0 +1,16 @@
+config CLK_RENESAS_CPG_MSSR
+	bool
+	default y if ARCH_R8A7795
+
+config CLK_RENESAS_CPG_MSTP
+	bool
+	default y if ARCH_R7S72100
+	default y if ARCH_R8A73A4
+	default y if ARCH_R8A7740
+	default y if ARCH_R8A7778
+	default y if ARCH_R8A7779
+	default y if ARCH_R8A7790
+	default y if ARCH_R8A7791
+	default y if ARCH_R8A7793
+	default y if ARCH_R8A7794
+	default y if ARCH_SH73A0
diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile
index 7e2579b..ead8bb8 100644
--- a/drivers/clk/renesas/Makefile
+++ b/drivers/clk/renesas/Makefile
@@ -1,13 +1,15 @@
 obj-$(CONFIG_ARCH_EMEV2)		+= clk-emev2.o
-obj-$(CONFIG_ARCH_R7S72100)		+= clk-rz.o clk-mstp.o
-obj-$(CONFIG_ARCH_R8A73A4)		+= clk-r8a73a4.o clk-mstp.o clk-div6.o
-obj-$(CONFIG_ARCH_R8A7740)		+= clk-r8a7740.o clk-mstp.o clk-div6.o
-obj-$(CONFIG_ARCH_R8A7778)		+= clk-r8a7778.o clk-mstp.o
-obj-$(CONFIG_ARCH_R8A7779)		+= clk-r8a7779.o clk-mstp.o
-obj-$(CONFIG_ARCH_R8A7790)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
-obj-$(CONFIG_ARCH_R8A7791)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
-obj-$(CONFIG_ARCH_R8A7793)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
-obj-$(CONFIG_ARCH_R8A7794)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
-obj-$(CONFIG_ARCH_R8A7795)		+= renesas-cpg-mssr.o \
-					   r8a7795-cpg-mssr.o clk-div6.o
-obj-$(CONFIG_ARCH_SH73A0)		+= clk-sh73a0.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R7S72100)		+= clk-rz.o
+obj-$(CONFIG_ARCH_R8A73A4)		+= clk-r8a73a4.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7740)		+= clk-r8a7740.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7778)		+= clk-r8a7778.o
+obj-$(CONFIG_ARCH_R8A7779)		+= clk-r8a7779.o
+obj-$(CONFIG_ARCH_R8A7790)		+= clk-rcar-gen2.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7791)		+= clk-rcar-gen2.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7793)		+= clk-rcar-gen2.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7794)		+= clk-rcar-gen2.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7795)		+= r8a7795-cpg-mssr.o
+obj-$(CONFIG_ARCH_SH73A0)		+= clk-sh73a0.o clk-div6.o
+
+obj-$(CONFIG_CLK_RENESAS_CPG_MSSR)	+= renesas-cpg-mssr.o clk-div6.o
+obj-$(CONFIG_CLK_RENESAS_CPG_MSTP)	+= clk-mstp.o
diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c
index 3d44e18..8b597b9 100644
--- a/drivers/clk/renesas/clk-mstp.c
+++ b/drivers/clk/renesas/clk-mstp.c
@@ -243,9 +243,7 @@
 }
 CLK_OF_DECLARE(cpg_mstp_clks, "renesas,cpg-mstp-clocks", cpg_mstp_clocks_init);
 
-
-#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
-int cpg_mstp_attach_dev(struct generic_pm_domain *domain, struct device *dev)
+int cpg_mstp_attach_dev(struct generic_pm_domain *unused, struct device *dev)
 {
 	struct device_node *np = dev->of_node;
 	struct of_phandle_args clkspec;
@@ -297,7 +295,7 @@
 	return error;
 }
 
-void cpg_mstp_detach_dev(struct generic_pm_domain *domain, struct device *dev)
+void cpg_mstp_detach_dev(struct generic_pm_domain *unused, struct device *dev)
 {
 	if (!list_empty(&dev->power.subsys_data->clock_list))
 		pm_clk_destroy(dev);
@@ -326,4 +324,3 @@
 
 	of_genpd_add_provider_simple(np, pd);
 }
-#endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */
diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c
index b2198aef..6af7f5b 100644
--- a/drivers/clk/renesas/r8a7795-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c
@@ -13,6 +13,7 @@
  */
 
 #include <linux/bug.h>
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -26,6 +27,7 @@
 
 #include "renesas-cpg-mssr.h"
 
+#define CPG_RCKCR	0x240
 
 enum clk_ids {
 	/* Core Clock Outputs exported to DT */
@@ -50,6 +52,7 @@
 	CLK_S3,
 	CLK_SDSRC,
 	CLK_SSPSRC,
+	CLK_RINT,
 
 	/* Module Clocks */
 	MOD_CLK_BASE
@@ -63,8 +66,12 @@
 	CLK_TYPE_GEN3_PLL3,
 	CLK_TYPE_GEN3_PLL4,
 	CLK_TYPE_GEN3_SD,
+	CLK_TYPE_GEN3_R,
 };
 
+#define DEF_GEN3_SD(_name, _id, _parent, _offset)	\
+	DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD, _parent, .offset = _offset)
+
 static const struct cpg_core_clk r8a7795_core_clks[] __initconst = {
 	/* External Clock Inputs */
 	DEF_INPUT("extal",  CLK_EXTAL),
@@ -102,10 +109,10 @@
 	DEF_FIXED("s3d2",       R8A7795_CLK_S3D2,  CLK_S3,         2, 1),
 	DEF_FIXED("s3d4",       R8A7795_CLK_S3D4,  CLK_S3,         4, 1),
 
-	DEF_SD("sd0",           R8A7795_CLK_SD0,   CLK_PLL1_DIV2, 0x0074),
-	DEF_SD("sd1",           R8A7795_CLK_SD1,   CLK_PLL1_DIV2, 0x0078),
-	DEF_SD("sd2",           R8A7795_CLK_SD2,   CLK_PLL1_DIV2, 0x0268),
-	DEF_SD("sd3",           R8A7795_CLK_SD3,   CLK_PLL1_DIV2, 0x026c),
+	DEF_GEN3_SD("sd0",      R8A7795_CLK_SD0,   CLK_PLL1_DIV2, 0x0074),
+	DEF_GEN3_SD("sd1",      R8A7795_CLK_SD1,   CLK_PLL1_DIV2, 0x0078),
+	DEF_GEN3_SD("sd2",      R8A7795_CLK_SD2,   CLK_PLL1_DIV2, 0x0268),
+	DEF_GEN3_SD("sd3",      R8A7795_CLK_SD3,   CLK_PLL1_DIV2, 0x026c),
 
 	DEF_FIXED("cl",         R8A7795_CLK_CL,    CLK_PLL1_DIV2, 48, 1),
 	DEF_FIXED("cp",         R8A7795_CLK_CP,    CLK_EXTAL,      2, 1),
@@ -113,6 +120,11 @@
 	DEF_DIV6P1("mso",       R8A7795_CLK_MSO,   CLK_PLL1_DIV4, 0x014),
 	DEF_DIV6P1("hdmi",      R8A7795_CLK_HDMI,  CLK_PLL1_DIV2, 0x250),
 	DEF_DIV6P1("canfd",     R8A7795_CLK_CANFD, CLK_PLL1_DIV4, 0x244),
+
+	DEF_DIV6_RO("osc",      R8A7795_CLK_OSC,   CLK_EXTAL, CPG_RCKCR, 8),
+	DEF_DIV6_RO("r_int",    CLK_RINT,          CLK_EXTAL, CPG_RCKCR, 32),
+
+	DEF_BASE("r",           R8A7795_CLK_R, CLK_TYPE_GEN3_R, CLK_RINT),
 };
 
 static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = {
@@ -139,6 +151,7 @@
 	DEF_MOD("usb3-if0",		 328,	R8A7795_CLK_S3D1),
 	DEF_MOD("usb-dmac0",		 330,	R8A7795_CLK_S3D1),
 	DEF_MOD("usb-dmac1",		 331,	R8A7795_CLK_S3D1),
+	DEF_MOD("rwdt0",		 402,	R8A7795_CLK_R),
 	DEF_MOD("intc-ex",		 407,	R8A7795_CLK_CP),
 	DEF_MOD("intc-ap",		 408,	R8A7795_CLK_S3D1),
 	DEF_MOD("audmac0",		 502,	R8A7795_CLK_S3D4),
@@ -148,6 +161,7 @@
 	DEF_MOD("hscif2",		 518,	R8A7795_CLK_S3D1),
 	DEF_MOD("hscif1",		 519,	R8A7795_CLK_S3D1),
 	DEF_MOD("hscif0",		 520,	R8A7795_CLK_S3D1),
+	DEF_MOD("pwm",			 523,	R8A7795_CLK_S3D4),
 	DEF_MOD("fcpvd3",		 600,	R8A7795_CLK_S2D1),
 	DEF_MOD("fcpvd2",		 601,	R8A7795_CLK_S2D1),
 	DEF_MOD("fcpvd1",		 602,	R8A7795_CLK_S2D1),
@@ -578,6 +592,18 @@
 	case CLK_TYPE_GEN3_SD:
 		return cpg_sd_clk_register(core, base, __clk_get_name(parent));
 
+	case CLK_TYPE_GEN3_R:
+		/* RINT is default. Only if EXTALR is populated, we switch to it */
+		value = readl(base + CPG_RCKCR) & 0x3f;
+
+		if (clk_get_rate(clks[CLK_EXTALR])) {
+			parent = clks[CLK_EXTALR];
+			value |= BIT(15);
+		}
+
+		writel(value, base + CPG_RCKCR);
+		break;
+
 	default:
 		return ERR_PTR(-EINVAL);
 	}
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c
index 58e24b3..1f2dc362 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -15,6 +15,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/clk/renesas.h>
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/mod_devicetable.h>
@@ -253,7 +254,7 @@
 {
 	struct clk *clk = NULL, *parent;
 	struct device *dev = priv->dev;
-	unsigned int id = core->id;
+	unsigned int id = core->id, div = core->div;
 	const char *parent_name;
 
 	WARN_DEBUG(id >= priv->num_core_clks);
@@ -266,6 +267,7 @@
 
 	case CLK_TYPE_FF:
 	case CLK_TYPE_DIV6P1:
+	case CLK_TYPE_DIV6_RO:
 		WARN_DEBUG(core->parent >= priv->num_core_clks);
 		parent = priv->clks[core->parent];
 		if (IS_ERR(parent)) {
@@ -274,13 +276,18 @@
 		}
 
 		parent_name = __clk_get_name(parent);
-		if (core->type == CLK_TYPE_FF) {
-			clk = clk_register_fixed_factor(NULL, core->name,
-							parent_name, 0,
-							core->mult, core->div);
-		} else {
+
+		if (core->type == CLK_TYPE_DIV6_RO)
+			/* Multiply with the DIV6 register value */
+			div *= (readl(priv->base + core->offset) & 0x3f) + 1;
+
+		if (core->type == CLK_TYPE_DIV6P1) {
 			clk = cpg_div6_register(core->name, 1, &parent_name,
 						priv->base + core->offset);
+		} else {
+			clk = clk_register_fixed_factor(NULL, core->name,
+							parent_name, 0,
+							core->mult, div);
 		}
 		break;
 
@@ -375,8 +382,6 @@
 	kfree(clock);
 }
 
-
-#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
 struct cpg_mssr_clk_domain {
 	struct generic_pm_domain genpd;
 	struct device_node *np;
@@ -384,6 +389,8 @@
 	unsigned int core_pm_clks[0];
 };
 
+static struct cpg_mssr_clk_domain *cpg_mssr_clk_domain;
+
 static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec,
 			       struct cpg_mssr_clk_domain *pd)
 {
@@ -407,17 +414,20 @@
 	}
 }
 
-static int cpg_mssr_attach_dev(struct generic_pm_domain *genpd,
-			       struct device *dev)
+int cpg_mssr_attach_dev(struct generic_pm_domain *unused, struct device *dev)
 {
-	struct cpg_mssr_clk_domain *pd =
-		container_of(genpd, struct cpg_mssr_clk_domain, genpd);
+	struct cpg_mssr_clk_domain *pd = cpg_mssr_clk_domain;
 	struct device_node *np = dev->of_node;
 	struct of_phandle_args clkspec;
 	struct clk *clk;
 	int i = 0;
 	int error;
 
+	if (!pd) {
+		dev_dbg(dev, "CPG/MSSR clock domain not yet available\n");
+		return -EPROBE_DEFER;
+	}
+
 	while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
 					   &clkspec)) {
 		if (cpg_mssr_is_pm_clk(&clkspec, pd))
@@ -457,8 +467,7 @@
 	return error;
 }
 
-static void cpg_mssr_detach_dev(struct generic_pm_domain *genpd,
-				struct device *dev)
+void cpg_mssr_detach_dev(struct generic_pm_domain *unused, struct device *dev)
 {
 	if (!list_empty(&dev->power.subsys_data->clock_list))
 		pm_clk_destroy(dev);
@@ -487,19 +496,11 @@
 	pm_genpd_init(genpd, &simple_qos_governor, false);
 	genpd->attach_dev = cpg_mssr_attach_dev;
 	genpd->detach_dev = cpg_mssr_detach_dev;
+	cpg_mssr_clk_domain = pd;
 
 	of_genpd_add_provider_simple(np, genpd);
 	return 0;
 }
-#else
-static inline int cpg_mssr_add_clk_domain(struct device *dev,
-					  const unsigned int *core_pm_clks,
-					  unsigned int num_core_pm_clks)
-{
-	return 0;
-}
-#endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */
-
 
 static const struct of_device_id cpg_mssr_match[] = {
 #ifdef CONFIG_ARCH_R8A7795
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h
index 952b695..0d1e3e8 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.h
+++ b/drivers/clk/renesas/renesas-cpg-mssr.h
@@ -37,6 +37,7 @@
 	CLK_TYPE_IN,		/* External Clock Input */
 	CLK_TYPE_FF,		/* Fixed Factor Clock */
 	CLK_TYPE_DIV6P1,	/* DIV6 Clock with 1 parent clock */
+	CLK_TYPE_DIV6_RO,	/* DIV6 Clock read only with extra divisor */
 
 	/* Custom definitions start here */
 	CLK_TYPE_CUSTOM,
@@ -53,9 +54,8 @@
 	DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult)
 #define DEF_DIV6P1(_name, _id, _parent, _offset)	\
 	DEF_BASE(_name, _id, CLK_TYPE_DIV6P1, _parent, .offset = _offset)
-#define DEF_SD(_name, _id, _parent, _offset)	\
-	DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD, _parent, .offset = _offset)
-
+#define DEF_DIV6_RO(_name, _id, _parent, _offset, _div)	\
+	DEF_BASE(_name, _id, CLK_TYPE_DIV6_RO, _parent, .offset = _offset, .div = _div, .mult = 1)
 
     /*
      * Definitions of Module Clocks
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 80b9a37..f47a2fa 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -15,3 +15,4 @@
 obj-y	+= clk-rk3228.o
 obj-y	+= clk-rk3288.o
 obj-y	+= clk-rk3368.o
+obj-y	+= clk-rk3399.o
diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c
index 4e73ed5..4bb130c 100644
--- a/drivers/clk/rockchip/clk-cpu.c
+++ b/drivers/clk/rockchip/clk-cpu.c
@@ -158,12 +158,16 @@
 
 		writel(HIWORD_UPDATE(alt_div, reg_data->div_core_mask,
 					      reg_data->div_core_shift) |
-		       HIWORD_UPDATE(1, 1, reg_data->mux_core_shift),
+		       HIWORD_UPDATE(reg_data->mux_core_alt,
+				     reg_data->mux_core_mask,
+				     reg_data->mux_core_shift),
 		       cpuclk->reg_base + reg_data->core_reg);
 	} else {
 		/* select alternate parent */
-		writel(HIWORD_UPDATE(1, 1, reg_data->mux_core_shift),
-			cpuclk->reg_base + reg_data->core_reg);
+		writel(HIWORD_UPDATE(reg_data->mux_core_alt,
+				     reg_data->mux_core_mask,
+				     reg_data->mux_core_shift),
+		       cpuclk->reg_base + reg_data->core_reg);
 	}
 
 	spin_unlock_irqrestore(cpuclk->lock, flags);
@@ -198,7 +202,9 @@
 
 	writel(HIWORD_UPDATE(0, reg_data->div_core_mask,
 				reg_data->div_core_shift) |
-	       HIWORD_UPDATE(0, 1, reg_data->mux_core_shift),
+	       HIWORD_UPDATE(reg_data->mux_core_main,
+				reg_data->mux_core_mask,
+				reg_data->mux_core_shift),
 	       cpuclk->reg_base + reg_data->core_reg);
 
 	if (ndata->old_rate > ndata->new_rate)
@@ -252,7 +258,7 @@
 		return ERR_PTR(-ENOMEM);
 
 	init.name = name;
-	init.parent_names = &parent_names[0];
+	init.parent_names = &parent_names[reg_data->mux_core_main];
 	init.num_parents = 1;
 	init.ops = &rockchip_cpuclk_ops;
 
@@ -270,10 +276,10 @@
 	cpuclk->clk_nb.notifier_call = rockchip_cpuclk_notifier_cb;
 	cpuclk->hw.init = &init;
 
-	cpuclk->alt_parent = __clk_lookup(parent_names[1]);
+	cpuclk->alt_parent = __clk_lookup(parent_names[reg_data->mux_core_alt]);
 	if (!cpuclk->alt_parent) {
-		pr_err("%s: could not lookup alternate parent\n",
-		       __func__);
+		pr_err("%s: could not lookup alternate parent: (%d)\n",
+		       __func__, reg_data->mux_core_alt);
 		ret = -EINVAL;
 		goto free_cpuclk;
 	}
@@ -285,10 +291,11 @@
 		goto free_cpuclk;
 	}
 
-	clk = __clk_lookup(parent_names[0]);
+	clk = __clk_lookup(parent_names[reg_data->mux_core_main]);
 	if (!clk) {
-		pr_err("%s: could not lookup parent clock %s\n",
-		       __func__, parent_names[0]);
+		pr_err("%s: could not lookup parent clock: (%d) %s\n",
+		       __func__, reg_data->mux_core_main,
+		       parent_names[reg_data->mux_core_main]);
 		ret = -EINVAL;
 		goto free_alt_parent;
 	}
diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c
index e0dc7e8..bc856f2 100644
--- a/drivers/clk/rockchip/clk-mmc-phase.c
+++ b/drivers/clk/rockchip/clk-mmc-phase.c
@@ -123,7 +123,8 @@
 	raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
 	raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
 	raw_value |= nineties;
-	writel(HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift), mmc_clock->reg);
+	writel(HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift),
+	       mmc_clock->reg);
 
 	pr_debug("%s->set_phase(%d) delay_nums=%u reg[0x%p]=0x%03x actual_degrees=%d\n",
 		clk_hw_get_name(hw), degrees, delay_num,
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 5de797e..8ac73bc 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -46,6 +46,8 @@
 	const struct rockchip_pll_rate_table *rate_table;
 	unsigned int		rate_count;
 	spinlock_t		*lock;
+
+	struct rockchip_clk_provider *ctx;
 };
 
 #define to_rockchip_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw)
@@ -90,7 +92,7 @@
  */
 static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll)
 {
-	struct regmap *grf = rockchip_clk_get_grf();
+	struct regmap *grf = rockchip_clk_get_grf(pll->ctx);
 	unsigned int val;
 	int delay = 24000000, ret;
 
@@ -234,7 +236,7 @@
 	/* wait for the pll to lock */
 	ret = rockchip_pll_wait_lock(pll);
 	if (ret) {
-		pr_warn("%s: pll update unsucessful, trying to restore old params\n",
+		pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
 			__func__);
 		rockchip_rk3036_pll_set_params(pll, &cur);
 	}
@@ -251,7 +253,7 @@
 	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
 	const struct rockchip_pll_rate_table *rate;
 	unsigned long old_rate = rockchip_rk3036_pll_recalc_rate(hw, prate);
-	struct regmap *grf = rockchip_clk_get_grf();
+	struct regmap *grf = rockchip_clk_get_grf(pll->ctx);
 
 	if (IS_ERR(grf)) {
 		pr_debug("%s: grf regmap not available, aborting rate change\n",
@@ -473,7 +475,7 @@
 	/* wait for the pll to lock */
 	ret = rockchip_pll_wait_lock(pll);
 	if (ret) {
-		pr_warn("%s: pll update unsucessful, trying to restore old params\n",
+		pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
 			__func__);
 		rockchip_rk3066_pll_set_params(pll, &cur);
 	}
@@ -490,7 +492,7 @@
 	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
 	const struct rockchip_pll_rate_table *rate;
 	unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate);
-	struct regmap *grf = rockchip_clk_get_grf();
+	struct regmap *grf = rockchip_clk_get_grf(pll->ctx);
 
 	if (IS_ERR(grf)) {
 		pr_debug("%s: grf regmap not available, aborting rate change\n",
@@ -563,7 +565,7 @@
 		 rate->no, cur.no, rate->nf, cur.nf, rate->nb, cur.nb);
 	if (rate->nr != cur.nr || rate->no != cur.no || rate->nf != cur.nf
 						     || rate->nb != cur.nb) {
-		struct regmap *grf = rockchip_clk_get_grf();
+		struct regmap *grf = rockchip_clk_get_grf(pll->ctx);
 
 		if (IS_ERR(grf))
 			return;
@@ -591,16 +593,278 @@
 	.init = rockchip_rk3066_pll_init,
 };
 
+/**
+ * PLL used in RK3399
+ */
+
+#define RK3399_PLLCON(i)			(i * 0x4)
+#define RK3399_PLLCON0_FBDIV_MASK		0xfff
+#define RK3399_PLLCON0_FBDIV_SHIFT		0
+#define RK3399_PLLCON1_REFDIV_MASK		0x3f
+#define RK3399_PLLCON1_REFDIV_SHIFT		0
+#define RK3399_PLLCON1_POSTDIV1_MASK		0x7
+#define RK3399_PLLCON1_POSTDIV1_SHIFT		8
+#define RK3399_PLLCON1_POSTDIV2_MASK		0x7
+#define RK3399_PLLCON1_POSTDIV2_SHIFT		12
+#define RK3399_PLLCON2_FRAC_MASK		0xffffff
+#define RK3399_PLLCON2_FRAC_SHIFT		0
+#define RK3399_PLLCON2_LOCK_STATUS		BIT(31)
+#define RK3399_PLLCON3_PWRDOWN			BIT(0)
+#define RK3399_PLLCON3_DSMPD_MASK		0x1
+#define RK3399_PLLCON3_DSMPD_SHIFT		3
+
+static int rockchip_rk3399_pll_wait_lock(struct rockchip_clk_pll *pll)
+{
+	u32 pllcon;
+	int delay = 24000000;
+
+	/* poll check the lock status in rk3399 xPLLCON2 */
+	while (delay > 0) {
+		pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2));
+		if (pllcon & RK3399_PLLCON2_LOCK_STATUS)
+			return 0;
+
+		delay--;
+	}
+
+	pr_err("%s: timeout waiting for pll to lock\n", __func__);
+	return -ETIMEDOUT;
+}
+
+static void rockchip_rk3399_pll_get_params(struct rockchip_clk_pll *pll,
+					struct rockchip_pll_rate_table *rate)
+{
+	u32 pllcon;
+
+	pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(0));
+	rate->fbdiv = ((pllcon >> RK3399_PLLCON0_FBDIV_SHIFT)
+				& RK3399_PLLCON0_FBDIV_MASK);
+
+	pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(1));
+	rate->refdiv = ((pllcon >> RK3399_PLLCON1_REFDIV_SHIFT)
+				& RK3399_PLLCON1_REFDIV_MASK);
+	rate->postdiv1 = ((pllcon >> RK3399_PLLCON1_POSTDIV1_SHIFT)
+				& RK3399_PLLCON1_POSTDIV1_MASK);
+	rate->postdiv2 = ((pllcon >> RK3399_PLLCON1_POSTDIV2_SHIFT)
+				& RK3399_PLLCON1_POSTDIV2_MASK);
+
+	pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2));
+	rate->frac = ((pllcon >> RK3399_PLLCON2_FRAC_SHIFT)
+				& RK3399_PLLCON2_FRAC_MASK);
+
+	pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(3));
+	rate->dsmpd = ((pllcon >> RK3399_PLLCON3_DSMPD_SHIFT)
+				& RK3399_PLLCON3_DSMPD_MASK);
+}
+
+static unsigned long rockchip_rk3399_pll_recalc_rate(struct clk_hw *hw,
+						     unsigned long prate)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+	struct rockchip_pll_rate_table cur;
+	u64 rate64 = prate;
+
+	rockchip_rk3399_pll_get_params(pll, &cur);
+
+	rate64 *= cur.fbdiv;
+	do_div(rate64, cur.refdiv);
+
+	if (cur.dsmpd == 0) {
+		/* fractional mode */
+		u64 frac_rate64 = prate * cur.frac;
+
+		do_div(frac_rate64, cur.refdiv);
+		rate64 += frac_rate64 >> 24;
+	}
+
+	do_div(rate64, cur.postdiv1);
+	do_div(rate64, cur.postdiv2);
+
+	return (unsigned long)rate64;
+}
+
+static int rockchip_rk3399_pll_set_params(struct rockchip_clk_pll *pll,
+				const struct rockchip_pll_rate_table *rate)
+{
+	const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
+	struct clk_mux *pll_mux = &pll->pll_mux;
+	struct rockchip_pll_rate_table cur;
+	u32 pllcon;
+	int rate_change_remuxed = 0;
+	int cur_parent;
+	int ret;
+
+	pr_debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
+		__func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv,
+		rate->postdiv2, rate->dsmpd, rate->frac);
+
+	rockchip_rk3399_pll_get_params(pll, &cur);
+	cur.rate = 0;
+
+	cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
+	if (cur_parent == PLL_MODE_NORM) {
+		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
+		rate_change_remuxed = 1;
+	}
+
+	/* update pll values */
+	writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3399_PLLCON0_FBDIV_MASK,
+						  RK3399_PLLCON0_FBDIV_SHIFT),
+		       pll->reg_base + RK3399_PLLCON(0));
+
+	writel_relaxed(HIWORD_UPDATE(rate->refdiv, RK3399_PLLCON1_REFDIV_MASK,
+						   RK3399_PLLCON1_REFDIV_SHIFT) |
+		       HIWORD_UPDATE(rate->postdiv1, RK3399_PLLCON1_POSTDIV1_MASK,
+						     RK3399_PLLCON1_POSTDIV1_SHIFT) |
+		       HIWORD_UPDATE(rate->postdiv2, RK3399_PLLCON1_POSTDIV2_MASK,
+						     RK3399_PLLCON1_POSTDIV2_SHIFT),
+		       pll->reg_base + RK3399_PLLCON(1));
+
+	/* xPLL CON2 is not HIWORD_MASK */
+	pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2));
+	pllcon &= ~(RK3399_PLLCON2_FRAC_MASK << RK3399_PLLCON2_FRAC_SHIFT);
+	pllcon |= rate->frac << RK3399_PLLCON2_FRAC_SHIFT;
+	writel_relaxed(pllcon, pll->reg_base + RK3399_PLLCON(2));
+
+	writel_relaxed(HIWORD_UPDATE(rate->dsmpd, RK3399_PLLCON3_DSMPD_MASK,
+					    RK3399_PLLCON3_DSMPD_SHIFT),
+		       pll->reg_base + RK3399_PLLCON(3));
+
+	/* wait for the pll to lock */
+	ret = rockchip_rk3399_pll_wait_lock(pll);
+	if (ret) {
+		pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
+			__func__);
+		rockchip_rk3399_pll_set_params(pll, &cur);
+	}
+
+	if (rate_change_remuxed)
+		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
+
+	return ret;
+}
+
+static int rockchip_rk3399_pll_set_rate(struct clk_hw *hw, unsigned long drate,
+					unsigned long prate)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+	const struct rockchip_pll_rate_table *rate;
+	unsigned long old_rate = rockchip_rk3399_pll_recalc_rate(hw, prate);
+
+	pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
+		 __func__, __clk_get_name(hw->clk), old_rate, drate, prate);
+
+	/* Get required rate settings from table */
+	rate = rockchip_get_pll_settings(pll, drate);
+	if (!rate) {
+		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+			drate, __clk_get_name(hw->clk));
+		return -EINVAL;
+	}
+
+	return rockchip_rk3399_pll_set_params(pll, rate);
+}
+
+static int rockchip_rk3399_pll_enable(struct clk_hw *hw)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+
+	writel(HIWORD_UPDATE(0, RK3399_PLLCON3_PWRDOWN, 0),
+	       pll->reg_base + RK3399_PLLCON(3));
+
+	return 0;
+}
+
+static void rockchip_rk3399_pll_disable(struct clk_hw *hw)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+
+	writel(HIWORD_UPDATE(RK3399_PLLCON3_PWRDOWN,
+			     RK3399_PLLCON3_PWRDOWN, 0),
+	       pll->reg_base + RK3399_PLLCON(3));
+}
+
+static int rockchip_rk3399_pll_is_enabled(struct clk_hw *hw)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+	u32 pllcon = readl(pll->reg_base + RK3399_PLLCON(3));
+
+	return !(pllcon & RK3399_PLLCON3_PWRDOWN);
+}
+
+static void rockchip_rk3399_pll_init(struct clk_hw *hw)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+	const struct rockchip_pll_rate_table *rate;
+	struct rockchip_pll_rate_table cur;
+	unsigned long drate;
+
+	if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
+		return;
+
+	drate = clk_hw_get_rate(hw);
+	rate = rockchip_get_pll_settings(pll, drate);
+
+	/* when no rate setting for the current rate, rely on clk_set_rate */
+	if (!rate)
+		return;
+
+	rockchip_rk3399_pll_get_params(pll, &cur);
+
+	pr_debug("%s: pll %s@%lu: Hz\n", __func__, __clk_get_name(hw->clk),
+		 drate);
+	pr_debug("old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
+		 cur.fbdiv, cur.postdiv1, cur.refdiv, cur.postdiv2,
+		 cur.dsmpd, cur.frac);
+	pr_debug("new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
+		 rate->fbdiv, rate->postdiv1, rate->refdiv, rate->postdiv2,
+		 rate->dsmpd, rate->frac);
+
+	if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 ||
+		rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 ||
+		rate->dsmpd != cur.dsmpd || rate->frac != cur.frac) {
+		struct clk *parent = clk_get_parent(hw->clk);
+
+		if (!parent) {
+			pr_warn("%s: parent of %s not available\n",
+				__func__, __clk_get_name(hw->clk));
+			return;
+		}
+
+		pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
+			 __func__, __clk_get_name(hw->clk));
+		rockchip_rk3399_pll_set_params(pll, rate);
+	}
+}
+
+static const struct clk_ops rockchip_rk3399_pll_clk_norate_ops = {
+	.recalc_rate = rockchip_rk3399_pll_recalc_rate,
+	.enable = rockchip_rk3399_pll_enable,
+	.disable = rockchip_rk3399_pll_disable,
+	.is_enabled = rockchip_rk3399_pll_is_enabled,
+};
+
+static const struct clk_ops rockchip_rk3399_pll_clk_ops = {
+	.recalc_rate = rockchip_rk3399_pll_recalc_rate,
+	.round_rate = rockchip_pll_round_rate,
+	.set_rate = rockchip_rk3399_pll_set_rate,
+	.enable = rockchip_rk3399_pll_enable,
+	.disable = rockchip_rk3399_pll_disable,
+	.is_enabled = rockchip_rk3399_pll_is_enabled,
+	.init = rockchip_rk3399_pll_init,
+};
+
 /*
  * Common registering of pll clocks
  */
 
-struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
+struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
+		enum rockchip_pll_type pll_type,
 		const char *name, const char *const *parent_names,
-		u8 num_parents, void __iomem *base, int con_offset,
-		int grf_lock_offset, int lock_shift, int mode_offset,
-		int mode_shift, struct rockchip_pll_rate_table *rate_table,
-		u8 clk_pll_flags, spinlock_t *lock)
+		u8 num_parents, int con_offset, int grf_lock_offset,
+		int lock_shift, int mode_offset, int mode_shift,
+		struct rockchip_pll_rate_table *rate_table,
+		u8 clk_pll_flags)
 {
 	const char *pll_parents[3];
 	struct clk_init_data init;
@@ -624,14 +888,16 @@
 	/* create the mux on top of the real pll */
 	pll->pll_mux_ops = &clk_mux_ops;
 	pll_mux = &pll->pll_mux;
-	pll_mux->reg = base + mode_offset;
+	pll_mux->reg = ctx->reg_base + mode_offset;
 	pll_mux->shift = mode_shift;
 	pll_mux->mask = PLL_MODE_MASK;
 	pll_mux->flags = 0;
-	pll_mux->lock = lock;
+	pll_mux->lock = &ctx->lock;
 	pll_mux->hw.init = &init;
 
-	if (pll_type == pll_rk3036 || pll_type == pll_rk3066)
+	if (pll_type == pll_rk3036 ||
+	    pll_type == pll_rk3066 ||
+	    pll_type == pll_rk3399)
 		pll_mux->flags |= CLK_MUX_HIWORD_MASK;
 
 	/* the actual muxing is xin24m, pll-output, xin32k */
@@ -688,6 +954,12 @@
 		else
 			init.ops = &rockchip_rk3066_pll_clk_ops;
 		break;
+	case pll_rk3399:
+		if (!pll->rate_table)
+			init.ops = &rockchip_rk3399_pll_clk_norate_ops;
+		else
+			init.ops = &rockchip_rk3399_pll_clk_ops;
+		break;
 	default:
 		pr_warn("%s: Unknown pll type for pll clk %s\n",
 			__func__, name);
@@ -695,11 +967,12 @@
 
 	pll->hw.init = &init;
 	pll->type = pll_type;
-	pll->reg_base = base + con_offset;
+	pll->reg_base = ctx->reg_base + con_offset;
 	pll->lock_offset = grf_lock_offset;
 	pll->lock_shift = lock_shift;
 	pll->flags = clk_pll_flags;
-	pll->lock = lock;
+	pll->lock = &ctx->lock;
+	pll->ctx = ctx;
 
 	pll_clk = clk_register(NULL, &pll->hw);
 	if (IS_ERR(pll_clk)) {
diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c
index 7cdb2d6..924f560 100644
--- a/drivers/clk/rockchip/clk-rk3036.c
+++ b/drivers/clk/rockchip/clk-rk3036.c
@@ -113,7 +113,10 @@
 	.core_reg = RK2928_CLKSEL_CON(0),
 	.div_core_shift = 0,
 	.div_core_mask = 0x1f,
+	.mux_core_alt = 1,
+	.mux_core_main = 0,
 	.mux_core_shift = 7,
+	.mux_core_mask = 0x1,
 };
 
 PNAME(mux_pll_p)		= { "xin24m", "xin24m" };
@@ -437,6 +440,7 @@
 
 static void __init rk3036_clk_init(struct device_node *np)
 {
+	struct rockchip_clk_provider *ctx;
 	void __iomem *reg_base;
 	struct clk *clk;
 
@@ -446,22 +450,27 @@
 		return;
 	}
 
-	rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+	ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+	if (IS_ERR(ctx)) {
+		pr_err("%s: rockchip clk init failed\n", __func__);
+		iounmap(reg_base);
+		return;
+	}
 
 	clk = clk_register_fixed_factor(NULL, "usb480m", "xin24m", 0, 20, 1);
 	if (IS_ERR(clk))
 		pr_warn("%s: could not register clock usb480m: %ld\n",
 			__func__, PTR_ERR(clk));
 
-	rockchip_clk_register_plls(rk3036_pll_clks,
+	rockchip_clk_register_plls(ctx, rk3036_pll_clks,
 				   ARRAY_SIZE(rk3036_pll_clks),
 				   RK3036_GRF_SOC_STATUS0);
-	rockchip_clk_register_branches(rk3036_clk_branches,
+	rockchip_clk_register_branches(ctx, rk3036_clk_branches,
 				  ARRAY_SIZE(rk3036_clk_branches));
 	rockchip_clk_protect_critical(rk3036_critical_clocks,
 				      ARRAY_SIZE(rk3036_critical_clocks));
 
-	rockchip_clk_register_armclk(ARMCLK, "armclk",
+	rockchip_clk_register_armclk(ctx, ARMCLK, "armclk",
 			mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
 			&rk3036_cpuclk_data, rk3036_cpuclk_rates,
 			ARRAY_SIZE(rk3036_cpuclk_rates));
@@ -469,6 +478,8 @@
 	rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
 				  ROCKCHIP_SOFTRST_HIWORD_MASK);
 
-	rockchip_register_restart_notifier(RK2928_GLB_SRST_FST, NULL);
+	rockchip_register_restart_notifier(ctx, RK2928_GLB_SRST_FST, NULL);
+
+	rockchip_clk_of_add_provider(np, ctx);
 }
 CLK_OF_DECLARE(rk3036_cru, "rockchip,rk3036-cru", rk3036_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c
index 40bab39..d0e722a 100644
--- a/drivers/clk/rockchip/clk-rk3188.c
+++ b/drivers/clk/rockchip/clk-rk3188.c
@@ -155,7 +155,10 @@
 	.core_reg = RK2928_CLKSEL_CON(0),
 	.div_core_shift = 0,
 	.div_core_mask = 0x1f,
+	.mux_core_alt = 1,
+	.mux_core_main = 0,
 	.mux_core_shift = 8,
+	.mux_core_mask = 0x1,
 };
 
 #define RK3188_DIV_ACLK_CORE_MASK	0x7
@@ -191,7 +194,10 @@
 	.core_reg = RK2928_CLKSEL_CON(0),
 	.div_core_shift = 9,
 	.div_core_mask = 0x1f,
+	.mux_core_alt = 1,
+	.mux_core_main = 0,
 	.mux_core_shift = 8,
+	.mux_core_mask = 0x1,
 };
 
 PNAME(mux_pll_p)		= { "xin24m", "xin32k" };
@@ -753,57 +759,75 @@
 	"hclk_cpubus"
 };
 
-static void __init rk3188_common_clk_init(struct device_node *np)
+static struct rockchip_clk_provider *__init rk3188_common_clk_init(struct device_node *np)
 {
+	struct rockchip_clk_provider *ctx;
 	void __iomem *reg_base;
 
 	reg_base = of_iomap(np, 0);
 	if (!reg_base) {
 		pr_err("%s: could not map cru region\n", __func__);
-		return;
+		return ERR_PTR(-ENOMEM);
 	}
 
-	rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+	ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+	if (IS_ERR(ctx)) {
+		pr_err("%s: rockchip clk init failed\n", __func__);
+		iounmap(reg_base);
+		return ERR_PTR(-ENOMEM);
+	}
 
-	rockchip_clk_register_branches(common_clk_branches,
+	rockchip_clk_register_branches(ctx, common_clk_branches,
 				  ARRAY_SIZE(common_clk_branches));
 
 	rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
 				  ROCKCHIP_SOFTRST_HIWORD_MASK);
 
-	rockchip_register_restart_notifier(RK2928_GLB_SRST_FST, NULL);
+	rockchip_register_restart_notifier(ctx, RK2928_GLB_SRST_FST, NULL);
+
+	return ctx;
 }
 
 static void __init rk3066a_clk_init(struct device_node *np)
 {
-	rk3188_common_clk_init(np);
-	rockchip_clk_register_plls(rk3066_pll_clks,
+	struct rockchip_clk_provider *ctx;
+
+	ctx = rk3188_common_clk_init(np);
+	if (IS_ERR(ctx))
+		return;
+
+	rockchip_clk_register_plls(ctx, rk3066_pll_clks,
 				   ARRAY_SIZE(rk3066_pll_clks),
 				   RK3066_GRF_SOC_STATUS);
-	rockchip_clk_register_branches(rk3066a_clk_branches,
+	rockchip_clk_register_branches(ctx, rk3066a_clk_branches,
 				  ARRAY_SIZE(rk3066a_clk_branches));
-	rockchip_clk_register_armclk(ARMCLK, "armclk",
+	rockchip_clk_register_armclk(ctx, ARMCLK, "armclk",
 			mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
 			&rk3066_cpuclk_data, rk3066_cpuclk_rates,
 			ARRAY_SIZE(rk3066_cpuclk_rates));
 	rockchip_clk_protect_critical(rk3188_critical_clocks,
 				      ARRAY_SIZE(rk3188_critical_clocks));
+	rockchip_clk_of_add_provider(np, ctx);
 }
 CLK_OF_DECLARE(rk3066a_cru, "rockchip,rk3066a-cru", rk3066a_clk_init);
 
 static void __init rk3188a_clk_init(struct device_node *np)
 {
+	struct rockchip_clk_provider *ctx;
 	struct clk *clk1, *clk2;
 	unsigned long rate;
 	int ret;
 
-	rk3188_common_clk_init(np);
-	rockchip_clk_register_plls(rk3188_pll_clks,
+	ctx = rk3188_common_clk_init(np);
+	if (IS_ERR(ctx))
+		return;
+
+	rockchip_clk_register_plls(ctx, rk3188_pll_clks,
 				   ARRAY_SIZE(rk3188_pll_clks),
 				   RK3188_GRF_SOC_STATUS);
-	rockchip_clk_register_branches(rk3188_clk_branches,
+	rockchip_clk_register_branches(ctx, rk3188_clk_branches,
 				  ARRAY_SIZE(rk3188_clk_branches));
-	rockchip_clk_register_armclk(ARMCLK, "armclk",
+	rockchip_clk_register_armclk(ctx, ARMCLK, "armclk",
 				  mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
 				  &rk3188_cpuclk_data, rk3188_cpuclk_rates,
 				  ARRAY_SIZE(rk3188_cpuclk_rates));
@@ -827,6 +851,7 @@
 
 	rockchip_clk_protect_critical(rk3188_critical_clocks,
 				      ARRAY_SIZE(rk3188_critical_clocks));
+	rockchip_clk_of_add_provider(np, ctx);
 }
 CLK_OF_DECLARE(rk3188a_cru, "rockchip,rk3188a-cru", rk3188a_clk_init);
 
diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c
index 7702d28..016bdb0 100644
--- a/drivers/clk/rockchip/clk-rk3228.c
+++ b/drivers/clk/rockchip/clk-rk3228.c
@@ -111,7 +111,10 @@
 	.core_reg = RK2928_CLKSEL_CON(0),
 	.div_core_shift = 0,
 	.div_core_mask = 0x1f,
+	.mux_core_alt = 1,
+	.mux_core_main = 0,
 	.mux_core_shift = 6,
+	.mux_core_mask = 0x1,
 };
 
 PNAME(mux_pll_p)		= { "clk_24m", "xin24m" };
@@ -625,6 +628,7 @@
 
 static void __init rk3228_clk_init(struct device_node *np)
 {
+	struct rockchip_clk_provider *ctx;
 	void __iomem *reg_base;
 
 	reg_base = of_iomap(np, 0);
@@ -633,17 +637,22 @@
 		return;
 	}
 
-	rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+	ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+	if (IS_ERR(ctx)) {
+		pr_err("%s: rockchip clk init failed\n", __func__);
+		iounmap(reg_base);
+		return;
+	}
 
-	rockchip_clk_register_plls(rk3228_pll_clks,
+	rockchip_clk_register_plls(ctx, rk3228_pll_clks,
 				   ARRAY_SIZE(rk3228_pll_clks),
 				   RK3228_GRF_SOC_STATUS0);
-	rockchip_clk_register_branches(rk3228_clk_branches,
+	rockchip_clk_register_branches(ctx, rk3228_clk_branches,
 				  ARRAY_SIZE(rk3228_clk_branches));
 	rockchip_clk_protect_critical(rk3228_critical_clocks,
 				      ARRAY_SIZE(rk3228_critical_clocks));
 
-	rockchip_clk_register_armclk(ARMCLK, "armclk",
+	rockchip_clk_register_armclk(ctx, ARMCLK, "armclk",
 			mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
 			&rk3228_cpuclk_data, rk3228_cpuclk_rates,
 			ARRAY_SIZE(rk3228_cpuclk_rates));
@@ -651,6 +660,8 @@
 	rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
 				  ROCKCHIP_SOFTRST_HIWORD_MASK);
 
-	rockchip_register_restart_notifier(RK3228_GLB_SRST_FST, NULL);
+	rockchip_register_restart_notifier(ctx, RK3228_GLB_SRST_FST, NULL);
+
+	rockchip_clk_of_add_provider(np, ctx);
 }
 CLK_OF_DECLARE(rk3228_cru, "rockchip,rk3228-cru", rk3228_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 3cb7216..39af05a 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -165,7 +165,10 @@
 	.core_reg = RK3288_CLKSEL_CON(0),
 	.div_core_shift = 8,
 	.div_core_mask = 0x1f,
+	.mux_core_alt = 1,
+	.mux_core_main = 0,
 	.mux_core_shift = 15,
+	.mux_core_mask = 0x1,
 };
 
 PNAME(mux_pll_p)		= { "xin24m", "xin32k" };
@@ -878,6 +881,7 @@
 
 static void __init rk3288_clk_init(struct device_node *np)
 {
+	struct rockchip_clk_provider *ctx;
 	struct clk *clk;
 
 	rk3288_cru_base = of_iomap(np, 0);
@@ -886,7 +890,12 @@
 		return;
 	}
 
-	rockchip_clk_init(np, rk3288_cru_base, CLK_NR_CLKS);
+	ctx = rockchip_clk_init(np, rk3288_cru_base, CLK_NR_CLKS);
+	if (IS_ERR(ctx)) {
+		pr_err("%s: rockchip clk init failed\n", __func__);
+		iounmap(rk3288_cru_base);
+		return;
+	}
 
 	/* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */
 	clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
@@ -894,17 +903,17 @@
 		pr_warn("%s: could not register clock pclk_wdt: %ld\n",
 			__func__, PTR_ERR(clk));
 	else
-		rockchip_clk_add_lookup(clk, PCLK_WDT);
+		rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
 
-	rockchip_clk_register_plls(rk3288_pll_clks,
+	rockchip_clk_register_plls(ctx, rk3288_pll_clks,
 				   ARRAY_SIZE(rk3288_pll_clks),
 				   RK3288_GRF_SOC_STATUS1);
-	rockchip_clk_register_branches(rk3288_clk_branches,
+	rockchip_clk_register_branches(ctx, rk3288_clk_branches,
 				  ARRAY_SIZE(rk3288_clk_branches));
 	rockchip_clk_protect_critical(rk3288_critical_clocks,
 				      ARRAY_SIZE(rk3288_critical_clocks));
 
-	rockchip_clk_register_armclk(ARMCLK, "armclk",
+	rockchip_clk_register_armclk(ctx, ARMCLK, "armclk",
 			mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
 			&rk3288_cpuclk_data, rk3288_cpuclk_rates,
 			ARRAY_SIZE(rk3288_cpuclk_rates));
@@ -913,8 +922,10 @@
 				  rk3288_cru_base + RK3288_SOFTRST_CON(0),
 				  ROCKCHIP_SOFTRST_HIWORD_MASK);
 
-	rockchip_register_restart_notifier(RK3288_GLB_SRST_FST,
+	rockchip_register_restart_notifier(ctx, RK3288_GLB_SRST_FST,
 					   rk3288_clk_shutdown);
 	register_syscore_ops(&rk3288_clk_syscore_ops);
+
+	rockchip_clk_of_add_provider(np, ctx);
 }
 CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c
index a2bb122..6cb474c 100644
--- a/drivers/clk/rockchip/clk-rk3368.c
+++ b/drivers/clk/rockchip/clk-rk3368.c
@@ -165,14 +165,20 @@
 	.core_reg = RK3368_CLKSEL_CON(0),
 	.div_core_shift = 0,
 	.div_core_mask = 0x1f,
+	.mux_core_alt = 1,
+	.mux_core_main = 0,
 	.mux_core_shift = 7,
+	.mux_core_mask = 0x1,
 };
 
 static const struct rockchip_cpuclk_reg_data rk3368_cpuclkl_data = {
 	.core_reg = RK3368_CLKSEL_CON(2),
 	.div_core_shift = 0,
+	.mux_core_alt = 1,
+	.mux_core_main = 0,
 	.div_core_mask = 0x1f,
 	.mux_core_shift = 7,
+	.mux_core_mask = 0x1,
 };
 
 #define RK3368_DIV_ACLKM_MASK		0x1f
@@ -856,6 +862,7 @@
 
 static void __init rk3368_clk_init(struct device_node *np)
 {
+	struct rockchip_clk_provider *ctx;
 	void __iomem *reg_base;
 	struct clk *clk;
 
@@ -865,7 +872,12 @@
 		return;
 	}
 
-	rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+	ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+	if (IS_ERR(ctx)) {
+		pr_err("%s: rockchip clk init failed\n", __func__);
+		iounmap(reg_base);
+		return;
+	}
 
 	/* Watchdog pclk is controlled by sgrf_soc_con3[7]. */
 	clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
@@ -873,22 +885,22 @@
 		pr_warn("%s: could not register clock pclk_wdt: %ld\n",
 			__func__, PTR_ERR(clk));
 	else
-		rockchip_clk_add_lookup(clk, PCLK_WDT);
+		rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
 
-	rockchip_clk_register_plls(rk3368_pll_clks,
+	rockchip_clk_register_plls(ctx, rk3368_pll_clks,
 				   ARRAY_SIZE(rk3368_pll_clks),
 				   RK3368_GRF_SOC_STATUS0);
-	rockchip_clk_register_branches(rk3368_clk_branches,
+	rockchip_clk_register_branches(ctx, rk3368_clk_branches,
 				  ARRAY_SIZE(rk3368_clk_branches));
 	rockchip_clk_protect_critical(rk3368_critical_clocks,
 				      ARRAY_SIZE(rk3368_critical_clocks));
 
-	rockchip_clk_register_armclk(ARMCLKB, "armclkb",
+	rockchip_clk_register_armclk(ctx, ARMCLKB, "armclkb",
 			mux_armclkb_p, ARRAY_SIZE(mux_armclkb_p),
 			&rk3368_cpuclkb_data, rk3368_cpuclkb_rates,
 			ARRAY_SIZE(rk3368_cpuclkb_rates));
 
-	rockchip_clk_register_armclk(ARMCLKL, "armclkl",
+	rockchip_clk_register_armclk(ctx, ARMCLKL, "armclkl",
 			mux_armclkl_p, ARRAY_SIZE(mux_armclkl_p),
 			&rk3368_cpuclkl_data, rk3368_cpuclkl_rates,
 			ARRAY_SIZE(rk3368_cpuclkl_rates));
@@ -896,6 +908,8 @@
 	rockchip_register_softrst(np, 15, reg_base + RK3368_SOFTRST_CON(0),
 				  ROCKCHIP_SOFTRST_HIWORD_MASK);
 
-	rockchip_register_restart_notifier(RK3368_GLB_SRST_FST, NULL);
+	rockchip_register_restart_notifier(ctx, RK3368_GLB_SRST_FST, NULL);
+
+	rockchip_clk_of_add_provider(np, ctx);
 }
 CLK_OF_DECLARE(rk3368_cru, "rockchip,rk3368-cru", rk3368_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
new file mode 100644
index 0000000..5248726
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -0,0 +1,1573 @@
+/*
+ * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.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.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <dt-bindings/clock/rk3399-cru.h>
+#include "clk.h"
+
+enum rk3399_plls {
+	lpll, bpll, dpll, cpll, gpll, npll, vpll,
+};
+
+enum rk3399_pmu_plls {
+	ppll,
+};
+
+static struct rockchip_pll_rate_table rk3399_pll_rates[] = {
+	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+	RK3036_PLL_RATE(2208000000, 1, 92, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2184000000, 1, 91, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2160000000, 1, 90, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2136000000, 1, 89, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2112000000, 1, 88, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2088000000, 1, 87, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2064000000, 1, 86, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2040000000, 1, 85, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2016000000, 1, 84, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1992000000, 1, 83, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1968000000, 1, 82, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1944000000, 1, 81, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1920000000, 1, 80, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1872000000, 1, 78, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1848000000, 1, 77, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1824000000, 1, 76, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1776000000, 1, 74, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1752000000, 1, 73, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1728000000, 1, 72, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1680000000, 1, 70, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1656000000, 1, 69, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1632000000, 1, 68, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
+	RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 912000000, 1, 76, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 900000000, 4, 300, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 888000000, 1, 74, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 800000000, 6, 400, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 676000000, 3, 169, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0),
+	RK3036_PLL_RATE( 594000000, 1, 99, 4, 1, 1, 0),
+	RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0),
+	RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0),
+	RK3036_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0),
+	RK3036_PLL_RATE( 297000000, 1, 99, 4, 2, 1, 0),
+	RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0),
+	RK3036_PLL_RATE( 148500000, 1, 99, 4, 4, 1, 0),
+	RK3036_PLL_RATE(  96000000, 1, 64, 4, 4, 1, 0),
+	RK3036_PLL_RATE(  74250000, 2, 99, 4, 4, 1, 0),
+	RK3036_PLL_RATE(  54000000, 1, 54, 6, 4, 1, 0),
+	RK3036_PLL_RATE(  27000000, 1, 27, 6, 4, 1, 0),
+	{ /* sentinel */ },
+};
+
+/* CRU parents */
+PNAME(mux_pll_p)				= { "xin24m", "xin32k" };
+
+PNAME(mux_armclkl_p)				= { "clk_core_l_lpll_src",
+						    "clk_core_l_bpll_src",
+						    "clk_core_l_dpll_src",
+						    "clk_core_l_gpll_src" };
+PNAME(mux_armclkb_p)				= { "clk_core_b_lpll_src",
+						    "clk_core_b_bpll_src",
+						    "clk_core_b_dpll_src",
+						    "clk_core_b_gpll_src" };
+PNAME(mux_aclk_cci_p)				= { "cpll_aclk_cci_src",
+						    "gpll_aclk_cci_src",
+						    "npll_aclk_cci_src",
+						    "vpll_aclk_cci_src" };
+PNAME(mux_cci_trace_p)				= { "cpll_cci_trace",
+						    "gpll_cci_trace" };
+PNAME(mux_cs_p)					= { "cpll_cs", "gpll_cs",
+						    "npll_cs"};
+PNAME(mux_aclk_perihp_p)			= { "cpll_aclk_perihp_src",
+						    "gpll_aclk_perihp_src" };
+
+PNAME(mux_pll_src_cpll_gpll_p)			= { "cpll", "gpll" };
+PNAME(mux_pll_src_cpll_gpll_npll_p)		= { "cpll", "gpll", "npll" };
+PNAME(mux_pll_src_cpll_gpll_ppll_p)		= { "cpll", "gpll", "ppll" };
+PNAME(mux_pll_src_cpll_gpll_upll_p)		= { "cpll", "gpll", "upll" };
+PNAME(mux_pll_src_npll_cpll_gpll_p)		= { "npll", "cpll", "gpll" };
+PNAME(mux_pll_src_cpll_gpll_npll_ppll_p)	= { "cpll", "gpll", "npll",
+						    "ppll" };
+PNAME(mux_pll_src_cpll_gpll_npll_24m_p)		= { "cpll", "gpll", "npll",
+						    "xin24m" };
+PNAME(mux_pll_src_cpll_gpll_npll_usbphy480m_p)	= { "cpll", "gpll", "npll",
+						    "clk_usbphy_480m" };
+PNAME(mux_pll_src_ppll_cpll_gpll_npll_p)	= { "ppll", "cpll", "gpll",
+						    "npll", "upll" };
+PNAME(mux_pll_src_cpll_gpll_npll_upll_24m_p)	= { "cpll", "gpll", "npll",
+						    "upll", "xin24m" };
+PNAME(mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p) = { "cpll", "gpll", "npll",
+						    "ppll", "upll", "xin24m" };
+
+PNAME(mux_pll_src_vpll_cpll_gpll_p)		= { "vpll", "cpll", "gpll" };
+PNAME(mux_pll_src_vpll_cpll_gpll_npll_p)	= { "vpll", "cpll", "gpll",
+						    "npll" };
+PNAME(mux_pll_src_vpll_cpll_gpll_24m_p)		= { "vpll", "cpll", "gpll",
+						    "xin24m" };
+
+PNAME(mux_dclk_vop0_p)			= { "dclk_vop0_div",
+					    "dclk_vop0_frac" };
+PNAME(mux_dclk_vop1_p)			= { "dclk_vop1_div",
+					    "dclk_vop1_frac" };
+
+PNAME(mux_clk_cif_p)			= { "clk_cifout_src", "xin24m" };
+
+PNAME(mux_pll_src_24m_usbphy480m_p)	= { "xin24m", "clk_usbphy_480m" };
+PNAME(mux_pll_src_24m_pciephy_p)	= { "xin24m", "clk_pciephy_ref100m" };
+PNAME(mux_pll_src_24m_32k_cpll_gpll_p)	= { "xin24m", "xin32k",
+					    "cpll", "gpll" };
+PNAME(mux_pciecore_cru_phy_p)		= { "clk_pcie_core_cru",
+					    "clk_pcie_core_phy" };
+
+PNAME(mux_aclk_emmc_p)			= { "cpll_aclk_emmc_src",
+					    "gpll_aclk_emmc_src" };
+
+PNAME(mux_aclk_perilp0_p)		= { "cpll_aclk_perilp0_src",
+					    "gpll_aclk_perilp0_src" };
+
+PNAME(mux_fclk_cm0s_p)			= { "cpll_fclk_cm0s_src",
+					    "gpll_fclk_cm0s_src" };
+
+PNAME(mux_hclk_perilp1_p)		= { "cpll_hclk_perilp1_src",
+					    "gpll_hclk_perilp1_src" };
+
+PNAME(mux_clk_testout1_p)		= { "clk_testout1_pll_src", "xin24m" };
+PNAME(mux_clk_testout2_p)		= { "clk_testout2_pll_src", "xin24m" };
+
+PNAME(mux_usbphy_480m_p)		= { "clk_usbphy0_480m_src",
+					    "clk_usbphy1_480m_src" };
+PNAME(mux_aclk_gmac_p)			= { "cpll_aclk_gmac_src",
+					    "gpll_aclk_gmac_src" };
+PNAME(mux_rmii_p)			= { "clk_gmac", "clkin_gmac" };
+PNAME(mux_spdif_p)			= { "clk_spdif_div", "clk_spdif_frac",
+					    "clkin_i2s", "xin12m" };
+PNAME(mux_i2s0_p)			= { "clk_i2s0_div", "clk_i2s0_frac",
+					    "clkin_i2s", "xin12m" };
+PNAME(mux_i2s1_p)			= { "clk_i2s1_div", "clk_i2s1_frac",
+					    "clkin_i2s", "xin12m" };
+PNAME(mux_i2s2_p)			= { "clk_i2s2_div", "clk_i2s2_frac",
+					    "clkin_i2s", "xin12m" };
+PNAME(mux_i2sch_p)			= { "clk_i2s0", "clk_i2s1",
+					    "clk_i2s2" };
+PNAME(mux_i2sout_p)			= { "clk_i2sout_src", "xin12m" };
+
+PNAME(mux_uart0_p)	= { "clk_uart0_div", "clk_uart0_frac", "xin24m" };
+PNAME(mux_uart1_p)	= { "clk_uart1_div", "clk_uart1_frac", "xin24m" };
+PNAME(mux_uart2_p)	= { "clk_uart2_div", "clk_uart2_frac", "xin24m" };
+PNAME(mux_uart3_p)	= { "clk_uart3_div", "clk_uart3_frac", "xin24m" };
+
+/* PMU CRU parents */
+PNAME(mux_ppll_24m_p)		= { "ppll", "xin24m" };
+PNAME(mux_24m_ppll_p)		= { "xin24m", "ppll" };
+PNAME(mux_fclk_cm0s_pmu_ppll_p)	= { "fclk_cm0s_pmu_ppll_src", "xin24m" };
+PNAME(mux_wifi_pmu_p)		= { "clk_wifi_div", "clk_wifi_frac" };
+PNAME(mux_uart4_pmu_p)		= { "clk_uart4_div", "clk_uart4_frac",
+				    "xin24m" };
+PNAME(mux_clk_testout2_2io_p)	= { "clk_testout2", "clk_32k_suspend_pmu" };
+
+static struct rockchip_pll_clock rk3399_pll_clks[] __initdata = {
+	[lpll] = PLL(pll_rk3399, PLL_APLLL, "lpll", mux_pll_p, 0, RK3399_PLL_CON(0),
+		     RK3399_PLL_CON(3), 8, 31, 0, rk3399_pll_rates),
+	[bpll] = PLL(pll_rk3399, PLL_APLLB, "bpll", mux_pll_p, 0, RK3399_PLL_CON(8),
+		     RK3399_PLL_CON(11), 8, 31, 0, rk3399_pll_rates),
+	[dpll] = PLL(pll_rk3399, PLL_DPLL, "dpll", mux_pll_p, 0, RK3399_PLL_CON(16),
+		     RK3399_PLL_CON(19), 8, 31, 0, NULL),
+	[cpll] = PLL(pll_rk3399, PLL_CPLL, "cpll", mux_pll_p, 0, RK3399_PLL_CON(24),
+		     RK3399_PLL_CON(27), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
+	[gpll] = PLL(pll_rk3399, PLL_GPLL, "gpll", mux_pll_p, 0, RK3399_PLL_CON(32),
+		     RK3399_PLL_CON(35), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
+	[npll] = PLL(pll_rk3399, PLL_NPLL, "npll",  mux_pll_p, 0, RK3399_PLL_CON(40),
+		     RK3399_PLL_CON(43), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
+	[vpll] = PLL(pll_rk3399, PLL_VPLL, "vpll",  mux_pll_p, 0, RK3399_PLL_CON(48),
+		     RK3399_PLL_CON(51), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
+};
+
+static struct rockchip_pll_clock rk3399_pmu_pll_clks[] __initdata = {
+	[ppll] = PLL(pll_rk3399, PLL_PPLL, "ppll",  mux_pll_p, 0, RK3399_PMU_PLL_CON(0),
+		     RK3399_PMU_PLL_CON(3), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
+};
+
+#define MFLAGS CLK_MUX_HIWORD_MASK
+#define DFLAGS CLK_DIVIDER_HIWORD_MASK
+#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+#define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK
+
+static struct rockchip_clk_branch rk3399_spdif_fracmux __initdata =
+	MUX(0, "clk_spdif_mux", mux_spdif_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(32), 13, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_i2s0_fracmux __initdata =
+	MUX(0, "clk_i2s0_mux", mux_i2s0_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(28), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_i2s1_fracmux __initdata =
+	MUX(0, "clk_i2s1_mux", mux_i2s1_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(29), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_i2s2_fracmux __initdata =
+	MUX(0, "clk_i2s2_mux", mux_i2s2_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(30), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_uart0_fracmux __initdata =
+	MUX(SCLK_UART0, "clk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(33), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_uart1_fracmux __initdata =
+	MUX(SCLK_UART1, "clk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(34), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_uart2_fracmux __initdata =
+	MUX(SCLK_UART2, "clk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(35), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_uart3_fracmux __initdata =
+	MUX(SCLK_UART3, "clk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(36), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_uart4_pmu_fracmux __initdata =
+	MUX(SCLK_UART4_PMU, "clk_uart4_pmu", mux_uart4_pmu_p, CLK_SET_RATE_PARENT,
+			RK3399_PMU_CLKSEL_CON(5), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_dclk_vop0_fracmux __initdata =
+	MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(49), 11, 1, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_dclk_vop1_fracmux __initdata =
+	MUX(DCLK_VOP1, "dclk_vop1", mux_dclk_vop1_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(50), 11, 1, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_pmuclk_wifi_fracmux __initdata =
+	MUX(SCLK_WIFI_PMU, "clk_wifi_pmu", mux_wifi_pmu_p, CLK_SET_RATE_PARENT,
+			RK3399_PMU_CLKSEL_CON(1), 14, 1, MFLAGS);
+
+static const struct rockchip_cpuclk_reg_data rk3399_cpuclkl_data = {
+	.core_reg = RK3399_CLKSEL_CON(0),
+	.div_core_shift = 0,
+	.div_core_mask = 0x1f,
+	.mux_core_alt = 3,
+	.mux_core_main = 0,
+	.mux_core_shift = 6,
+	.mux_core_mask = 0x3,
+};
+
+static const struct rockchip_cpuclk_reg_data rk3399_cpuclkb_data = {
+	.core_reg = RK3399_CLKSEL_CON(2),
+	.div_core_shift = 0,
+	.div_core_mask = 0x1f,
+	.mux_core_alt = 3,
+	.mux_core_main = 1,
+	.mux_core_shift = 6,
+	.mux_core_mask = 0x3,
+};
+
+#define RK3399_DIV_ACLKM_MASK		0x1f
+#define RK3399_DIV_ACLKM_SHIFT		8
+#define RK3399_DIV_ATCLK_MASK		0x1f
+#define RK3399_DIV_ATCLK_SHIFT		0
+#define RK3399_DIV_PCLK_DBG_MASK	0x1f
+#define RK3399_DIV_PCLK_DBG_SHIFT	8
+
+#define RK3399_CLKSEL0(_offs, _aclkm)					\
+	{								\
+		.reg = RK3399_CLKSEL_CON(0 + _offs),			\
+		.val = HIWORD_UPDATE(_aclkm, RK3399_DIV_ACLKM_MASK,	\
+				RK3399_DIV_ACLKM_SHIFT),		\
+	}
+#define RK3399_CLKSEL1(_offs, _atclk, _pdbg)				\
+	{								\
+		.reg = RK3399_CLKSEL_CON(1 + _offs),			\
+		.val = HIWORD_UPDATE(_atclk, RK3399_DIV_ATCLK_MASK,	\
+				RK3399_DIV_ATCLK_SHIFT) |		\
+		       HIWORD_UPDATE(_pdbg, RK3399_DIV_PCLK_DBG_MASK,	\
+				RK3399_DIV_PCLK_DBG_SHIFT),		\
+	}
+
+/* cluster_l: aclkm in clksel0, rest in clksel1 */
+#define RK3399_CPUCLKL_RATE(_prate, _aclkm, _atclk, _pdbg)		\
+	{								\
+		.prate = _prate##U,					\
+		.divs = {						\
+			RK3399_CLKSEL0(0, _aclkm),			\
+			RK3399_CLKSEL1(0, _atclk, _pdbg),		\
+		},							\
+	}
+
+/* cluster_b: aclkm in clksel2, rest in clksel3 */
+#define RK3399_CPUCLKB_RATE(_prate, _aclkm, _atclk, _pdbg)		\
+	{								\
+		.prate = _prate##U,					\
+		.divs = {						\
+			RK3399_CLKSEL0(2, _aclkm),			\
+			RK3399_CLKSEL1(2, _atclk, _pdbg),		\
+		},							\
+	}
+
+static struct rockchip_cpuclk_rate_table rk3399_cpuclkl_rates[] __initdata = {
+	RK3399_CPUCLKL_RATE(1800000000, 1, 8, 8),
+	RK3399_CPUCLKL_RATE(1704000000, 1, 8, 8),
+	RK3399_CPUCLKL_RATE(1608000000, 1, 7, 7),
+	RK3399_CPUCLKL_RATE(1512000000, 1, 7, 7),
+	RK3399_CPUCLKL_RATE(1488000000, 1, 6, 6),
+	RK3399_CPUCLKL_RATE(1416000000, 1, 6, 6),
+	RK3399_CPUCLKL_RATE(1200000000, 1, 5, 5),
+	RK3399_CPUCLKL_RATE(1008000000, 1, 5, 5),
+	RK3399_CPUCLKL_RATE( 816000000, 1, 4, 4),
+	RK3399_CPUCLKL_RATE( 696000000, 1, 3, 3),
+	RK3399_CPUCLKL_RATE( 600000000, 1, 3, 3),
+	RK3399_CPUCLKL_RATE( 408000000, 1, 2, 2),
+	RK3399_CPUCLKL_RATE( 312000000, 1, 1, 1),
+	RK3399_CPUCLKL_RATE( 216000000, 1, 1, 1),
+	RK3399_CPUCLKL_RATE(  96000000, 1, 1, 1),
+};
+
+static struct rockchip_cpuclk_rate_table rk3399_cpuclkb_rates[] __initdata = {
+	RK3399_CPUCLKB_RATE(2208000000, 1, 11, 11),
+	RK3399_CPUCLKB_RATE(2184000000, 1, 11, 11),
+	RK3399_CPUCLKB_RATE(2088000000, 1, 10, 10),
+	RK3399_CPUCLKB_RATE(2040000000, 1, 10, 10),
+	RK3399_CPUCLKB_RATE(1992000000, 1, 9, 9),
+	RK3399_CPUCLKB_RATE(1896000000, 1, 9, 9),
+	RK3399_CPUCLKB_RATE(1800000000, 1, 8, 8),
+	RK3399_CPUCLKB_RATE(1704000000, 1, 8, 8),
+	RK3399_CPUCLKB_RATE(1608000000, 1, 7, 7),
+	RK3399_CPUCLKB_RATE(1512000000, 1, 7, 7),
+	RK3399_CPUCLKB_RATE(1488000000, 1, 6, 6),
+	RK3399_CPUCLKB_RATE(1416000000, 1, 6, 6),
+	RK3399_CPUCLKB_RATE(1200000000, 1, 5, 5),
+	RK3399_CPUCLKB_RATE(1008000000, 1, 5, 5),
+	RK3399_CPUCLKB_RATE( 816000000, 1, 4, 4),
+	RK3399_CPUCLKB_RATE( 696000000, 1, 3, 3),
+	RK3399_CPUCLKB_RATE( 600000000, 1, 3, 3),
+	RK3399_CPUCLKB_RATE( 408000000, 1, 2, 2),
+	RK3399_CPUCLKB_RATE( 312000000, 1, 1, 1),
+	RK3399_CPUCLKB_RATE( 216000000, 1, 1, 1),
+	RK3399_CPUCLKB_RATE(  96000000, 1, 1, 1),
+};
+
+static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
+	/*
+	 * CRU Clock-Architecture
+	 */
+
+	/* usbphy */
+	GATE(SCLK_USB2PHY0_REF, "clk_usb2phy0_ref", "xin24m", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(6), 5, GFLAGS),
+	GATE(SCLK_USB2PHY1_REF, "clk_usb2phy1_ref", "xin24m", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(6), 6, GFLAGS),
+
+	GATE(0, "clk_usbphy0_480m_src", "clk_usbphy0_480m", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(13), 12, GFLAGS),
+	GATE(0, "clk_usbphy1_480m_src", "clk_usbphy1_480m", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(13), 12, GFLAGS),
+	MUX(0, "clk_usbphy_480m", mux_usbphy_480m_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(14), 6, 1, MFLAGS),
+
+	MUX(0, "upll", mux_pll_src_24m_usbphy480m_p, 0,
+			RK3399_CLKSEL_CON(14), 15, 1, MFLAGS),
+
+	COMPOSITE_NODIV(SCLK_HSICPHY, "clk_hsicphy", mux_pll_src_cpll_gpll_npll_usbphy480m_p, 0,
+			RK3399_CLKSEL_CON(19), 0, 2, MFLAGS,
+			RK3399_CLKGATE_CON(6), 4, GFLAGS),
+
+	COMPOSITE(ACLK_USB3, "aclk_usb3", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(39), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 0, GFLAGS),
+	GATE(ACLK_USB3_NOC, "aclk_usb3_noc", "aclk_usb3", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(30), 0, GFLAGS),
+	GATE(ACLK_USB3OTG0, "aclk_usb3otg0", "aclk_usb3", 0,
+			RK3399_CLKGATE_CON(30), 1, GFLAGS),
+	GATE(ACLK_USB3OTG1, "aclk_usb3otg1", "aclk_usb3", 0,
+			RK3399_CLKGATE_CON(30), 2, GFLAGS),
+	GATE(ACLK_USB3_RKSOC_AXI_PERF, "aclk_usb3_rksoc_axi_perf", "aclk_usb3", 0,
+			RK3399_CLKGATE_CON(30), 3, GFLAGS),
+	GATE(ACLK_USB3_GRF, "aclk_usb3_grf", "aclk_usb3", 0,
+			RK3399_CLKGATE_CON(30), 4, GFLAGS),
+
+	GATE(SCLK_USB3OTG0_REF, "clk_usb3otg0_ref", "xin24m", 0,
+			RK3399_CLKGATE_CON(12), 1, GFLAGS),
+	GATE(SCLK_USB3OTG1_REF, "clk_usb3otg1_ref", "xin24m", 0,
+			RK3399_CLKGATE_CON(12), 2, GFLAGS),
+
+	COMPOSITE(SCLK_USB3OTG0_SUSPEND, "clk_usb3otg0_suspend", mux_pll_p, 0,
+			RK3399_CLKSEL_CON(40), 15, 1, MFLAGS, 0, 10, DFLAGS,
+			RK3399_CLKGATE_CON(12), 3, GFLAGS),
+
+	COMPOSITE(SCLK_USB3OTG1_SUSPEND, "clk_usb3otg1_suspend", mux_pll_p, 0,
+			RK3399_CLKSEL_CON(41), 15, 1, MFLAGS, 0, 10, DFLAGS,
+			RK3399_CLKGATE_CON(12), 4, GFLAGS),
+
+	COMPOSITE(SCLK_UPHY0_TCPDPHY_REF, "clk_uphy0_tcpdphy_ref", mux_pll_p, 0,
+			RK3399_CLKSEL_CON(64), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 4, GFLAGS),
+
+	COMPOSITE(SCLK_UPHY0_TCPDCORE, "clk_uphy0_tcpdcore", mux_pll_src_24m_32k_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(64), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 5, GFLAGS),
+
+	COMPOSITE(SCLK_UPHY1_TCPDPHY_REF, "clk_uphy1_tcpdphy_ref", mux_pll_p, 0,
+			RK3399_CLKSEL_CON(65), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 6, GFLAGS),
+
+	COMPOSITE(SCLK_UPHY1_TCPDCORE, "clk_uphy1_tcpdcore", mux_pll_src_24m_32k_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(65), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 7, GFLAGS),
+
+	/* little core */
+	GATE(0, "clk_core_l_lpll_src", "lpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(0), 0, GFLAGS),
+	GATE(0, "clk_core_l_bpll_src", "bpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(0), 1, GFLAGS),
+	GATE(0, "clk_core_l_dpll_src", "dpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(0), 2, GFLAGS),
+	GATE(0, "clk_core_l_gpll_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(0), 3, GFLAGS),
+
+	COMPOSITE_NOMUX(0, "aclkm_core_l", "armclkl", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(0), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3399_CLKGATE_CON(0), 4, GFLAGS),
+	COMPOSITE_NOMUX(0, "atclk_core_l", "armclkl", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(1), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3399_CLKGATE_CON(0), 5, GFLAGS),
+	COMPOSITE_NOMUX(0, "pclk_dbg_core_l", "armclkl", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(1), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3399_CLKGATE_CON(0), 6, GFLAGS),
+
+	GATE(ACLK_CORE_ADB400_CORE_L_2_CCI500, "aclk_core_adb400_core_l_2_cci500", "aclkm_core_l", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 12, GFLAGS),
+	GATE(ACLK_PERF_CORE_L, "aclk_perf_core_l", "aclkm_core_l", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 13, GFLAGS),
+
+	GATE(0, "clk_dbg_pd_core_l", "armclkl", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 9, GFLAGS),
+	GATE(ACLK_GIC_ADB400_GIC_2_CORE_L, "aclk_core_adb400_gic_2_core_l", "armclkl", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 10, GFLAGS),
+	GATE(ACLK_GIC_ADB400_CORE_L_2_GIC, "aclk_core_adb400_core_l_2_gic", "armclkl", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 11, GFLAGS),
+	GATE(SCLK_PVTM_CORE_L, "clk_pvtm_core_l", "xin24m", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(0), 7, GFLAGS),
+
+	/* big core */
+	GATE(0, "clk_core_b_lpll_src", "lpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(1), 0, GFLAGS),
+	GATE(0, "clk_core_b_bpll_src", "bpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(1), 1, GFLAGS),
+	GATE(0, "clk_core_b_dpll_src", "dpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(1), 2, GFLAGS),
+	GATE(0, "clk_core_b_gpll_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(1), 3, GFLAGS),
+
+	COMPOSITE_NOMUX(0, "aclkm_core_b", "armclkb", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(2), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3399_CLKGATE_CON(1), 4, GFLAGS),
+	COMPOSITE_NOMUX(0, "atclk_core_b", "armclkb", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(3), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3399_CLKGATE_CON(1), 5, GFLAGS),
+	COMPOSITE_NOMUX(0, "pclk_dbg_core_b", "armclkb", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(3), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3399_CLKGATE_CON(1), 6, GFLAGS),
+
+	GATE(ACLK_CORE_ADB400_CORE_B_2_CCI500, "aclk_core_adb400_core_b_2_cci500", "aclkm_core_b", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 5, GFLAGS),
+	GATE(ACLK_PERF_CORE_B, "aclk_perf_core_b", "aclkm_core_b", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 6, GFLAGS),
+
+	GATE(0, "clk_dbg_pd_core_b", "armclkb", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 1, GFLAGS),
+	GATE(ACLK_GIC_ADB400_GIC_2_CORE_B, "aclk_core_adb400_gic_2_core_b", "armclkb", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 3, GFLAGS),
+	GATE(ACLK_GIC_ADB400_CORE_B_2_GIC, "aclk_core_adb400_core_b_2_gic", "armclkb", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 4, GFLAGS),
+
+	DIV(0, "pclken_dbg_core_b", "pclk_dbg_core_b", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(3), 13, 2, DFLAGS | CLK_DIVIDER_READ_ONLY),
+
+	GATE(0, "pclk_dbg_cxcs_pd_core_b", "pclk_dbg_core_b", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 2, GFLAGS),
+
+	GATE(SCLK_PVTM_CORE_B, "clk_pvtm_core_b", "xin24m", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(1), 7, GFLAGS),
+
+	/* gmac */
+	GATE(0, "cpll_aclk_gmac_src", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(6), 9, GFLAGS),
+	GATE(0, "gpll_aclk_gmac_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(6), 8, GFLAGS),
+	COMPOSITE(0, "aclk_gmac_pre", mux_aclk_gmac_p, 0,
+			RK3399_CLKSEL_CON(20), 7, 1, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(6), 10, GFLAGS),
+
+	GATE(ACLK_GMAC, "aclk_gmac", "aclk_gmac_pre", 0,
+			RK3399_CLKGATE_CON(32), 0, GFLAGS),
+	GATE(ACLK_GMAC_NOC, "aclk_gmac_noc", "aclk_gmac_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(32), 1, GFLAGS),
+	GATE(ACLK_PERF_GMAC, "aclk_perf_gmac", "aclk_gmac_pre", 0,
+			RK3399_CLKGATE_CON(32), 4, GFLAGS),
+
+	COMPOSITE_NOMUX(0, "pclk_gmac_pre", "aclk_gmac_pre", 0,
+			RK3399_CLKSEL_CON(19), 8, 3, DFLAGS,
+			RK3399_CLKGATE_CON(6), 11, GFLAGS),
+	GATE(PCLK_GMAC, "pclk_gmac", "pclk_gmac_pre", 0,
+			RK3399_CLKGATE_CON(32), 2, GFLAGS),
+	GATE(PCLK_GMAC_NOC, "pclk_gmac_noc", "pclk_gmac_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(32), 3, GFLAGS),
+
+	COMPOSITE(SCLK_MAC, "clk_gmac", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(20), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(5), 5, GFLAGS),
+
+	MUX(SCLK_RMII_SRC, "clk_rmii_src", mux_rmii_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(19), 4, 1, MFLAGS),
+	GATE(SCLK_MACREF_OUT, "clk_mac_refout", "clk_rmii_src", 0,
+			RK3399_CLKGATE_CON(5), 6, GFLAGS),
+	GATE(SCLK_MACREF, "clk_mac_ref", "clk_rmii_src", 0,
+			RK3399_CLKGATE_CON(5), 7, GFLAGS),
+	GATE(SCLK_MAC_RX, "clk_rmii_rx", "clk_rmii_src", 0,
+			RK3399_CLKGATE_CON(5), 8, GFLAGS),
+	GATE(SCLK_MAC_TX, "clk_rmii_tx", "clk_rmii_src", 0,
+			RK3399_CLKGATE_CON(5), 9, GFLAGS),
+
+	/* spdif */
+	COMPOSITE(0, "clk_spdif_div", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(32), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(8), 13, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(99), 0,
+			RK3399_CLKGATE_CON(8), 14, GFLAGS,
+			&rk3399_spdif_fracmux),
+	GATE(SCLK_SPDIF_8CH, "clk_spdif", "clk_spdif_mux", CLK_SET_RATE_PARENT,
+			RK3399_CLKGATE_CON(8), 15, GFLAGS),
+
+	COMPOSITE(SCLK_SPDIF_REC_DPTX, "clk_spdif_rec_dptx", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(32), 15, 1, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 6, GFLAGS),
+	/* i2s */
+	COMPOSITE(0, "clk_i2s0_div", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(28), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(8), 3, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(96), 0,
+			RK3399_CLKGATE_CON(8), 4, GFLAGS,
+			&rk3399_i2s0_fracmux),
+	GATE(SCLK_I2S0_8CH, "clk_i2s0", "clk_i2s0_mux", CLK_SET_RATE_PARENT,
+			RK3399_CLKGATE_CON(8), 5, GFLAGS),
+
+	COMPOSITE(0, "clk_i2s1_div", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(29), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(8), 6, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(97), 0,
+			RK3399_CLKGATE_CON(8), 7, GFLAGS,
+			&rk3399_i2s1_fracmux),
+	GATE(SCLK_I2S1_8CH, "clk_i2s1", "clk_i2s1_mux", CLK_SET_RATE_PARENT,
+			RK3399_CLKGATE_CON(8), 8, GFLAGS),
+
+	COMPOSITE(0, "clk_i2s2_div", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(30), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(8), 9, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(98), 0,
+			RK3399_CLKGATE_CON(8), 10, GFLAGS,
+			&rk3399_i2s2_fracmux),
+	GATE(SCLK_I2S2_8CH, "clk_i2s2", "clk_i2s2_mux", CLK_SET_RATE_PARENT,
+			RK3399_CLKGATE_CON(8), 11, GFLAGS),
+
+	MUX(0, "clk_i2sout_src", mux_i2sch_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(31), 0, 2, MFLAGS),
+	COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "clk_i2sout", mux_i2sout_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(30), 8, 2, MFLAGS,
+			RK3399_CLKGATE_CON(8), 12, GFLAGS),
+
+	/* uart */
+	MUX(0, "clk_uart0_src", mux_pll_src_cpll_gpll_upll_p, 0,
+			RK3399_CLKSEL_CON(33), 12, 2, MFLAGS),
+	COMPOSITE_NOMUX(0, "clk_uart0_div", "clk_uart0_src", 0,
+			RK3399_CLKSEL_CON(33), 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 0, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div", CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(100), 0,
+			RK3399_CLKGATE_CON(9), 1, GFLAGS,
+			&rk3399_uart0_fracmux),
+
+	MUX(0, "clk_uart_src", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(33), 15, 1, MFLAGS),
+	COMPOSITE_NOMUX(0, "clk_uart1_div", "clk_uart_src", 0,
+			RK3399_CLKSEL_CON(34), 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 2, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div", CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(101), 0,
+			RK3399_CLKGATE_CON(9), 3, GFLAGS,
+			&rk3399_uart1_fracmux),
+
+	COMPOSITE_NOMUX(0, "clk_uart2_div", "clk_uart_src", 0,
+			RK3399_CLKSEL_CON(35), 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 4, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div", CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(102), 0,
+			RK3399_CLKGATE_CON(9), 5, GFLAGS,
+			&rk3399_uart2_fracmux),
+
+	COMPOSITE_NOMUX(0, "clk_uart3_div", "clk_uart_src", 0,
+			RK3399_CLKSEL_CON(36), 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 6, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_div", CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(103), 0,
+			RK3399_CLKGATE_CON(9), 7, GFLAGS,
+			&rk3399_uart3_fracmux),
+
+	COMPOSITE(0, "pclk_ddr", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(6), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(3), 4, GFLAGS),
+
+	GATE(PCLK_CENTER_MAIN_NOC, "pclk_center_main_noc", "pclk_ddr", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(18), 10, GFLAGS),
+	GATE(PCLK_DDR_MON, "pclk_ddr_mon", "pclk_ddr", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(18), 12, GFLAGS),
+	GATE(PCLK_CIC, "pclk_cic", "pclk_ddr", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(18), 15, GFLAGS),
+	GATE(PCLK_DDR_SGRF, "pclk_ddr_sgrf", "pclk_ddr", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(19), 2, GFLAGS),
+
+	GATE(SCLK_PVTM_DDR, "clk_pvtm_ddr", "xin24m", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(4), 11, GFLAGS),
+	GATE(SCLK_DFIMON0_TIMER, "clk_dfimon0_timer", "xin24m", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(3), 5, GFLAGS),
+	GATE(SCLK_DFIMON1_TIMER, "clk_dfimon1_timer", "xin24m", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(3), 6, GFLAGS),
+
+	/* cci */
+	GATE(0, "cpll_aclk_cci_src", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 0, GFLAGS),
+	GATE(0, "gpll_aclk_cci_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 1, GFLAGS),
+	GATE(0, "npll_aclk_cci_src", "npll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 2, GFLAGS),
+	GATE(0, "vpll_aclk_cci_src", "vpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 3, GFLAGS),
+
+	COMPOSITE(0, "aclk_cci_pre", mux_aclk_cci_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(5), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(2), 4, GFLAGS),
+
+	GATE(ACLK_ADB400M_PD_CORE_L, "aclk_adb400m_pd_core_l", "aclk_cci_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 0, GFLAGS),
+	GATE(ACLK_ADB400M_PD_CORE_B, "aclk_adb400m_pd_core_b", "aclk_cci_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 1, GFLAGS),
+	GATE(ACLK_CCI, "aclk_cci", "aclk_cci_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 2, GFLAGS),
+	GATE(ACLK_CCI_NOC0, "aclk_cci_noc0", "aclk_cci_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 3, GFLAGS),
+	GATE(ACLK_CCI_NOC1, "aclk_cci_noc1", "aclk_cci_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 4, GFLAGS),
+	GATE(ACLK_CCI_GRF, "aclk_cci_grf", "aclk_cci_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 7, GFLAGS),
+
+	GATE(0, "cpll_cci_trace", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 5, GFLAGS),
+	GATE(0, "gpll_cci_trace", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 6, GFLAGS),
+	COMPOSITE(SCLK_CCI_TRACE, "clk_cci_trace", mux_cci_trace_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(5), 15, 2, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(2), 7, GFLAGS),
+
+	GATE(0, "cpll_cs", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 8, GFLAGS),
+	GATE(0, "gpll_cs", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 9, GFLAGS),
+	GATE(0, "npll_cs", "npll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 10, GFLAGS),
+	COMPOSITE_NOGATE(0, "clk_cs", mux_cs_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(4), 6, 2, MFLAGS, 0, 5, DFLAGS),
+	GATE(0, "clk_dbg_cxcs", "clk_cs", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 5, GFLAGS),
+	GATE(0, "clk_dbg_noc", "clk_cs", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 6, GFLAGS),
+
+	/* vcodec */
+	COMPOSITE(0, "aclk_vcodec_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0,
+			RK3399_CLKSEL_CON(7), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 0, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_vcodec_pre", "aclk_vcodec_pre", 0,
+			RK3399_CLKSEL_CON(7), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 1, GFLAGS),
+	GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_vcodec_pre", 0,
+			RK3399_CLKGATE_CON(17), 2, GFLAGS),
+	GATE(0, "hclk_vcodec_noc", "hclk_vcodec_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(17), 3, GFLAGS),
+
+	GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vcodec_pre", 0,
+			RK3399_CLKGATE_CON(17), 0, GFLAGS),
+	GATE(0, "aclk_vcodec_noc", "aclk_vcodec_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(17), 1, GFLAGS),
+
+	/* vdu */
+	COMPOSITE(SCLK_VDU_CORE, "clk_vdu_core", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(9), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 4, GFLAGS),
+	COMPOSITE(SCLK_VDU_CA, "clk_vdu_ca", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(9), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 5, GFLAGS),
+
+	COMPOSITE(0, "aclk_vdu_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0,
+			RK3399_CLKSEL_CON(8), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 2, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_vdu_pre", "aclk_vdu_pre", 0,
+			RK3399_CLKSEL_CON(8), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 3, GFLAGS),
+	GATE(HCLK_VDU, "hclk_vdu", "hclk_vdu_pre", 0,
+			RK3399_CLKGATE_CON(17), 10, GFLAGS),
+	GATE(HCLK_VDU_NOC, "hclk_vdu_noc", "hclk_vdu_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(17), 11, GFLAGS),
+
+	GATE(ACLK_VDU, "aclk_vdu", "aclk_vdu_pre", 0,
+			RK3399_CLKGATE_CON(17), 8, GFLAGS),
+	GATE(ACLK_VDU_NOC, "aclk_vdu_noc", "aclk_vdu_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(17), 9, GFLAGS),
+
+	/* iep */
+	COMPOSITE(0, "aclk_iep_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0,
+			RK3399_CLKSEL_CON(10), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 6, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_iep_pre", "aclk_iep_pre", 0,
+			RK3399_CLKSEL_CON(10), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 7, GFLAGS),
+	GATE(HCLK_IEP, "hclk_iep", "hclk_iep_pre", 0,
+			RK3399_CLKGATE_CON(16), 2, GFLAGS),
+	GATE(HCLK_IEP_NOC, "hclk_iep_noc", "hclk_iep_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(16), 3, GFLAGS),
+
+	GATE(ACLK_IEP, "aclk_iep", "aclk_iep_pre", 0,
+			RK3399_CLKGATE_CON(16), 0, GFLAGS),
+	GATE(ACLK_IEP_NOC, "aclk_iep_noc", "aclk_iep_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(16), 1, GFLAGS),
+
+	/* rga */
+	COMPOSITE(SCLK_RGA_CORE, "clk_rga_core", mux_pll_src_cpll_gpll_npll_ppll_p, 0,
+			RK3399_CLKSEL_CON(12), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 10, GFLAGS),
+
+	COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0,
+			RK3399_CLKSEL_CON(11), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 8, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_rga_pre", "aclk_rga_pre", 0,
+			RK3399_CLKSEL_CON(11), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 9, GFLAGS),
+	GATE(HCLK_RGA, "hclk_rga", "hclk_rga_pre", 0,
+			RK3399_CLKGATE_CON(16), 10, GFLAGS),
+	GATE(HCLK_RGA_NOC, "hclk_rga_noc", "hclk_rga_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(16), 11, GFLAGS),
+
+	GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0,
+			RK3399_CLKGATE_CON(16), 8, GFLAGS),
+	GATE(ACLK_RGA_NOC, "aclk_rga_noc", "aclk_rga_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(16), 9, GFLAGS),
+
+	/* center */
+	COMPOSITE(0, "aclk_center", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(12), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(3), 7, GFLAGS),
+	GATE(ACLK_CENTER_MAIN_NOC, "aclk_center_main_noc", "aclk_center", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(19), 0, GFLAGS),
+	GATE(ACLK_CENTER_PERI_NOC, "aclk_center_peri_noc", "aclk_center", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(19), 1, GFLAGS),
+
+	/* gpu */
+	COMPOSITE(0, "aclk_gpu_pre", mux_pll_src_ppll_cpll_gpll_npll_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(13), 5, 3, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 0, GFLAGS),
+	GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", 0,
+			RK3399_CLKGATE_CON(30), 8, GFLAGS),
+	GATE(ACLK_PERF_GPU, "aclk_perf_gpu", "aclk_gpu_pre", 0,
+			RK3399_CLKGATE_CON(30), 10, GFLAGS),
+	GATE(ACLK_GPU_GRF, "aclk_gpu_grf", "aclk_gpu_pre", 0,
+			RK3399_CLKGATE_CON(30), 11, GFLAGS),
+	GATE(SCLK_PVTM_GPU, "aclk_pvtm_gpu", "xin24m", 0,
+			RK3399_CLKGATE_CON(13), 1, GFLAGS),
+
+	/* perihp */
+	GATE(0, "cpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(5), 0, GFLAGS),
+	GATE(0, "gpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(5), 1, GFLAGS),
+	COMPOSITE(ACLK_PERIHP, "aclk_perihp", mux_aclk_perihp_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(14), 7, 1, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(5), 2, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_PERIHP, "hclk_perihp", "aclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(14), 8, 2, DFLAGS,
+			RK3399_CLKGATE_CON(5), 3, GFLAGS),
+	COMPOSITE_NOMUX(PCLK_PERIHP, "pclk_perihp", "aclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(14), 12, 2, DFLAGS,
+			RK3399_CLKGATE_CON(5), 4, GFLAGS),
+
+	GATE(ACLK_PERF_PCIE, "aclk_perf_pcie", "aclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(20), 2, GFLAGS),
+	GATE(ACLK_PCIE, "aclk_pcie", "aclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(20), 10, GFLAGS),
+	GATE(0, "aclk_perihp_noc", "aclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(20), 12, GFLAGS),
+
+	GATE(HCLK_HOST0, "hclk_host0", "hclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 5, GFLAGS),
+	GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 6, GFLAGS),
+	GATE(HCLK_HOST1, "hclk_host1", "hclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 7, GFLAGS),
+	GATE(HCLK_HOST1_ARB, "hclk_host1_arb", "hclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 8, GFLAGS),
+	GATE(HCLK_HSIC, "hclk_hsic", "hclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 9, GFLAGS),
+	GATE(0, "hclk_perihp_noc", "hclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(20), 13, GFLAGS),
+	GATE(0, "hclk_ahb1tom", "hclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(20), 15, GFLAGS),
+
+	GATE(PCLK_PERIHP_GRF, "pclk_perihp_grf", "pclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(20), 4, GFLAGS),
+	GATE(PCLK_PCIE, "pclk_pcie", "pclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 11, GFLAGS),
+	GATE(0, "pclk_perihp_noc", "pclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(20), 14, GFLAGS),
+	GATE(PCLK_HSICPHY, "pclk_hsicphy", "pclk_perihp", 0,
+			RK3399_CLKGATE_CON(31), 8, GFLAGS),
+
+	/* sdio & sdmmc */
+	COMPOSITE(0, "hclk_sd", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(13), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 13, GFLAGS),
+	GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_sd", 0,
+			RK3399_CLKGATE_CON(33), 8, GFLAGS),
+	GATE(0, "hclk_sdmmc_noc", "hclk_sd", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(33), 9, GFLAGS),
+
+	COMPOSITE(SCLK_SDIO, "clk_sdio", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p, 0,
+			RK3399_CLKSEL_CON(15), 8, 3, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(6), 0, GFLAGS),
+
+	COMPOSITE(SCLK_SDMMC, "clk_sdmmc", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p, 0,
+			RK3399_CLKSEL_CON(16), 8, 3, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(6), 1, GFLAGS),
+
+	MMC(SCLK_SDMMC_DRV,     "emmc_drv",    "clk_sdmmc", RK3399_SDMMC_CON0, 1),
+	MMC(SCLK_SDMMC_SAMPLE,  "emmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1),
+
+	MMC(SCLK_SDIO_DRV,      "sdio_drv",    "clk_sdio",  RK3399_SDIO_CON0,  1),
+	MMC(SCLK_SDIO_SAMPLE,   "sdio_sample", "clk_sdio",  RK3399_SDIO_CON1,  1),
+
+	/* pcie */
+	COMPOSITE(SCLK_PCIE_PM, "clk_pcie_pm", mux_pll_src_cpll_gpll_npll_24m_p, 0,
+			RK3399_CLKSEL_CON(17), 8, 3, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(6), 2, GFLAGS),
+
+	COMPOSITE_NOMUX(SCLK_PCIEPHY_REF100M, "clk_pciephy_ref100m", "npll", 0,
+			RK3399_CLKSEL_CON(18), 11, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 6, GFLAGS),
+	MUX(SCLK_PCIEPHY_REF, "clk_pciephy_ref", mux_pll_src_24m_pciephy_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(18), 10, 1, MFLAGS),
+
+	COMPOSITE(0, "clk_pcie_core_cru", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(18), 8, 2, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(6), 3, GFLAGS),
+	MUX(SCLK_PCIE_CORE, "clk_pcie_core", mux_pciecore_cru_phy_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(18), 7, 1, MFLAGS),
+
+	/* emmc */
+	COMPOSITE(SCLK_EMMC, "clk_emmc", mux_pll_src_cpll_gpll_npll_upll_24m_p, 0,
+			RK3399_CLKSEL_CON(22), 8, 3, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(6), 14, GFLAGS),
+
+	GATE(0, "cpll_aclk_emmc_src", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(6), 12, GFLAGS),
+	GATE(0, "gpll_aclk_emmc_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(6), 13, GFLAGS),
+	COMPOSITE_NOGATE(ACLK_EMMC, "aclk_emmc", mux_aclk_emmc_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(21), 7, 1, MFLAGS, 0, 5, DFLAGS),
+	GATE(ACLK_EMMC_CORE, "aclk_emmccore", "aclk_emmc", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(32), 8, GFLAGS),
+	GATE(ACLK_EMMC_NOC, "aclk_emmc_noc", "aclk_emmc", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(32), 9, GFLAGS),
+	GATE(ACLK_EMMC_GRF, "aclk_emmcgrf", "aclk_emmc", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(32), 10, GFLAGS),
+
+	/* perilp0 */
+	GATE(0, "cpll_aclk_perilp0_src", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(7), 1, GFLAGS),
+	GATE(0, "gpll_aclk_perilp0_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(7), 0, GFLAGS),
+	COMPOSITE(ACLK_PERILP0, "aclk_perilp0", mux_aclk_perilp0_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(23), 7, 1, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(7), 2, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_PERILP0, "hclk_perilp0", "aclk_perilp0", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(23), 8, 2, DFLAGS,
+			RK3399_CLKGATE_CON(7), 3, GFLAGS),
+	COMPOSITE_NOMUX(PCLK_PERILP0, "pclk_perilp0", "aclk_perilp0", 0,
+			RK3399_CLKSEL_CON(23), 12, 3, DFLAGS,
+			RK3399_CLKGATE_CON(7), 4, GFLAGS),
+
+	/* aclk_perilp0 gates */
+	GATE(ACLK_INTMEM, "aclk_intmem", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 0, GFLAGS),
+	GATE(ACLK_TZMA, "aclk_tzma", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 1, GFLAGS),
+	GATE(SCLK_INTMEM0, "clk_intmem0", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 2, GFLAGS),
+	GATE(SCLK_INTMEM1, "clk_intmem1", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 3, GFLAGS),
+	GATE(SCLK_INTMEM2, "clk_intmem2", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 4, GFLAGS),
+	GATE(SCLK_INTMEM3, "clk_intmem3", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 5, GFLAGS),
+	GATE(SCLK_INTMEM4, "clk_intmem4", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 6, GFLAGS),
+	GATE(SCLK_INTMEM5, "clk_intmem5", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 7, GFLAGS),
+	GATE(ACLK_DCF, "aclk_dcf", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 8, GFLAGS),
+	GATE(ACLK_DMAC0_PERILP, "aclk_dmac0_perilp", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 5, GFLAGS),
+	GATE(ACLK_DMAC1_PERILP, "aclk_dmac1_perilp", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 6, GFLAGS),
+	GATE(ACLK_PERILP0_NOC, "aclk_perilp0_noc", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 7, GFLAGS),
+
+	/* hclk_perilp0 gates */
+	GATE(HCLK_ROM, "hclk_rom", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 4, GFLAGS),
+	GATE(HCLK_M_CRYPTO0, "hclk_m_crypto0", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 5, GFLAGS),
+	GATE(HCLK_S_CRYPTO0, "hclk_s_crypto0", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 6, GFLAGS),
+	GATE(HCLK_M_CRYPTO1, "hclk_m_crypto1", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 14, GFLAGS),
+	GATE(HCLK_S_CRYPTO1, "hclk_s_crypto1", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 15, GFLAGS),
+	GATE(HCLK_PERILP0_NOC, "hclk_perilp0_noc", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 8, GFLAGS),
+
+	/* pclk_perilp0 gates */
+	GATE(PCLK_DCF, "pclk_dcf", "pclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 9, GFLAGS),
+
+	/* crypto */
+	COMPOSITE(SCLK_CRYPTO0, "clk_crypto0", mux_pll_src_cpll_gpll_ppll_p, 0,
+			RK3399_CLKSEL_CON(24), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(7), 7, GFLAGS),
+
+	COMPOSITE(SCLK_CRYPTO1, "clk_crypto1", mux_pll_src_cpll_gpll_ppll_p, 0,
+			RK3399_CLKSEL_CON(26), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(7), 8, GFLAGS),
+
+	/* cm0s_perilp */
+	GATE(0, "cpll_fclk_cm0s_src", "cpll", 0,
+			RK3399_CLKGATE_CON(7), 6, GFLAGS),
+	GATE(0, "gpll_fclk_cm0s_src", "gpll", 0,
+			RK3399_CLKGATE_CON(7), 5, GFLAGS),
+	COMPOSITE(FCLK_CM0S, "fclk_cm0s", mux_fclk_cm0s_p, 0,
+			RK3399_CLKSEL_CON(24), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(7), 9, GFLAGS),
+
+	/* fclk_cm0s gates */
+	GATE(SCLK_M0_PERILP, "sclk_m0_perilp", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 8, GFLAGS),
+	GATE(HCLK_M0_PERILP, "hclk_m0_perilp", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 9, GFLAGS),
+	GATE(DCLK_M0_PERILP, "dclk_m0_perilp", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 10, GFLAGS),
+	GATE(SCLK_M0_PERILP_DEC, "clk_m0_perilp_dec", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 11, GFLAGS),
+	GATE(HCLK_M0_PERILP_NOC, "hclk_m0_perilp_noc", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 11, GFLAGS),
+
+	/* perilp1 */
+	GATE(0, "cpll_hclk_perilp1_src", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(8), 1, GFLAGS),
+	GATE(0, "gpll_hclk_perilp1_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(8), 0, GFLAGS),
+	COMPOSITE_NOGATE(HCLK_PERILP1, "hclk_perilp1", mux_hclk_perilp1_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(25), 7, 1, MFLAGS, 0, 5, DFLAGS),
+	COMPOSITE_NOMUX(PCLK_PERILP1, "pclk_perilp1", "hclk_perilp1", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(25), 8, 3, DFLAGS,
+			RK3399_CLKGATE_CON(8), 2, GFLAGS),
+
+	/* hclk_perilp1 gates */
+	GATE(0, "hclk_perilp1_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 9, GFLAGS),
+	GATE(0, "hclk_sdio_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 12, GFLAGS),
+	GATE(HCLK_I2S0_8CH, "hclk_i2s0", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 0, GFLAGS),
+	GATE(HCLK_I2S1_8CH, "hclk_i2s1", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 1, GFLAGS),
+	GATE(HCLK_I2S2_8CH, "hclk_i2s2", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 2, GFLAGS),
+	GATE(HCLK_SPDIF, "hclk_spdif", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 3, GFLAGS),
+	GATE(HCLK_SDIO, "hclk_sdio", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 4, GFLAGS),
+	GATE(PCLK_SPI5, "pclk_spi5", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 5, GFLAGS),
+	GATE(0, "hclk_sdioaudio_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 6, GFLAGS),
+
+	/* pclk_perilp1 gates */
+	GATE(PCLK_UART0, "pclk_uart0", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 0, GFLAGS),
+	GATE(PCLK_UART1, "pclk_uart1", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 1, GFLAGS),
+	GATE(PCLK_UART2, "pclk_uart2", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 2, GFLAGS),
+	GATE(PCLK_UART3, "pclk_uart3", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 3, GFLAGS),
+	GATE(PCLK_I2C7, "pclk_rki2c7", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 5, GFLAGS),
+	GATE(PCLK_I2C1, "pclk_rki2c1", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 6, GFLAGS),
+	GATE(PCLK_I2C5, "pclk_rki2c5", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 7, GFLAGS),
+	GATE(PCLK_I2C6, "pclk_rki2c6", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 8, GFLAGS),
+	GATE(PCLK_I2C2, "pclk_rki2c2", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 9, GFLAGS),
+	GATE(PCLK_I2C3, "pclk_rki2c3", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 10, GFLAGS),
+	GATE(PCLK_MAILBOX0, "pclk_mailbox0", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 11, GFLAGS),
+	GATE(PCLK_SARADC, "pclk_saradc", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 12, GFLAGS),
+	GATE(PCLK_TSADC, "pclk_tsadc", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 13, GFLAGS),
+	GATE(PCLK_EFUSE1024NS, "pclk_efuse1024ns", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 14, GFLAGS),
+	GATE(PCLK_EFUSE1024S, "pclk_efuse1024s", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 15, GFLAGS),
+	GATE(PCLK_SPI0, "pclk_spi0", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 10, GFLAGS),
+	GATE(PCLK_SPI1, "pclk_spi1", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 11, GFLAGS),
+	GATE(PCLK_SPI2, "pclk_spi2", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 12, GFLAGS),
+	GATE(PCLK_SPI4, "pclk_spi4", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 13, GFLAGS),
+	GATE(PCLK_PERIHP_GRF, "pclk_perilp_sgrf", "pclk_perilp1", 0, RK3399_CLKGATE_CON(24), 13, GFLAGS),
+	GATE(0, "pclk_perilp1_noc", "pclk_perilp1", 0, RK3399_CLKGATE_CON(25), 10, GFLAGS),
+
+	/* saradc */
+	COMPOSITE_NOMUX(SCLK_SARADC, "clk_saradc", "xin24m", 0,
+			RK3399_CLKSEL_CON(26), 8, 8, DFLAGS,
+			RK3399_CLKGATE_CON(9), 11, GFLAGS),
+
+	/* tsadc */
+	COMPOSITE(SCLK_TSADC, "clk_tsadc", mux_pll_p, 0,
+			RK3399_CLKSEL_CON(27), 15, 1, MFLAGS, 0, 10, DFLAGS,
+			RK3399_CLKGATE_CON(9), 10, GFLAGS),
+
+	/* cif_testout */
+	MUX(0, "clk_testout1_pll_src", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(38), 6, 2, MFLAGS),
+	COMPOSITE(0, "clk_testout1", mux_clk_testout1_p, 0,
+			RK3399_CLKSEL_CON(38), 5, 1, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 14, GFLAGS),
+
+	MUX(0, "clk_testout2_pll_src", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(38), 14, 2, MFLAGS),
+	COMPOSITE(0, "clk_testout2", mux_clk_testout2_p, 0,
+			RK3399_CLKSEL_CON(38), 13, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 15, GFLAGS),
+
+	/* vio */
+	COMPOSITE(ACLK_VIO, "aclk_vio", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(42), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 10, GFLAGS),
+	COMPOSITE_NOMUX(PCLK_VIO, "pclk_vio", "aclk_vio", 0,
+			RK3399_CLKSEL_CON(43), 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 1, GFLAGS),
+
+	GATE(ACLK_VIO_NOC, "aclk_vio_noc", "aclk_vio", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(29), 0, GFLAGS),
+
+	GATE(PCLK_MIPI_DSI0, "pclk_mipi_dsi0", "pclk_vio", 0,
+			RK3399_CLKGATE_CON(29), 1, GFLAGS),
+	GATE(PCLK_MIPI_DSI1, "pclk_mipi_dsi1", "pclk_vio", 0,
+			RK3399_CLKGATE_CON(29), 2, GFLAGS),
+	GATE(PCLK_VIO_GRF, "pclk_vio_grf", "pclk_vio", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(29), 12, GFLAGS),
+
+	/* hdcp */
+	COMPOSITE(ACLK_HDCP, "aclk_hdcp", mux_pll_src_cpll_gpll_ppll_p, 0,
+			RK3399_CLKSEL_CON(42), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 12, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_HDCP, "hclk_hdcp", "aclk_hdcp", 0,
+			RK3399_CLKSEL_CON(43), 5, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 3, GFLAGS),
+	COMPOSITE_NOMUX(PCLK_HDCP, "pclk_hdcp", "aclk_hdcp", 0,
+			RK3399_CLKSEL_CON(43), 10, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 10, GFLAGS),
+
+	GATE(ACLK_HDCP_NOC, "aclk_hdcp_noc", "aclk_hdcp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(29), 4, GFLAGS),
+	GATE(ACLK_HDCP22, "aclk_hdcp22", "aclk_hdcp", 0,
+			RK3399_CLKGATE_CON(29), 10, GFLAGS),
+
+	GATE(HCLK_HDCP_NOC, "hclk_hdcp_noc", "hclk_hdcp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(29), 5, GFLAGS),
+	GATE(HCLK_HDCP22, "hclk_hdcp22", "hclk_hdcp", 0,
+			RK3399_CLKGATE_CON(29), 9, GFLAGS),
+
+	GATE(PCLK_HDCP_NOC, "pclk_hdcp_noc", "pclk_hdcp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(29), 3, GFLAGS),
+	GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "pclk_hdcp", 0,
+			RK3399_CLKGATE_CON(29), 6, GFLAGS),
+	GATE(PCLK_DP_CTRL, "pclk_dp_ctrl", "pclk_hdcp", 0,
+			RK3399_CLKGATE_CON(29), 7, GFLAGS),
+	GATE(PCLK_HDCP22, "pclk_hdcp22", "pclk_hdcp", 0,
+			RK3399_CLKGATE_CON(29), 8, GFLAGS),
+	GATE(PCLK_GASKET, "pclk_gasket", "pclk_hdcp", 0,
+			RK3399_CLKGATE_CON(29), 11, GFLAGS),
+
+	/* edp */
+	COMPOSITE(SCLK_DP_CORE, "clk_dp_core", mux_pll_src_npll_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(46), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 8, GFLAGS),
+
+	COMPOSITE(PCLK_EDP, "pclk_edp", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(44), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 11, GFLAGS),
+	GATE(PCLK_EDP_NOC, "pclk_edp_noc", "pclk_edp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(32), 12, GFLAGS),
+	GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "pclk_edp", 0,
+			RK3399_CLKGATE_CON(32), 13, GFLAGS),
+
+	/* hdmi */
+	GATE(SCLK_HDMI_SFR, "clk_hdmi_sfr", "xin24m", 0,
+			RK3399_CLKGATE_CON(11), 6, GFLAGS),
+
+	COMPOSITE(SCLK_HDMI_CEC, "clk_hdmi_cec", mux_pll_p, 0,
+			RK3399_CLKSEL_CON(45), 15, 1, MFLAGS, 0, 10, DFLAGS,
+			RK3399_CLKGATE_CON(11), 7, GFLAGS),
+
+	/* vop0 */
+	COMPOSITE(ACLK_VOP0_PRE, "aclk_vop0_pre", mux_pll_src_vpll_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(47), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 8, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_vop0_pre", "aclk_vop0_pre", 0,
+			RK3399_CLKSEL_CON(47), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 9, GFLAGS),
+
+	GATE(ACLK_VOP0, "aclk_vop0", "aclk_vop0_pre", 0,
+			RK3399_CLKGATE_CON(28), 3, GFLAGS),
+	GATE(ACLK_VOP0_NOC, "aclk_vop0_noc", "aclk_vop0_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(28), 1, GFLAGS),
+
+	GATE(HCLK_VOP0, "hclk_vop0", "hclk_vop0_pre", 0,
+			RK3399_CLKGATE_CON(28), 2, GFLAGS),
+	GATE(HCLK_VOP0_NOC, "hclk_vop0_noc", "hclk_vop0_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(28), 0, GFLAGS),
+
+	COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(49), 8, 2, MFLAGS, 0, 8, DFLAGS,
+			RK3399_CLKGATE_CON(10), 12, GFLAGS),
+
+	COMPOSITE_FRACMUX_NOGATE(0, "dclk_vop0_frac", "dclk_vop0_div", CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(106), 0,
+			&rk3399_dclk_vop0_fracmux),
+
+	COMPOSITE(SCLK_VOP0_PWM, "clk_vop0_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, 0,
+			RK3399_CLKSEL_CON(51), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 14, GFLAGS),
+
+	/* vop1 */
+	COMPOSITE(ACLK_VOP1_PRE, "aclk_vop1_pre", mux_pll_src_vpll_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(48), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 10, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_vop1_pre", "aclk_vop1_pre", 0,
+			RK3399_CLKSEL_CON(48), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 11, GFLAGS),
+
+	GATE(ACLK_VOP1, "aclk_vop1", "aclk_vop1_pre", 0,
+			RK3399_CLKGATE_CON(28), 7, GFLAGS),
+	GATE(ACLK_VOP1_NOC, "aclk_vop1_noc", "aclk_vop1_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(28), 5, GFLAGS),
+
+	GATE(HCLK_VOP1, "hclk_vop1", "hclk_vop1_pre", 0,
+			RK3399_CLKGATE_CON(28), 6, GFLAGS),
+	GATE(HCLK_VOP1_NOC, "hclk_vop1_noc", "hclk_vop1_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(28), 4, GFLAGS),
+
+	COMPOSITE(DCLK_VOP1_DIV, "dclk_vop1_div", mux_pll_src_vpll_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(50), 8, 2, MFLAGS, 0, 8, DFLAGS,
+			RK3399_CLKGATE_CON(10), 13, GFLAGS),
+
+	COMPOSITE_FRACMUX_NOGATE(0, "dclk_vop1_frac", "dclk_vop1_div", CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(107), 0,
+			&rk3399_dclk_vop1_fracmux),
+
+	COMPOSITE(SCLK_VOP1_PWM, "clk_vop1_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(52), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 15, GFLAGS),
+
+	/* isp */
+	COMPOSITE(ACLK_ISP0, "aclk_isp0", mux_pll_src_cpll_gpll_ppll_p, 0,
+			RK3399_CLKSEL_CON(53), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 8, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_ISP0, "hclk_isp0", "aclk_isp0", 0,
+			RK3399_CLKSEL_CON(53), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 9, GFLAGS),
+
+	GATE(ACLK_ISP0_NOC, "aclk_isp0_noc", "aclk_isp0", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(27), 1, GFLAGS),
+	GATE(ACLK_ISP0_WRAPPER, "aclk_isp0_wrapper", "aclk_isp0", 0,
+			RK3399_CLKGATE_CON(27), 5, GFLAGS),
+	GATE(HCLK_ISP1_WRAPPER, "hclk_isp1_wrapper", "aclk_isp0", 0,
+			RK3399_CLKGATE_CON(27), 7, GFLAGS),
+
+	GATE(HCLK_ISP0_NOC, "hclk_isp0_noc", "hclk_isp0", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(27), 0, GFLAGS),
+	GATE(HCLK_ISP0_WRAPPER, "hclk_isp0_wrapper", "hclk_isp0", 0,
+			RK3399_CLKGATE_CON(27), 4, GFLAGS),
+
+	COMPOSITE(SCLK_ISP0, "clk_isp0", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(55), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 4, GFLAGS),
+
+	COMPOSITE(ACLK_ISP1, "aclk_isp1", mux_pll_src_cpll_gpll_ppll_p, 0,
+			RK3399_CLKSEL_CON(54), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 10, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_ISP1, "hclk_isp1", "aclk_isp1", 0,
+			RK3399_CLKSEL_CON(54), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 11, GFLAGS),
+
+	GATE(ACLK_ISP1_NOC, "aclk_isp1_noc", "aclk_isp1", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(27), 3, GFLAGS),
+
+	GATE(HCLK_ISP1_NOC, "hclk_isp1_noc", "hclk_isp1", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(27), 2, GFLAGS),
+	GATE(ACLK_ISP1_WRAPPER, "aclk_isp1_wrapper", "hclk_isp1", 0,
+			RK3399_CLKGATE_CON(27), 8, GFLAGS),
+
+	COMPOSITE(SCLK_ISP1, "clk_isp1", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(55), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 5, GFLAGS),
+
+	/*
+	 * We use pclkin_cifinv by default GRF_SOC_CON20[9] (GSC20_9) setting in system,
+	 * so we ignore the mux and make clocks nodes as following,
+	 *
+	 * pclkin_cifinv --|-------\
+	 *                 |GSC20_9|-- pclkin_cifmux -- |G27_6| -- pclkin_isp1_wrapper
+	 * pclkin_cif    --|-------/
+	 */
+	GATE(PCLK_ISP1_WRAPPER, "pclkin_isp1_wrapper", "pclkin_cif", 0,
+			RK3399_CLKGATE_CON(27), 6, GFLAGS),
+
+	/* cif */
+	COMPOSITE_NODIV(0, "clk_cifout_src", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(56), 6, 2, MFLAGS,
+			RK3399_CLKGATE_CON(10), 7, GFLAGS),
+
+	COMPOSITE_NOGATE(SCLK_CIF_OUT, "clk_cifout", mux_clk_cif_p, 0,
+			 RK3399_CLKSEL_CON(56), 5, 1, MFLAGS, 0, 5, DFLAGS),
+
+	/* gic */
+	COMPOSITE(ACLK_GIC_PRE, "aclk_gic_pre", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(56), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 12, GFLAGS),
+
+	GATE(ACLK_GIC, "aclk_gic", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 0, GFLAGS),
+	GATE(ACLK_GIC_NOC, "aclk_gic_noc", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 1, GFLAGS),
+	GATE(ACLK_GIC_ADB400_CORE_L_2_GIC, "aclk_gic_adb400_core_l_2_gic", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 2, GFLAGS),
+	GATE(ACLK_GIC_ADB400_CORE_B_2_GIC, "aclk_gic_adb400_core_b_2_gic", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 3, GFLAGS),
+	GATE(ACLK_GIC_ADB400_GIC_2_CORE_L, "aclk_gic_adb400_gic_2_core_l", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 4, GFLAGS),
+	GATE(ACLK_GIC_ADB400_GIC_2_CORE_B, "aclk_gic_adb400_gic_2_core_b", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 5, GFLAGS),
+
+	/* alive */
+	/* pclk_alive_gpll_src is controlled by PMUGRF_SOC_CON0[6] */
+	DIV(PCLK_ALIVE, "pclk_alive", "gpll", 0,
+			RK3399_CLKSEL_CON(57), 0, 5, DFLAGS),
+
+	GATE(PCLK_USBPHY_MUX_G, "pclk_usbphy_mux_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 4, GFLAGS),
+	GATE(PCLK_UPHY0_TCPHY_G, "pclk_uphy0_tcphy_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 5, GFLAGS),
+	GATE(PCLK_UPHY0_TCPD_G, "pclk_uphy0_tcpd_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 6, GFLAGS),
+	GATE(PCLK_UPHY1_TCPHY_G, "pclk_uphy1_tcphy_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 8, GFLAGS),
+	GATE(PCLK_UPHY1_TCPD_G, "pclk_uphy1_tcpd_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 9, GFLAGS),
+
+	GATE(PCLK_GRF, "pclk_grf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 1, GFLAGS),
+	GATE(PCLK_INTR_ARB, "pclk_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 2, GFLAGS),
+	GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 3, GFLAGS),
+	GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 4, GFLAGS),
+	GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 5, GFLAGS),
+	GATE(PCLK_TIMER0, "pclk_timer0", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 6, GFLAGS),
+	GATE(PCLK_TIMER1, "pclk_timer1", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 7, GFLAGS),
+	GATE(PCLK_PMU_INTR_ARB, "pclk_pmu_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 9, GFLAGS),
+	GATE(PCLK_SGRF, "pclk_sgrf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 10, GFLAGS),
+
+	GATE(SCLK_MIPIDPHY_REF, "clk_mipidphy_ref", "xin24m", 0, RK3399_CLKGATE_CON(11), 14, GFLAGS),
+	GATE(SCLK_DPHY_PLL, "clk_dphy_pll", "clk_mipidphy_ref", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 0, GFLAGS),
+
+	GATE(SCLK_MIPIDPHY_CFG, "clk_mipidphy_cfg", "xin24m", 0, RK3399_CLKGATE_CON(11), 15, GFLAGS),
+	GATE(SCLK_DPHY_TX0_CFG, "clk_dphy_tx0_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 1, GFLAGS),
+	GATE(SCLK_DPHY_TX1RX1_CFG, "clk_dphy_tx1rx1_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 2, GFLAGS),
+	GATE(SCLK_DPHY_RX0_CFG, "clk_dphy_rx0_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 3, GFLAGS),
+
+	/* testout */
+	MUX(0, "clk_test_pre", mux_pll_src_cpll_gpll_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(58), 7, 1, MFLAGS),
+	COMPOSITE_FRAC(0, "clk_test_frac", "clk_test_pre", CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(105), 0,
+			RK3399_CLKGATE_CON(13), 9, GFLAGS),
+
+	DIV(0, "clk_test_24m", "xin24m", 0,
+			RK3399_CLKSEL_CON(57), 6, 10, DFLAGS),
+
+	/* spi */
+	COMPOSITE(SCLK_SPI0, "clk_spi0", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(59), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 12, GFLAGS),
+
+	COMPOSITE(SCLK_SPI1, "clk_spi1", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(59), 15, 1, MFLAGS, 8, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 13, GFLAGS),
+
+	COMPOSITE(SCLK_SPI2, "clk_spi2", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(60), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 14, GFLAGS),
+
+	COMPOSITE(SCLK_SPI4, "clk_spi4", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(60), 15, 1, MFLAGS, 8, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 15, GFLAGS),
+
+	COMPOSITE(SCLK_SPI5, "clk_spi5", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(58), 15, 1, MFLAGS, 8, 7, DFLAGS,
+			RK3399_CLKGATE_CON(13), 13, GFLAGS),
+
+	/* i2c */
+	COMPOSITE(SCLK_I2C1, "clk_i2c1", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(61), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(10), 0, GFLAGS),
+
+	COMPOSITE(SCLK_I2C2, "clk_i2c2", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(62), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(10), 2, GFLAGS),
+
+	COMPOSITE(SCLK_I2C3, "clk_i2c3", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(63), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(10), 4, GFLAGS),
+
+	COMPOSITE(SCLK_I2C5, "clk_i2c5", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(61), 15, 1, MFLAGS, 8, 7, DFLAGS,
+			RK3399_CLKGATE_CON(10), 1, GFLAGS),
+
+	COMPOSITE(SCLK_I2C6, "clk_i2c6", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(62), 15, 1, MFLAGS, 8, 7, DFLAGS,
+			RK3399_CLKGATE_CON(10), 3, GFLAGS),
+
+	COMPOSITE(SCLK_I2C7, "clk_i2c7", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(63), 15, 1, MFLAGS, 8, 7, DFLAGS,
+			RK3399_CLKGATE_CON(10), 5, GFLAGS),
+
+	/* timer */
+	GATE(SCLK_TIMER00, "clk_timer00", "xin24m", 0, RK3399_CLKGATE_CON(26), 0, GFLAGS),
+	GATE(SCLK_TIMER01, "clk_timer01", "xin24m", 0, RK3399_CLKGATE_CON(26), 1, GFLAGS),
+	GATE(SCLK_TIMER02, "clk_timer02", "xin24m", 0, RK3399_CLKGATE_CON(26), 2, GFLAGS),
+	GATE(SCLK_TIMER03, "clk_timer03", "xin24m", 0, RK3399_CLKGATE_CON(26), 3, GFLAGS),
+	GATE(SCLK_TIMER04, "clk_timer04", "xin24m", 0, RK3399_CLKGATE_CON(26), 4, GFLAGS),
+	GATE(SCLK_TIMER05, "clk_timer05", "xin24m", 0, RK3399_CLKGATE_CON(26), 5, GFLAGS),
+	GATE(SCLK_TIMER06, "clk_timer06", "xin24m", 0, RK3399_CLKGATE_CON(26), 6, GFLAGS),
+	GATE(SCLK_TIMER07, "clk_timer07", "xin24m", 0, RK3399_CLKGATE_CON(26), 7, GFLAGS),
+	GATE(SCLK_TIMER08, "clk_timer08", "xin24m", 0, RK3399_CLKGATE_CON(26), 8, GFLAGS),
+	GATE(SCLK_TIMER09, "clk_timer09", "xin24m", 0, RK3399_CLKGATE_CON(26), 9, GFLAGS),
+	GATE(SCLK_TIMER10, "clk_timer10", "xin24m", 0, RK3399_CLKGATE_CON(26), 10, GFLAGS),
+	GATE(SCLK_TIMER11, "clk_timer11", "xin24m", 0, RK3399_CLKGATE_CON(26), 11, GFLAGS),
+
+	/* clk_test */
+	/* clk_test_pre is controlled by CRU_MISC_CON[3] */
+	COMPOSITE_NOMUX(0, "clk_test", "clk_test_pre", CLK_IGNORE_UNUSED,
+			RK3368_CLKSEL_CON(58), 0, 5, DFLAGS,
+			RK3368_CLKGATE_CON(13), 11, GFLAGS),
+};
+
+static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = {
+	/*
+	 * PMU CRU Clock-Architecture
+	 */
+
+	GATE(0, "fclk_cm0s_pmu_ppll_src", "ppll", 0,
+			RK3399_PMU_CLKGATE_CON(0), 1, GFLAGS),
+
+	COMPOSITE_NOGATE(FCLK_CM0S_SRC_PMU, "fclk_cm0s_src_pmu", mux_fclk_cm0s_pmu_ppll_p, 0,
+			RK3399_PMU_CLKSEL_CON(0), 15, 1, MFLAGS, 8, 5, DFLAGS),
+
+	COMPOSITE(SCLK_SPI3_PMU, "clk_spi3_pmu", mux_24m_ppll_p, 0,
+			RK3399_PMU_CLKSEL_CON(1), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_PMU_CLKGATE_CON(0), 2, GFLAGS),
+
+	COMPOSITE(0, "clk_wifi_div", mux_ppll_24m_p, CLK_IGNORE_UNUSED,
+			RK3399_PMU_CLKSEL_CON(1), 13, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_PMU_CLKGATE_CON(0), 8, GFLAGS),
+
+	COMPOSITE_FRACMUX_NOGATE(0, "clk_wifi_frac", "clk_wifi_div", CLK_SET_RATE_PARENT,
+			RK3399_PMU_CLKSEL_CON(7), 0,
+			&rk3399_pmuclk_wifi_fracmux),
+
+	MUX(0, "clk_timer_src_pmu", mux_pll_p, CLK_IGNORE_UNUSED,
+			RK3399_PMU_CLKSEL_CON(1), 15, 1, MFLAGS),
+
+	COMPOSITE_NOMUX(SCLK_I2C0_PMU, "clk_i2c0_pmu", "ppll", 0,
+			RK3399_PMU_CLKSEL_CON(2), 0, 7, DFLAGS,
+			RK3399_PMU_CLKGATE_CON(0), 9, GFLAGS),
+
+	COMPOSITE_NOMUX(SCLK_I2C4_PMU, "clk_i2c4_pmu", "ppll", 0,
+			RK3399_PMU_CLKSEL_CON(3), 0, 7, DFLAGS,
+			RK3399_PMU_CLKGATE_CON(0), 10, GFLAGS),
+
+	COMPOSITE_NOMUX(SCLK_I2C8_PMU, "clk_i2c8_pmu", "ppll", 0,
+			RK3399_PMU_CLKSEL_CON(2), 8, 7, DFLAGS,
+			RK3399_PMU_CLKGATE_CON(0), 11, GFLAGS),
+
+	DIV(0, "clk_32k_suspend_pmu", "xin24m", CLK_IGNORE_UNUSED,
+			RK3399_PMU_CLKSEL_CON(4), 0, 10, DFLAGS),
+	MUX(0, "clk_testout_2io", mux_clk_testout2_2io_p, CLK_IGNORE_UNUSED,
+			RK3399_PMU_CLKSEL_CON(4), 15, 1, MFLAGS),
+
+	COMPOSITE(0, "clk_uart4_div", mux_24m_ppll_p, 0,
+			RK3399_PMU_CLKSEL_CON(5), 10, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_PMU_CLKGATE_CON(0), 5, GFLAGS),
+
+	COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_div", CLK_SET_RATE_PARENT,
+			RK3399_PMU_CLKSEL_CON(6), 0,
+			RK3399_PMU_CLKGATE_CON(0), 6, GFLAGS,
+			&rk3399_uart4_pmu_fracmux),
+
+	DIV(PCLK_SRC_PMU, "pclk_pmu_src", "ppll", CLK_IGNORE_UNUSED,
+			RK3399_PMU_CLKSEL_CON(0), 0, 5, DFLAGS),
+
+	/* pmu clock gates */
+	GATE(SCLK_TIMER12_PMU, "clk_timer0_pmu", "clk_timer_src_pmu", 0, RK3399_PMU_CLKGATE_CON(0), 3, GFLAGS),
+	GATE(SCLK_TIMER13_PMU, "clk_timer1_pmu", "clk_timer_src_pmu", 0, RK3399_PMU_CLKGATE_CON(0), 4, GFLAGS),
+
+	GATE(SCLK_PVTM_PMU, "clk_pvtm_pmu", "xin24m", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(0), 7, GFLAGS),
+
+	GATE(PCLK_PMU, "pclk_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 0, GFLAGS),
+	GATE(PCLK_PMUGRF_PMU, "pclk_pmugrf_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 1, GFLAGS),
+	GATE(PCLK_INTMEM1_PMU, "pclk_intmem1_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 2, GFLAGS),
+	GATE(PCLK_GPIO0_PMU, "pclk_gpio0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 3, GFLAGS),
+	GATE(PCLK_GPIO1_PMU, "pclk_gpio1_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 4, GFLAGS),
+	GATE(PCLK_SGRF_PMU, "pclk_sgrf_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 5, GFLAGS),
+	GATE(PCLK_NOC_PMU, "pclk_noc_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 6, GFLAGS),
+	GATE(PCLK_I2C0_PMU, "pclk_i2c0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 7, GFLAGS),
+	GATE(PCLK_I2C4_PMU, "pclk_i2c4_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 8, GFLAGS),
+	GATE(PCLK_I2C8_PMU, "pclk_i2c8_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 9, GFLAGS),
+	GATE(PCLK_RKPWM_PMU, "pclk_rkpwm_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 10, GFLAGS),
+	GATE(PCLK_SPI3_PMU, "pclk_spi3_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 11, GFLAGS),
+	GATE(PCLK_TIMER_PMU, "pclk_timer_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 12, GFLAGS),
+	GATE(PCLK_MAILBOX_PMU, "pclk_mailbox_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 13, GFLAGS),
+	GATE(PCLK_UART4_PMU, "pclk_uart4_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 14, GFLAGS),
+	GATE(PCLK_WDT_M0_PMU, "pclk_wdt_m0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 15, GFLAGS),
+
+	GATE(FCLK_CM0S_PMU, "fclk_cm0s_pmu", "fclk_cm0s_src_pmu", 0, RK3399_PMU_CLKGATE_CON(2), 0, GFLAGS),
+	GATE(SCLK_CM0S_PMU, "sclk_cm0s_pmu", "fclk_cm0s_src_pmu", 0, RK3399_PMU_CLKGATE_CON(2), 1, GFLAGS),
+	GATE(HCLK_CM0S_PMU, "hclk_cm0s_pmu", "fclk_cm0s_src_pmu", 0, RK3399_PMU_CLKGATE_CON(2), 2, GFLAGS),
+	GATE(DCLK_CM0S_PMU, "dclk_cm0s_pmu", "fclk_cm0s_src_pmu", 0, RK3399_PMU_CLKGATE_CON(2), 3, GFLAGS),
+	GATE(HCLK_NOC_PMU, "hclk_noc_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 5, GFLAGS),
+};
+
+static const char *const rk3399_cru_critical_clocks[] __initconst = {
+	"aclk_cci_pre",
+	"pclk_perilp0",
+	"pclk_perilp0",
+	"hclk_perilp0",
+	"hclk_perilp0_noc",
+	"pclk_perilp1",
+	"pclk_perilp1_noc",
+	"pclk_perihp",
+	"pclk_perihp_noc",
+	"hclk_perihp",
+	"aclk_perihp",
+	"aclk_perihp_noc",
+	"aclk_perilp0",
+	"aclk_perilp0_noc",
+	"hclk_perilp1",
+	"hclk_perilp1_noc",
+	"aclk_dmac0_perilp",
+	"gpll_hclk_perilp1_src",
+	"gpll_aclk_perilp0_src",
+	"gpll_aclk_perihp_src",
+};
+
+static const char *const rk3399_pmucru_critical_clocks[] __initconst = {
+	"ppll",
+	"pclk_pmu_src",
+	"fclk_cm0s_src_pmu",
+	"clk_timer_src_pmu",
+};
+
+static void __init rk3399_clk_init(struct device_node *np)
+{
+	struct rockchip_clk_provider *ctx;
+	void __iomem *reg_base;
+
+	reg_base = of_iomap(np, 0);
+	if (!reg_base) {
+		pr_err("%s: could not map cru region\n", __func__);
+		return;
+	}
+
+	ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+	if (IS_ERR(ctx)) {
+		pr_err("%s: rockchip clk init failed\n", __func__);
+		return;
+	}
+
+	rockchip_clk_register_plls(ctx, rk3399_pll_clks,
+				   ARRAY_SIZE(rk3399_pll_clks), -1);
+
+	rockchip_clk_register_branches(ctx, rk3399_clk_branches,
+				  ARRAY_SIZE(rk3399_clk_branches));
+
+	rockchip_clk_protect_critical(rk3399_cru_critical_clocks,
+				      ARRAY_SIZE(rk3399_cru_critical_clocks));
+
+	rockchip_clk_register_armclk(ctx, ARMCLKL, "armclkl",
+			mux_armclkl_p, ARRAY_SIZE(mux_armclkl_p),
+			&rk3399_cpuclkl_data, rk3399_cpuclkl_rates,
+			ARRAY_SIZE(rk3399_cpuclkl_rates));
+
+	rockchip_clk_register_armclk(ctx, ARMCLKB, "armclkb",
+			mux_armclkb_p, ARRAY_SIZE(mux_armclkb_p),
+			&rk3399_cpuclkb_data, rk3399_cpuclkb_rates,
+			ARRAY_SIZE(rk3399_cpuclkb_rates));
+
+	rockchip_register_softrst(np, 21, reg_base + RK3399_SOFTRST_CON(0),
+				  ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+	rockchip_register_restart_notifier(ctx, RK3399_GLB_SRST_FST, NULL);
+
+	rockchip_clk_of_add_provider(np, ctx);
+}
+CLK_OF_DECLARE(rk3399_cru, "rockchip,rk3399-cru", rk3399_clk_init);
+
+static void __init rk3399_pmu_clk_init(struct device_node *np)
+{
+	struct rockchip_clk_provider *ctx;
+	void __iomem *reg_base;
+
+	reg_base = of_iomap(np, 0);
+	if (!reg_base) {
+		pr_err("%s: could not map cru pmu region\n", __func__);
+		return;
+	}
+
+	ctx = rockchip_clk_init(np, reg_base, CLKPMU_NR_CLKS);
+	if (IS_ERR(ctx)) {
+		pr_err("%s: rockchip pmu clk init failed\n", __func__);
+		return;
+	}
+
+	rockchip_clk_register_plls(ctx, rk3399_pmu_pll_clks,
+				   ARRAY_SIZE(rk3399_pmu_pll_clks), -1);
+
+	rockchip_clk_register_branches(ctx, rk3399_clk_pmu_branches,
+				  ARRAY_SIZE(rk3399_clk_pmu_branches));
+
+	rockchip_clk_protect_critical(rk3399_pmucru_critical_clocks,
+				  ARRAY_SIZE(rk3399_pmucru_critical_clocks));
+
+	rockchip_register_softrst(np, 2, reg_base + RK3399_PMU_SOFTRST_CON(0),
+				  ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+	rockchip_clk_of_add_provider(np, ctx);
+}
+CLK_OF_DECLARE(rk3399_cru_pmu, "rockchip,rk3399-pmucru", rk3399_pmu_clk_init);
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index ec06350..f0a8be1 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -2,6 +2,9 @@
  * Copyright (c) 2014 MundoReader S.L.
  * Author: Heiko Stuebner <heiko@sntech.de>
  *
+ * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.com>
+ *
  * based on
  *
  * samsung/clk.c
@@ -39,7 +42,8 @@
  * sometimes without one of those components.
  */
 static struct clk *rockchip_clk_register_branch(const char *name,
-		const char *const *parent_names, u8 num_parents, void __iomem *base,
+		const char *const *parent_names, u8 num_parents,
+		void __iomem *base,
 		int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags,
 		u8 div_shift, u8 div_width, u8 div_flags,
 		struct clk_div_table *div_table, int gate_offset,
@@ -136,9 +140,11 @@
 	pr_debug("%s: event %lu, old_rate %lu, new_rate: %lu\n",
 		 __func__, event, ndata->old_rate, ndata->new_rate);
 	if (event == PRE_RATE_CHANGE) {
-		frac->rate_change_idx = frac->mux_ops->get_parent(&frac_mux->hw);
+		frac->rate_change_idx =
+				frac->mux_ops->get_parent(&frac_mux->hw);
 		if (frac->rate_change_idx != frac->mux_frac_idx) {
-			frac->mux_ops->set_parent(&frac_mux->hw, frac->mux_frac_idx);
+			frac->mux_ops->set_parent(&frac_mux->hw,
+						  frac->mux_frac_idx);
 			frac->rate_change_remuxed = 1;
 		}
 	} else if (event == POST_RATE_CHANGE) {
@@ -149,7 +155,8 @@
 		 * reaches the mux itself.
 		 */
 		if (frac->rate_change_remuxed) {
-			frac->mux_ops->set_parent(&frac_mux->hw, frac->rate_change_idx);
+			frac->mux_ops->set_parent(&frac_mux->hw,
+						  frac->rate_change_idx);
 			frac->rate_change_remuxed = 0;
 		}
 	}
@@ -157,7 +164,8 @@
 	return notifier_from_errno(ret);
 }
 
-static struct clk *rockchip_clk_register_frac_branch(const char *name,
+static struct clk *rockchip_clk_register_frac_branch(
+		struct rockchip_clk_provider *ctx, const char *name,
 		const char *const *parent_names, u8 num_parents,
 		void __iomem *base, int muxdiv_offset, u8 div_flags,
 		int gate_offset, u8 gate_shift, u8 gate_flags,
@@ -250,7 +258,7 @@
 		if (IS_ERR(mux_clk))
 			return clk;
 
-		rockchip_clk_add_lookup(mux_clk, child->id);
+		rockchip_clk_add_lookup(ctx, mux_clk, child->id);
 
 		/* notifier on the fraction divider to catch rate changes */
 		if (frac->mux_frac_idx >= 0) {
@@ -314,66 +322,87 @@
 	return clk;
 }
 
-static DEFINE_SPINLOCK(clk_lock);
-static struct clk **clk_table;
-static void __iomem *reg_base;
-static struct clk_onecell_data clk_data;
-static struct device_node *cru_node;
-static struct regmap *grf;
-
-void __init rockchip_clk_init(struct device_node *np, void __iomem *base,
-			      unsigned long nr_clks)
+struct rockchip_clk_provider * __init rockchip_clk_init(struct device_node *np,
+			void __iomem *base, unsigned long nr_clks)
 {
-	reg_base = base;
-	cru_node = np;
-	grf = ERR_PTR(-EPROBE_DEFER);
+	struct rockchip_clk_provider *ctx;
+	struct clk **clk_table;
+	int i;
+
+	ctx = kzalloc(sizeof(struct rockchip_clk_provider), GFP_KERNEL);
+	if (!ctx)
+		return ERR_PTR(-ENOMEM);
 
 	clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
 	if (!clk_table)
-		pr_err("%s: could not allocate clock lookup table\n", __func__);
+		goto err_free;
 
-	clk_data.clks = clk_table;
-	clk_data.clk_num = nr_clks;
-	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	for (i = 0; i < nr_clks; ++i)
+		clk_table[i] = ERR_PTR(-ENOENT);
+
+	ctx->reg_base = base;
+	ctx->clk_data.clks = clk_table;
+	ctx->clk_data.clk_num = nr_clks;
+	ctx->cru_node = np;
+	ctx->grf = ERR_PTR(-EPROBE_DEFER);
+	spin_lock_init(&ctx->lock);
+
+	return ctx;
+
+err_free:
+	kfree(ctx);
+	return ERR_PTR(-ENOMEM);
 }
 
-struct regmap *rockchip_clk_get_grf(void)
+void __init rockchip_clk_of_add_provider(struct device_node *np,
+				struct rockchip_clk_provider *ctx)
 {
-	if (IS_ERR(grf))
-		grf = syscon_regmap_lookup_by_phandle(cru_node, "rockchip,grf");
-	return grf;
+	if (of_clk_add_provider(np, of_clk_src_onecell_get,
+				&ctx->clk_data))
+		pr_err("%s: could not register clk provider\n", __func__);
 }
 
-void rockchip_clk_add_lookup(struct clk *clk, unsigned int id)
+struct regmap *rockchip_clk_get_grf(struct rockchip_clk_provider *ctx)
 {
-	if (clk_table && id)
-		clk_table[id] = clk;
+	if (IS_ERR(ctx->grf))
+		ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node,
+							   "rockchip,grf");
+	return ctx->grf;
 }
 
-void __init rockchip_clk_register_plls(struct rockchip_pll_clock *list,
+void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx,
+			     struct clk *clk, unsigned int id)
+{
+	if (ctx->clk_data.clks && id)
+		ctx->clk_data.clks[id] = clk;
+}
+
+void __init rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
+				struct rockchip_pll_clock *list,
 				unsigned int nr_pll, int grf_lock_offset)
 {
 	struct clk *clk;
 	int idx;
 
 	for (idx = 0; idx < nr_pll; idx++, list++) {
-		clk = rockchip_clk_register_pll(list->type, list->name,
+		clk = rockchip_clk_register_pll(ctx, list->type, list->name,
 				list->parent_names, list->num_parents,
-				reg_base, list->con_offset, grf_lock_offset,
+				list->con_offset, grf_lock_offset,
 				list->lock_shift, list->mode_offset,
 				list->mode_shift, list->rate_table,
-				list->pll_flags, &clk_lock);
+				list->pll_flags);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
 				list->name);
 			continue;
 		}
 
-		rockchip_clk_add_lookup(clk, list->id);
+		rockchip_clk_add_lookup(ctx, clk, list->id);
 	}
 }
 
 void __init rockchip_clk_register_branches(
+				      struct rockchip_clk_provider *ctx,
 				      struct rockchip_clk_branch *list,
 				      unsigned int nr_clk)
 {
@@ -389,56 +418,59 @@
 		case branch_mux:
 			clk = clk_register_mux(NULL, list->name,
 				list->parent_names, list->num_parents,
-				flags, reg_base + list->muxdiv_offset,
+				flags, ctx->reg_base + list->muxdiv_offset,
 				list->mux_shift, list->mux_width,
-				list->mux_flags, &clk_lock);
+				list->mux_flags, &ctx->lock);
 			break;
 		case branch_divider:
 			if (list->div_table)
 				clk = clk_register_divider_table(NULL,
 					list->name, list->parent_names[0],
-					flags, reg_base + list->muxdiv_offset,
+					flags,
+					ctx->reg_base + list->muxdiv_offset,
 					list->div_shift, list->div_width,
 					list->div_flags, list->div_table,
-					&clk_lock);
+					&ctx->lock);
 			else
 				clk = clk_register_divider(NULL, list->name,
 					list->parent_names[0], flags,
-					reg_base + list->muxdiv_offset,
+					ctx->reg_base + list->muxdiv_offset,
 					list->div_shift, list->div_width,
-					list->div_flags, &clk_lock);
+					list->div_flags, &ctx->lock);
 			break;
 		case branch_fraction_divider:
-			clk = rockchip_clk_register_frac_branch(list->name,
+			clk = rockchip_clk_register_frac_branch(ctx, list->name,
 				list->parent_names, list->num_parents,
-				reg_base, list->muxdiv_offset, list->div_flags,
+				ctx->reg_base, list->muxdiv_offset,
+				list->div_flags,
 				list->gate_offset, list->gate_shift,
 				list->gate_flags, flags, list->child,
-				&clk_lock);
+				&ctx->lock);
 			break;
 		case branch_gate:
 			flags |= CLK_SET_RATE_PARENT;
 
 			clk = clk_register_gate(NULL, list->name,
 				list->parent_names[0], flags,
-				reg_base + list->gate_offset,
-				list->gate_shift, list->gate_flags, &clk_lock);
+				ctx->reg_base + list->gate_offset,
+				list->gate_shift, list->gate_flags, &ctx->lock);
 			break;
 		case branch_composite:
 			clk = rockchip_clk_register_branch(list->name,
 				list->parent_names, list->num_parents,
-				reg_base, list->muxdiv_offset, list->mux_shift,
+				ctx->reg_base, list->muxdiv_offset,
+				list->mux_shift,
 				list->mux_width, list->mux_flags,
 				list->div_shift, list->div_width,
 				list->div_flags, list->div_table,
 				list->gate_offset, list->gate_shift,
-				list->gate_flags, flags, &clk_lock);
+				list->gate_flags, flags, &ctx->lock);
 			break;
 		case branch_mmc:
 			clk = rockchip_clk_register_mmc(
 				list->name,
 				list->parent_names, list->num_parents,
-				reg_base + list->muxdiv_offset,
+				ctx->reg_base + list->muxdiv_offset,
 				list->div_shift
 			);
 			break;
@@ -446,16 +478,16 @@
 			clk = rockchip_clk_register_inverter(
 				list->name, list->parent_names,
 				list->num_parents,
-				reg_base + list->muxdiv_offset,
-				list->div_shift, list->div_flags, &clk_lock);
+				ctx->reg_base + list->muxdiv_offset,
+				list->div_shift, list->div_flags, &ctx->lock);
 			break;
 		case branch_factor:
 			clk = rockchip_clk_register_factor_branch(
 				list->name, list->parent_names,
-				list->num_parents, reg_base,
+				list->num_parents, ctx->reg_base,
 				list->div_shift, list->div_width,
 				list->gate_offset, list->gate_shift,
-				list->gate_flags, flags, &clk_lock);
+				list->gate_flags, flags, &ctx->lock);
 			break;
 		}
 
@@ -472,11 +504,12 @@
 			continue;
 		}
 
-		rockchip_clk_add_lookup(clk, list->id);
+		rockchip_clk_add_lookup(ctx, clk, list->id);
 	}
 }
 
-void __init rockchip_clk_register_armclk(unsigned int lookup_id,
+void __init rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
+			unsigned int lookup_id,
 			const char *name, const char *const *parent_names,
 			u8 num_parents,
 			const struct rockchip_cpuclk_reg_data *reg_data,
@@ -486,15 +519,15 @@
 	struct clk *clk;
 
 	clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents,
-					   reg_data, rates, nrates, reg_base,
-					   &clk_lock);
+					   reg_data, rates, nrates,
+					   ctx->reg_base, &ctx->lock);
 	if (IS_ERR(clk)) {
 		pr_err("%s: failed to register clock %s: %ld\n",
 		       __func__, name, PTR_ERR(clk));
 		return;
 	}
 
-	rockchip_clk_add_lookup(clk, lookup_id);
+	rockchip_clk_add_lookup(ctx, clk, lookup_id);
 }
 
 void __init rockchip_clk_protect_critical(const char *const clocks[],
@@ -511,6 +544,7 @@
 	}
 }
 
+static void __iomem *rst_base;
 static unsigned int reg_restart;
 static void (*cb_restart)(void);
 static int rockchip_restart_notify(struct notifier_block *this,
@@ -519,7 +553,7 @@
 	if (cb_restart)
 		cb_restart();
 
-	writel(0xfdb9, reg_base + reg_restart);
+	writel(0xfdb9, rst_base + reg_restart);
 	return NOTIFY_DONE;
 }
 
@@ -528,10 +562,14 @@
 	.priority = 128,
 };
 
-void __init rockchip_register_restart_notifier(unsigned int reg, void (*cb)(void))
+void __init
+rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx,
+					       unsigned int reg,
+					       void (*cb)(void))
 {
 	int ret;
 
+	rst_base = ctx->reg_base;
 	reg_restart = reg;
 	cb_restart = cb;
 	ret = register_restart_handler(&rockchip_restart_handler);
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 39c198b..1abb7d0 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -27,13 +27,13 @@
 #define CLK_ROCKCHIP_CLK_H
 
 #include <linux/io.h>
+#include <linux/clk-provider.h>
 
 struct clk;
 
 #define HIWORD_UPDATE(val, mask, shift) \
 		((val) << (shift) | (mask) << ((shift) + 16))
 
-/* register positions shared by RK2928, RK3036, RK3066, RK3188 and RK3228 */
 #define RK2928_PLL_CON(x)		((x) * 0x4)
 #define RK2928_MODE_CON		0x40
 #define RK2928_CLKSEL_CON(x)	((x) * 0x4 + 0x44)
@@ -92,9 +92,30 @@
 #define RK3368_EMMC_CON0		0x418
 #define RK3368_EMMC_CON1		0x41c
 
+#define RK3399_PLL_CON(x)		RK2928_PLL_CON(x)
+#define RK3399_CLKSEL_CON(x)		((x) * 0x4 + 0x100)
+#define RK3399_CLKGATE_CON(x)		((x) * 0x4 + 0x300)
+#define RK3399_SOFTRST_CON(x)		((x) * 0x4 + 0x400)
+#define RK3399_GLB_SRST_FST		0x500
+#define RK3399_GLB_SRST_SND		0x504
+#define RK3399_GLB_CNT_TH		0x508
+#define RK3399_MISC_CON			0x50c
+#define RK3399_RST_CON			0x510
+#define RK3399_RST_ST			0x514
+#define RK3399_SDMMC_CON0		0x580
+#define RK3399_SDMMC_CON1		0x584
+#define RK3399_SDIO_CON0		0x588
+#define RK3399_SDIO_CON1		0x58c
+
+#define RK3399_PMU_PLL_CON(x)		RK2928_PLL_CON(x)
+#define RK3399_PMU_CLKSEL_CON(x)	((x) * 0x4 + 0x80)
+#define RK3399_PMU_CLKGATE_CON(x)	((x) * 0x4 + 0x100)
+#define RK3399_PMU_SOFTRST_CON(x)	((x) * 0x4 + 0x110)
+
 enum rockchip_pll_type {
 	pll_rk3036,
 	pll_rk3066,
+	pll_rk3399,
 };
 
 #define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1,	\
@@ -127,13 +148,29 @@
 	.nb = _nb,						\
 }
 
+/**
+ * struct rockchip_clk_provider - information about clock provider
+ * @reg_base: virtual address for the register base.
+ * @clk_data: holds clock related data like clk* and number of clocks.
+ * @cru_node: device-node of the clock-provider
+ * @grf: regmap of the general-register-files syscon
+ * @lock: maintains exclusion between callbacks for a given clock-provider.
+ */
+struct rockchip_clk_provider {
+	void __iomem *reg_base;
+	struct clk_onecell_data clk_data;
+	struct device_node *cru_node;
+	struct regmap *grf;
+	spinlock_t lock;
+};
+
 struct rockchip_pll_rate_table {
 	unsigned long rate;
 	unsigned int nr;
 	unsigned int nf;
 	unsigned int no;
 	unsigned int nb;
-	/* for RK3036 */
+	/* for RK3036/RK3399 */
 	unsigned int fbdiv;
 	unsigned int postdiv1;
 	unsigned int refdiv;
@@ -143,10 +180,11 @@
 };
 
 /**
- * struct rockchip_pll_clock: information about pll clock
+ * struct rockchip_pll_clock - information about pll clock
  * @id: platform specific id of the clock.
  * @name: name of this pll clock.
- * @parent_name: name of the parent clock.
+ * @parent_names: name of the parent clock.
+ * @num_parents: number of parents
  * @flags: optional flags for basic clock.
  * @con_offset: offset of the register for configuring the PLL.
  * @mode_offset: offset of the register for configuring the PLL-mode.
@@ -194,12 +232,13 @@
 		.rate_table	= _rtable,				\
 	}
 
-struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
+struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
+		enum rockchip_pll_type pll_type,
 		const char *name, const char *const *parent_names,
-		u8 num_parents, void __iomem *base, int con_offset,
-		int grf_lock_offset, int lock_shift, int reg_mode,
-		int mode_shift, struct rockchip_pll_rate_table *rate_table,
-		u8 clk_pll_flags, spinlock_t *lock);
+		u8 num_parents, int con_offset, int grf_lock_offset,
+		int lock_shift, int mode_offset, int mode_shift,
+		struct rockchip_pll_rate_table *rate_table,
+		u8 clk_pll_flags);
 
 struct rockchip_cpuclk_clksel {
 	int reg;
@@ -213,18 +252,23 @@
 };
 
 /**
- * struct rockchip_cpuclk_reg_data: describes register offsets and masks of the cpuclock
+ * struct rockchip_cpuclk_reg_data - register offsets and masks of the cpuclock
  * @core_reg:		register offset of the core settings register
  * @div_core_shift:	core divider offset used to divide the pll value
  * @div_core_mask:	core divider mask
+ * @mux_core_alt:	mux value to select alternate parent
+ * @mux_core_main:	mux value to select main parent of core
  * @mux_core_shift:	offset of the core multiplexer
+ * @mux_core_mask:	core multiplexer mask
  */
 struct rockchip_cpuclk_reg_data {
 	int		core_reg;
 	u8		div_core_shift;
 	u32		div_core_mask;
-	int		mux_core_reg;
+	u8		mux_core_alt;
+	u8		mux_core_main;
 	u8		mux_core_shift;
+	u32		mux_core_mask;
 };
 
 struct clk *rockchip_clk_register_cpuclk(const char *name,
@@ -428,6 +472,22 @@
 		.child		= ch,				\
 	}
 
+#define COMPOSITE_FRACMUX_NOGATE(_id, cname, pname, f, mo, df, ch) \
+	{							\
+		.id		= _id,				\
+		.branch_type	= branch_fraction_divider,	\
+		.name		= cname,			\
+		.parent_names	= (const char *[]){ pname },	\
+		.num_parents	= 1,				\
+		.flags		= f,				\
+		.muxdiv_offset	= mo,				\
+		.div_shift	= 16,				\
+		.div_width	= 16,				\
+		.div_flags	= df,				\
+		.gate_offset	= -1,				\
+		.child		= ch,				\
+	}
+
 #define MUX(_id, cname, pnames, f, o, s, w, mf)			\
 	{							\
 		.id		= _id,				\
@@ -536,21 +596,28 @@
 		.gate_flags	= gf,				\
 	}
 
-void rockchip_clk_init(struct device_node *np, void __iomem *base,
-		       unsigned long nr_clks);
-struct regmap *rockchip_clk_get_grf(void);
-void rockchip_clk_add_lookup(struct clk *clk, unsigned int id);
-void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list,
+struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
+			void __iomem *base, unsigned long nr_clks);
+void rockchip_clk_of_add_provider(struct device_node *np,
+				struct rockchip_clk_provider *ctx);
+struct regmap *rockchip_clk_get_grf(struct rockchip_clk_provider *ctx);
+void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx,
+			     struct clk *clk, unsigned int id);
+void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
+				    struct rockchip_clk_branch *list,
 				    unsigned int nr_clk);
-void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list,
+void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
+				struct rockchip_pll_clock *pll_list,
 				unsigned int nr_pll, int grf_lock_offset);
-void rockchip_clk_register_armclk(unsigned int lookup_id, const char *name,
+void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
+			unsigned int lookup_id, const char *name,
 			const char *const *parent_names, u8 num_parents,
 			const struct rockchip_cpuclk_reg_data *reg_data,
 			const struct rockchip_cpuclk_rate_table *rates,
 			int nrates);
 void rockchip_clk_protect_critical(const char *const clocks[], int nclocks);
-void rockchip_register_restart_notifier(unsigned int reg, void (*cb)(void));
+void rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx,
+					unsigned int reg, void (*cb)(void));
 
 #define ROCKCHIP_SOFTRST_HIWORD_MASK	BIT(0)
 
diff --git a/drivers/clk/rockchip/softrst.c b/drivers/clk/rockchip/softrst.c
index 552f7bb..21218987 100644
--- a/drivers/clk/rockchip/softrst.c
+++ b/drivers/clk/rockchip/softrst.c
@@ -81,7 +81,7 @@
 	return 0;
 }
 
-static struct reset_control_ops rockchip_softrst_ops = {
+static const struct reset_control_ops rockchip_softrst_ops = {
 	.assert		= rockchip_softrst_assert,
 	.deassert	= rockchip_softrst_deassert,
 };
diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c
index fdd41b1..16575ee 100644
--- a/drivers/clk/samsung/clk-exynos3250.c
+++ b/drivers/clk/samsung/clk-exynos3250.c
@@ -302,10 +302,12 @@
 
 	/* SRC_FSYS */
 	MUX(CLK_MOUT_TSADC, "mout_tsadc", group_sclk_p, SRC_FSYS, 28, 4),
+	MUX(CLK_MOUT_MMC2, "mout_mmc2", group_sclk_p, SRC_FSYS, 8, 4),
 	MUX(CLK_MOUT_MMC1, "mout_mmc1", group_sclk_p, SRC_FSYS, 4, 4),
 	MUX(CLK_MOUT_MMC0, "mout_mmc0", group_sclk_p, SRC_FSYS, 0, 4),
 
 	/* SRC_PERIL0 */
+	MUX(CLK_MOUT_UART2, "mout_uart2", group_sclk_p, SRC_PERIL0, 8, 4),
 	MUX(CLK_MOUT_UART1, "mout_uart1", group_sclk_p, SRC_PERIL0, 4, 4),
 	MUX(CLK_MOUT_UART0, "mout_uart0", group_sclk_p, SRC_PERIL0, 0, 4),
 
@@ -389,7 +391,13 @@
 		CLK_SET_RATE_PARENT, 0),
 	DIV(CLK_DIV_MMC0, "div_mmc0", "mout_mmc0", DIV_FSYS1, 0, 4),
 
+	/* DIV_FSYS2 */
+	DIV_F(CLK_DIV_MMC2_PRE, "div_mmc2_pre", "div_mmc2", DIV_FSYS2, 8, 8,
+		CLK_SET_RATE_PARENT, 0),
+	DIV(CLK_DIV_MMC2, "div_mmc2", "mout_mmc2", DIV_FSYS2, 0, 4),
+
 	/* DIV_PERIL0 */
+	DIV(CLK_DIV_UART2, "div_uart2", "mout_uart2", DIV_PERIL0, 8, 4),
 	DIV(CLK_DIV_UART1, "div_uart1", "mout_uart1", DIV_PERIL0, 4, 4),
 	DIV(CLK_DIV_UART0, "div_uart0", "mout_uart0", DIV_PERIL0, 0, 4),
 
@@ -538,6 +546,8 @@
 		GATE_SCLK_FSYS, 9, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_EBI, "sclk_ebi", "div_ebi",
 		GATE_SCLK_FSYS, 6, CLK_SET_RATE_PARENT, 0),
+	GATE(CLK_SCLK_MMC2, "sclk_mmc2", "div_mmc2_pre",
+		GATE_SCLK_FSYS, 2, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_MMC1, "sclk_mmc1", "div_mmc1_pre",
 		GATE_SCLK_FSYS, 1, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_MMC0, "sclk_mmc0", "div_mmc0_pre",
@@ -552,6 +562,9 @@
 		GATE_SCLK_PERIL, 7, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_SPI0, "sclk_spi0", "div_spi0_pre",
 		GATE_SCLK_PERIL, 6, CLK_SET_RATE_PARENT, 0),
+
+	GATE(CLK_SCLK_UART2, "sclk_uart2", "div_uart2",
+		GATE_SCLK_PERIL, 2, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_UART1, "sclk_uart1", "div_uart1",
 		GATE_SCLK_PERIL, 1, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_UART0, "sclk_uart0", "div_uart0",
@@ -630,6 +643,7 @@
 	GATE(CLK_USBOTG, "usbotg", "div_aclk_200", GATE_IP_FSYS, 13, 0, 0),
 	GATE(CLK_USBHOST, "usbhost", "div_aclk_200", GATE_IP_FSYS, 12, 0, 0),
 	GATE(CLK_SROMC, "sromc", "div_aclk_200", GATE_IP_FSYS, 11, 0, 0),
+	GATE(CLK_SDMMC2, "sdmmc2", "div_aclk_200", GATE_IP_FSYS, 7, 0, 0),
 	GATE(CLK_SDMMC1, "sdmmc1", "div_aclk_200", GATE_IP_FSYS, 6, 0, 0),
 	GATE(CLK_SDMMC0, "sdmmc0", "div_aclk_200", GATE_IP_FSYS, 5, 0, 0),
 	GATE(CLK_PDMA1, "pdma1", "div_aclk_200", GATE_IP_FSYS, 1, 0, 0),
@@ -649,6 +663,7 @@
 	GATE(CLK_I2C2, "i2c2", "div_aclk_100", GATE_IP_PERIL, 8, 0, 0),
 	GATE(CLK_I2C1, "i2c1", "div_aclk_100", GATE_IP_PERIL, 7, 0, 0),
 	GATE(CLK_I2C0, "i2c0", "div_aclk_100", GATE_IP_PERIL, 6, 0, 0),
+	GATE(CLK_UART2, "uart2", "div_aclk_100", GATE_IP_PERIL, 2, 0, 0),
 	GATE(CLK_UART1, "uart1", "div_aclk_100", GATE_IP_PERIL, 1, 0, 0),
 	GATE(CLK_UART0, "uart0", "div_aclk_100", GATE_IP_PERIL, 0, 0, 0),
 };
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index be03ed0..92382ce 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -554,8 +554,8 @@
 };
 
 static struct samsung_div_clock exynos5800_div_clks[] __initdata = {
-	DIV(0, "dout_aclk400_wcore", "mout_aclk400_wcore", DIV_TOP0, 16, 3),
-
+	DIV(CLK_DOUT_ACLK400_WCORE, "dout_aclk400_wcore",
+			"mout_aclk400_wcore", DIV_TOP0, 16, 3),
 	DIV(0, "dout_aclk550_cam", "mout_aclk550_cam",
 				DIV_TOP8, 16, 3),
 	DIV(0, "dout_aclkfl1_550_cam", "mout_aclkfl1_550_cam",
@@ -607,8 +607,8 @@
 };
 
 static struct samsung_div_clock exynos5420_div_clks[] __initdata = {
-	DIV(0, "dout_aclk400_wcore", "mout_aclk400_wcore_bpll",
-			DIV_TOP0, 16, 3),
+	DIV(CLK_DOUT_ACLK400_WCORE, "dout_aclk400_wcore",
+			"mout_aclk400_wcore_bpll", DIV_TOP0, 16, 3),
 };
 
 static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
@@ -785,31 +785,47 @@
 	DIV(0, "div_kfc", "mout_kfc", DIV_KFC0, 0, 3),
 	DIV(0, "sclk_kpll", "mout_kpll", DIV_KFC0, 24, 3),
 
-	DIV(0, "dout_aclk400_isp", "mout_aclk400_isp", DIV_TOP0, 0, 3),
-	DIV(0, "dout_aclk400_mscl", "mout_aclk400_mscl", DIV_TOP0, 4, 3),
-	DIV(0, "dout_aclk200", "mout_aclk200", DIV_TOP0, 8, 3),
-	DIV(0, "dout_aclk200_fsys2", "mout_aclk200_fsys2", DIV_TOP0, 12, 3),
-	DIV(0, "dout_aclk100_noc", "mout_aclk100_noc", DIV_TOP0, 20, 3),
-	DIV(0, "dout_pclk200_fsys", "mout_pclk200_fsys", DIV_TOP0, 24, 3),
-	DIV(0, "dout_aclk200_fsys", "mout_aclk200_fsys", DIV_TOP0, 28, 3),
+	DIV(CLK_DOUT_ACLK400_ISP, "dout_aclk400_isp", "mout_aclk400_isp",
+			DIV_TOP0, 0, 3),
+	DIV(CLK_DOUT_ACLK400_MSCL, "dout_aclk400_mscl", "mout_aclk400_mscl",
+			DIV_TOP0, 4, 3),
+	DIV(CLK_DOUT_ACLK200, "dout_aclk200", "mout_aclk200",
+			DIV_TOP0, 8, 3),
+	DIV(CLK_DOUT_ACLK200_FSYS2, "dout_aclk200_fsys2", "mout_aclk200_fsys2",
+			DIV_TOP0, 12, 3),
+	DIV(CLK_DOUT_ACLK100_NOC, "dout_aclk100_noc", "mout_aclk100_noc",
+			DIV_TOP0, 20, 3),
+	DIV(CLK_DOUT_PCLK200_FSYS, "dout_pclk200_fsys", "mout_pclk200_fsys",
+			DIV_TOP0, 24, 3),
+	DIV(CLK_DOUT_ACLK200_FSYS, "dout_aclk200_fsys", "mout_aclk200_fsys",
+			DIV_TOP0, 28, 3),
+	DIV(CLK_DOUT_ACLK333_432_GSCL, "dout_aclk333_432_gscl",
+			"mout_aclk333_432_gscl", DIV_TOP1, 0, 3),
+	DIV(CLK_DOUT_ACLK333_432_ISP, "dout_aclk333_432_isp",
+			"mout_aclk333_432_isp", DIV_TOP1, 4, 3),
+	DIV(CLK_DOUT_ACLK66, "dout_aclk66", "mout_aclk66",
+			DIV_TOP1, 8, 6),
+	DIV(CLK_DOUT_ACLK333_432_ISP0, "dout_aclk333_432_isp0",
+			"mout_aclk333_432_isp0", DIV_TOP1, 16, 3),
+	DIV(CLK_DOUT_ACLK266, "dout_aclk266", "mout_aclk266",
+			DIV_TOP1, 20, 3),
+	DIV(CLK_DOUT_ACLK166, "dout_aclk166", "mout_aclk166",
+			DIV_TOP1, 24, 3),
+	DIV(CLK_DOUT_ACLK333, "dout_aclk333", "mout_aclk333",
+			DIV_TOP1, 28, 3),
 
-	DIV(0, "dout_aclk333_432_gscl", "mout_aclk333_432_gscl",
-			DIV_TOP1, 0, 3),
-	DIV(0, "dout_aclk333_432_isp", "mout_aclk333_432_isp",
-			DIV_TOP1, 4, 3),
-	DIV(0, "dout_aclk66", "mout_aclk66", DIV_TOP1, 8, 6),
-	DIV(0, "dout_aclk333_432_isp0", "mout_aclk333_432_isp0",
-			DIV_TOP1, 16, 3),
-	DIV(0, "dout_aclk266", "mout_aclk266", DIV_TOP1, 20, 3),
-	DIV(0, "dout_aclk166", "mout_aclk166", DIV_TOP1, 24, 3),
-	DIV(0, "dout_aclk333", "mout_aclk333", DIV_TOP1, 28, 3),
-
-	DIV(0, "dout_aclk333_g2d", "mout_aclk333_g2d", DIV_TOP2, 8, 3),
-	DIV(0, "dout_aclk266_g2d", "mout_aclk266_g2d", DIV_TOP2, 12, 3),
-	DIV(0, "dout_aclk_g3d", "mout_aclk_g3d", DIV_TOP2, 16, 3),
-	DIV(0, "dout_aclk300_jpeg", "mout_aclk300_jpeg", DIV_TOP2, 20, 3),
-	DIV(0, "dout_aclk300_disp1", "mout_aclk300_disp1", DIV_TOP2, 24, 3),
-	DIV(0, "dout_aclk300_gscl", "mout_aclk300_gscl", DIV_TOP2, 28, 3),
+	DIV(CLK_DOUT_ACLK333_G2D, "dout_aclk333_g2d", "mout_aclk333_g2d",
+			DIV_TOP2, 8, 3),
+	DIV(CLK_DOUT_ACLK266_G2D, "dout_aclk266_g2d", "mout_aclk266_g2d",
+			DIV_TOP2, 12, 3),
+	DIV(CLK_DOUT_ACLK_G3D, "dout_aclk_g3d", "mout_aclk_g3d", DIV_TOP2,
+			16, 3),
+	DIV(CLK_DOUT_ACLK300_JPEG, "dout_aclk300_jpeg", "mout_aclk300_jpeg",
+			DIV_TOP2, 20, 3),
+	DIV(CLK_DOUT_ACLK300_DISP1, "dout_aclk300_disp1",
+			"mout_aclk300_disp1", DIV_TOP2, 24, 3),
+	DIV(CLK_DOUT_ACLK300_GSCL, "dout_aclk300_gscl", "mout_aclk300_gscl",
+			DIV_TOP2, 28, 3),
 
 	/* DISP1 Block */
 	DIV(0, "dout_fimd1", "mout_fimd1_final", DIV_DISP10, 0, 4),
@@ -817,7 +833,8 @@
 	DIV(0, "dout_dp1", "mout_dp1", DIV_DISP10, 24, 4),
 	DIV(CLK_DOUT_PIXEL, "dout_hdmi_pixel", "mout_pixel", DIV_DISP10, 28, 4),
 	DIV(0, "dout_disp1_blk", "aclk200_disp1", DIV2_RATIO0, 16, 2),
-	DIV(0, "dout_aclk400_disp1", "mout_aclk400_disp1", DIV_TOP2, 4, 3),
+	DIV(CLK_DOUT_ACLK400_DISP1, "dout_aclk400_disp1",
+			"mout_aclk400_disp1", DIV_TOP2, 4, 3),
 
 	/* Audio Block */
 	DIV(0, "dout_maudio0", "mout_maudio0", DIV_MAU, 20, 4),
diff --git a/drivers/clk/sirf/clk-atlas6.c b/drivers/clk/sirf/clk-atlas6.c
index c5eaa9d..665fa68 100644
--- a/drivers/clk/sirf/clk-atlas6.c
+++ b/drivers/clk/sirf/clk-atlas6.c
@@ -130,10 +130,9 @@
 		panic("unable to map clkc registers\n");
 
 	/* These are always available (RTC and 26MHz OSC)*/
-	atlas6_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL,
-		CLK_IS_ROOT, 32768);
-	atlas6_clks[osc] = clk_register_fixed_rate(NULL, "osc", NULL,
-		CLK_IS_ROOT, 26000000);
+	atlas6_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL, 0, 32768);
+	atlas6_clks[osc] = clk_register_fixed_rate(NULL, "osc", NULL, 0,
+						   26000000);
 
 	for (i = pll1; i < maxclk; i++) {
 		atlas6_clks[i] = clk_register(NULL, atlas6_clk_hw_array[i]);
diff --git a/drivers/clk/sirf/clk-atlas7.c b/drivers/clk/sirf/clk-atlas7.c
index 957aae6..d0c6c9a 100644
--- a/drivers/clk/sirf/clk-atlas7.c
+++ b/drivers/clk/sirf/clk-atlas7.c
@@ -1423,7 +1423,7 @@
 	return 0;
 }
 
-static struct reset_control_ops atlas7_rst_ops = {
+static const struct reset_control_ops atlas7_rst_ops = {
 	.reset = atlas7_reset_module,
 };
 
diff --git a/drivers/clk/sirf/clk-prima2.c b/drivers/clk/sirf/clk-prima2.c
index f92c402..aac1c8ec 100644
--- a/drivers/clk/sirf/clk-prima2.c
+++ b/drivers/clk/sirf/clk-prima2.c
@@ -129,10 +129,9 @@
 		panic("unable to map clkc registers\n");
 
 	/* These are always available (RTC and 26MHz OSC)*/
-	prima2_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL,
-		CLK_IS_ROOT, 32768);
-	prima2_clks[osc] = clk_register_fixed_rate(NULL, "osc", NULL,
-		CLK_IS_ROOT, 26000000);
+	prima2_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL, 0, 32768);
+	prima2_clks[osc] = clk_register_fixed_rate(NULL, "osc", NULL, 0,
+						   26000000);
 
 	for (i = pll1; i < maxclk; i++) {
 		prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]);
diff --git a/drivers/clk/sunxi/clk-a10-hosc.c b/drivers/clk/sunxi/clk-a10-hosc.c
index 6b598c6..dca5324 100644
--- a/drivers/clk/sunxi/clk-a10-hosc.c
+++ b/drivers/clk/sunxi/clk-a10-hosc.c
@@ -54,8 +54,7 @@
 			NULL, 0,
 			NULL, NULL,
 			&fixed->hw, &clk_fixed_rate_ops,
-			&gate->hw, &clk_gate_ops,
-			CLK_IS_ROOT);
+			&gate->hw, &clk_gate_ops, 0);
 
 	if (IS_ERR(clk))
 		goto err_free_gate;
diff --git a/drivers/clk/sunxi/clk-a10-ve.c b/drivers/clk/sunxi/clk-a10-ve.c
index 044c171..d9ea22e 100644
--- a/drivers/clk/sunxi/clk-a10-ve.c
+++ b/drivers/clk/sunxi/clk-a10-ve.c
@@ -85,7 +85,7 @@
 	return 0;
 }
 
-static struct reset_control_ops sunxi_ve_reset_ops = {
+static const struct reset_control_ops sunxi_ve_reset_ops = {
 	.assert		= sunxi_ve_reset_assert,
 	.deassert	= sunxi_ve_reset_deassert,
 };
diff --git a/drivers/clk/sunxi/clk-sun9i-mmc.c b/drivers/clk/sunxi/clk-sun9i-mmc.c
index 0c2dd02..7167373 100644
--- a/drivers/clk/sunxi/clk-sun9i-mmc.c
+++ b/drivers/clk/sunxi/clk-sun9i-mmc.c
@@ -83,7 +83,7 @@
 	return 0;
 }
 
-static struct reset_control_ops sun9i_mmc_reset_ops = {
+static const struct reset_control_ops sun9i_mmc_reset_ops = {
 	.assert		= sun9i_mmc_reset_assert,
 	.deassert	= sun9i_mmc_reset_deassert,
 };
diff --git a/drivers/clk/sunxi/clk-usb.c b/drivers/clk/sunxi/clk-usb.c
index 5432b1c..fe0c3d1 100644
--- a/drivers/clk/sunxi/clk-usb.c
+++ b/drivers/clk/sunxi/clk-usb.c
@@ -76,7 +76,7 @@
 	return 0;
 }
 
-static struct reset_control_ops sunxi_usb_reset_ops = {
+static const struct reset_control_ops sunxi_usb_reset_ops = {
 	.assert		= sunxi_usb_reset_assert,
 	.deassert	= sunxi_usb_reset_deassert,
 };
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index 97984c5..33fd093 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -3,6 +3,7 @@
 obj-y					+= clk-dfll.o
 obj-y					+= clk-divider.o
 obj-y					+= clk-periph.o
+obj-y					+= clk-periph-fixed.o
 obj-y					+= clk-periph-gate.o
 obj-y					+= clk-pll.o
 obj-y					+= clk-pll-out.o
diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c
index 19bfa07..f010562 100644
--- a/drivers/clk/tegra/clk-dfll.c
+++ b/drivers/clk/tegra/clk-dfll.c
@@ -55,6 +55,7 @@
 #include <linux/seq_file.h>
 
 #include "clk-dfll.h"
+#include "cvb.h"
 
 /*
  * DFLL control registers - access via dfll_{readl,writel}
@@ -442,8 +443,8 @@
 {
 	td->tune_range = DFLL_TUNE_LOW;
 
-	dfll_writel(td, td->soc->tune0_low, DFLL_TUNE0);
-	dfll_writel(td, td->soc->tune1, DFLL_TUNE1);
+	dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune0_low, DFLL_TUNE0);
+	dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune1, DFLL_TUNE1);
 	dfll_wmb(td);
 
 	if (td->soc->set_clock_trimmers_low)
@@ -1449,7 +1450,7 @@
 	}
 	v_max = dev_pm_opp_get_voltage(opp);
 
-	v = td->soc->min_millivolts * 1000;
+	v = td->soc->cvb->min_millivolts * 1000;
 	lut = find_vdd_map_entry_exact(td, v);
 	if (lut < 0)
 		goto out;
@@ -1461,7 +1462,7 @@
 			break;
 		v_opp = dev_pm_opp_get_voltage(opp);
 
-		if (v_opp <= td->soc->min_millivolts * 1000)
+		if (v_opp <= td->soc->cvb->min_millivolts * 1000)
 			td->dvco_rate_min = dev_pm_opp_get_freq(opp);
 
 		for (;;) {
@@ -1490,7 +1491,7 @@
 
 	if (!td->dvco_rate_min)
 		dev_err(td->dev, "no opp above DFLL minimum voltage %d mV\n",
-			td->soc->min_millivolts);
+			td->soc->cvb->min_millivolts);
 	else
 		ret = 0;
 
diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h
index 2e4c077..ed2ad88 100644
--- a/drivers/clk/tegra/clk-dfll.h
+++ b/drivers/clk/tegra/clk-dfll.h
@@ -24,22 +24,18 @@
 
 /**
  * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver
- * @opp_dev: struct device * that holds the OPP table for the DFLL
- * @min_millivolts: minimum voltage (in mV) that the DFLL can operate
- * @tune0_low: DFLL tuning register 0 (low voltage range)
- * @tune0_high: DFLL tuning register 0 (high voltage range)
- * @tune1: DFLL tuning register 1
- * @assert_dvco_reset: fn ptr to place the DVCO in reset
- * @deassert_dvco_reset: fn ptr to release the DVCO reset
- * @set_clock_trimmers_high: fn ptr to tune clock trimmers for high voltage
- * @set_clock_trimmers_low: fn ptr to tune clock trimmers for low voltage
+ * @dev: struct device * that holds the OPP table for the DFLL
+ * @max_freq: maximum frequency supported on this SoC
+ * @cvb: CPU frequency table for this SoC
+ * @init_clock_trimmers: callback to initialize clock trimmers
+ * @set_clock_trimmers_high: callback to tune clock trimmers for high voltage
+ * @set_clock_trimmers_low: callback to tune clock trimmers for low voltage
  */
 struct tegra_dfll_soc_data {
 	struct device *dev;
-	unsigned int min_millivolts;
-	u32 tune0_low;
-	u32 tune0_high;
-	u32 tune1;
+	unsigned long max_freq;
+	const struct cvb_table *cvb;
+
 	void (*init_clock_trimmers)(void);
 	void (*set_clock_trimmers_high)(void);
 	void (*set_clock_trimmers_low)(void);
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index 62ea381..36c9749 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -71,6 +71,7 @@
 	tegra_clk_disp2_8,
 	tegra_clk_dp2,
 	tegra_clk_dpaux,
+	tegra_clk_dpaux1,
 	tegra_clk_dsialp,
 	tegra_clk_dsia_mux,
 	tegra_clk_dsiblp,
@@ -306,6 +307,7 @@
 	tegra_clk_xusb_ss_div2,
 	tegra_clk_xusb_ssp_src,
 	tegra_clk_sclk_mux,
+	tegra_clk_sor_safe,
 	tegra_clk_max,
 };
 
diff --git a/drivers/clk/tegra/clk-periph-fixed.c b/drivers/clk/tegra/clk-periph-fixed.c
new file mode 100644
index 0000000..c57dfb0
--- /dev/null
+++ b/drivers/clk/tegra/clk-periph-fixed.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2015, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk-provider.h>
+
+#include "clk.h"
+
+static inline struct tegra_clk_periph_fixed *
+to_tegra_clk_periph_fixed(struct clk_hw *hw)
+{
+	return container_of(hw, struct tegra_clk_periph_fixed, hw);
+}
+
+static int tegra_clk_periph_fixed_is_enabled(struct clk_hw *hw)
+{
+	struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
+	u32 mask = 1 << (fixed->num % 32), value;
+
+	value = readl(fixed->base + fixed->regs->enb_reg);
+	if (value & mask) {
+		value = readl(fixed->base + fixed->regs->rst_reg);
+		if ((value & mask) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+static int tegra_clk_periph_fixed_enable(struct clk_hw *hw)
+{
+	struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
+	u32 mask = 1 << (fixed->num % 32);
+
+	writel(mask, fixed->base + fixed->regs->enb_set_reg);
+
+	return 0;
+}
+
+static void tegra_clk_periph_fixed_disable(struct clk_hw *hw)
+{
+	struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
+	u32 mask = 1 << (fixed->num % 32);
+
+	writel(mask, fixed->base + fixed->regs->enb_clr_reg);
+}
+
+static unsigned long
+tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw,
+				   unsigned long parent_rate)
+{
+	struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
+	unsigned long long rate;
+
+	rate = (unsigned long long)parent_rate * fixed->mul;
+	do_div(rate, fixed->div);
+
+	return (unsigned long)rate;
+}
+
+static const struct clk_ops tegra_clk_periph_fixed_ops = {
+	.is_enabled = tegra_clk_periph_fixed_is_enabled,
+	.enable = tegra_clk_periph_fixed_enable,
+	.disable = tegra_clk_periph_fixed_disable,
+	.recalc_rate = tegra_clk_periph_fixed_recalc_rate,
+};
+
+struct clk *tegra_clk_register_periph_fixed(const char *name,
+					    const char *parent,
+					    unsigned long flags,
+					    void __iomem *base,
+					    unsigned int mul,
+					    unsigned int div,
+					    unsigned int num)
+{
+	const struct tegra_clk_periph_regs *regs;
+	struct tegra_clk_periph_fixed *fixed;
+	struct clk_init_data init;
+	struct clk *clk;
+
+	regs = get_reg_bank(num);
+	if (!regs)
+		return ERR_PTR(-EINVAL);
+
+	fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
+	if (!fixed)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.flags = flags;
+	init.parent_names = parent ? &parent : NULL;
+	init.num_parents = parent ? 1 : 0;
+	init.ops = &tegra_clk_periph_fixed_ops;
+
+	fixed->base = base;
+	fixed->regs = regs;
+	fixed->mul = mul;
+	fixed->div = div;
+	fixed->num = num;
+
+	fixed->hw.init = &init;
+
+	clk = clk_register(NULL, &fixed->hw);
+	if (IS_ERR(clk))
+		kfree(fixed);
+
+	return clk;
+}
diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c
index d28d6e9..8812782 100644
--- a/drivers/clk/tegra/clk-periph-gate.c
+++ b/drivers/clk/tegra/clk-periph-gate.c
@@ -134,7 +134,7 @@
 	struct tegra_clk_periph_gate *gate;
 	struct clk *clk;
 	struct clk_init_data init;
-	struct tegra_clk_periph_regs *pregs;
+	const struct tegra_clk_periph_regs *pregs;
 
 	pregs = get_reg_bank(clk_num);
 	if (!pregs)
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
index ec5b611..a17ca6d 100644
--- a/drivers/clk/tegra/clk-periph.c
+++ b/drivers/clk/tegra/clk-periph.c
@@ -145,7 +145,7 @@
 {
 	struct clk *clk;
 	struct clk_init_data init;
-	struct tegra_clk_periph_regs *bank;
+	const struct tegra_clk_periph_regs *bank;
 	bool div = !(periph->gate.flags & TEGRA_PERIPH_NO_DIV);
 
 	if (periph->gate.flags & TEGRA_PERIPH_NO_DIV) {
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 6ac3f84..4e194ec 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -2013,6 +2013,52 @@
 #endif
 
 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
+struct clk *tegra_clk_register_pllre_tegra210(const char *name,
+			  const char *parent_name, void __iomem *clk_base,
+			  void __iomem *pmc, unsigned long flags,
+			  struct tegra_clk_pll_params *pll_params,
+			  spinlock_t *lock, unsigned long parent_rate)
+{
+	u32 val;
+	struct tegra_clk_pll *pll;
+	struct clk *clk;
+
+	pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+	if (pll_params->adjust_vco)
+		pll_params->vco_min = pll_params->adjust_vco(pll_params,
+							     parent_rate);
+
+	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
+	if (IS_ERR(pll))
+		return ERR_CAST(pll);
+
+	/* program minimum rate by default */
+
+	val = pll_readl_base(pll);
+	if (val & PLL_BASE_ENABLE)
+		WARN_ON(readl_relaxed(clk_base + pll_params->iddq_reg) &
+				BIT(pll_params->iddq_bit_idx));
+	else {
+		val = 0x4 << divm_shift(pll);
+		val |= 0x41 << divn_shift(pll);
+		pll_writel_base(val, pll);
+	}
+
+	/* disable lock override */
+
+	val = pll_readl_misc(pll);
+	val &= ~BIT(29);
+	pll_writel_misc(val, pll);
+
+	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+				      &tegra_clk_pllre_ops);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
+
 static int clk_plle_tegra210_enable(struct clk_hw *hw)
 {
 	struct tegra_clk_pll *pll = to_clk_pll(hw);
diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c
index d64ec7a..91c38f1 100644
--- a/drivers/clk/tegra/clk-tegra-fixed.c
+++ b/drivers/clk/tegra/clk-tegra-fixed.c
@@ -107,4 +107,3 @@
 		*dt_clk = clk;
 	}
 }
-
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index ea2b9cbf..29d04c6 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -803,7 +803,7 @@
 	GATE("hda2hdmi", "clk_m", 128, TEGRA_PERIPH_ON_APB, tegra_clk_hda2hdmi, 0),
 	GATE("bsea", "clk_m", 62, 0, tegra_clk_bsea, 0),
 	GATE("bsev", "clk_m", 63, 0, tegra_clk_bsev, 0),
-	GATE("mipi-cal", "clk_m", 56, 0, tegra_clk_mipi_cal, 0),
+	GATE("mipi-cal", "clk72mhz", 56, 0, tegra_clk_mipi_cal, 0),
 	GATE("usbd", "clk_m", 22, 0, tegra_clk_usbd, 0),
 	GATE("usb2", "clk_m", 58, 0, tegra_clk_usb2, 0),
 	GATE("usb3", "clk_m", 59, 0, tegra_clk_usb3, 0),
@@ -821,7 +821,6 @@
 	GATE("ispb", "clk_m", 3, 0, tegra_clk_ispb, 0),
 	GATE("vim2_clk", "clk_m", 11, 0, tegra_clk_vim2_clk, 0),
 	GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0),
-	GATE("dpaux", "clk_m", 181, 0, tegra_clk_dpaux, 0),
 	GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0),
 	GATE("pllg_ref", "pll_ref", 189, 0, tegra_clk_pll_g_ref, 0),
 	GATE("hsic_trk", "usb2_hsic_trk", 209, TEGRA_PERIPH_NO_RESET, tegra_clk_hsic_trk, 0),
@@ -877,7 +876,7 @@
 	struct clk **dt_clk;
 
 	for (i = 0; i < ARRAY_SIZE(periph_clks); i++) {
-		struct tegra_clk_periph_regs *bank;
+		const struct tegra_clk_periph_regs *bank;
 		struct tegra_periph_init_data *data;
 
 		data = periph_clks + i;
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index df47ec3..b78054f 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -743,7 +743,6 @@
 	[tegra_clk_csi] = { .dt_id = TEGRA114_CLK_CSI, .present = true },
 	[tegra_clk_i2c2] = { .dt_id = TEGRA114_CLK_I2C2, .present = true },
 	[tegra_clk_uartc] = { .dt_id = TEGRA114_CLK_UARTC, .present = true },
-	[tegra_clk_mipi_cal] = { .dt_id = TEGRA114_CLK_MIPI_CAL, .present = true },
 	[tegra_clk_emc] = { .dt_id = TEGRA114_CLK_EMC, .present = true },
 	[tegra_clk_usb2] = { .dt_id = TEGRA114_CLK_USB2, .present = true },
 	[tegra_clk_usb3] = { .dt_id = TEGRA114_CLK_USB3, .present = true },
@@ -1237,6 +1236,11 @@
 				    &emc_lock);
 	clks[TEGRA114_CLK_MC] = clk;
 
+	clk = tegra_clk_register_periph_gate("mipi-cal", "clk_m", 0, clk_base,
+					     CLK_SET_RATE_PARENT, 56,
+					     periph_clk_enb_refcnt);
+	clks[TEGRA114_CLK_MIPI_CAL] = clk;
+
 	for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) {
 		data = &tegra_periph_clk_list[i];
 		clk = tegra_clk_register_periph(data->name,
diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
index 6125333..c205809 100644
--- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
+++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
@@ -47,32 +47,32 @@
 		},
 		.speedo_scale = 100,
 		.voltage_scale = 1000,
-		.cvb_table = {
-			{204000000UL,   {1112619, -29295, 402} },
-			{306000000UL,	{1150460, -30585, 402} },
-			{408000000UL,	{1190122, -31865, 402} },
-			{510000000UL,	{1231606, -33155, 402} },
-			{612000000UL,	{1274912, -34435, 402} },
-			{714000000UL,	{1320040, -35725, 402} },
-			{816000000UL,	{1366990, -37005, 402} },
-			{918000000UL,	{1415762, -38295, 402} },
-			{1020000000UL,	{1466355, -39575, 402} },
-			{1122000000UL,	{1518771, -40865, 402} },
-			{1224000000UL,	{1573009, -42145, 402} },
-			{1326000000UL,	{1629068, -43435, 402} },
-			{1428000000UL,	{1686950, -44715, 402} },
-			{1530000000UL,	{1746653, -46005, 402} },
-			{1632000000UL,	{1808179, -47285, 402} },
-			{1734000000UL,	{1871526, -48575, 402} },
-			{1836000000UL,	{1936696, -49855, 402} },
-			{1938000000UL,	{2003687, -51145, 402} },
-			{2014500000UL,	{2054787, -52095, 402} },
-			{2116500000UL,	{2124957, -53385, 402} },
-			{2218500000UL,	{2196950, -54665, 402} },
-			{2320500000UL,	{2270765, -55955, 402} },
-			{2422500000UL,	{2346401, -57235, 402} },
-			{2524500000UL,	{2437299, -58535, 402} },
-			{0,		{      0,      0,   0} },
+		.entries = {
+			{  204000000UL, { 1112619, -29295, 402 } },
+			{  306000000UL, { 1150460, -30585, 402 } },
+			{  408000000UL, { 1190122, -31865, 402 } },
+			{  510000000UL, { 1231606, -33155, 402 } },
+			{  612000000UL, { 1274912, -34435, 402 } },
+			{  714000000UL, { 1320040, -35725, 402 } },
+			{  816000000UL, { 1366990, -37005, 402 } },
+			{  918000000UL, { 1415762, -38295, 402 } },
+			{ 1020000000UL, { 1466355, -39575, 402 } },
+			{ 1122000000UL, { 1518771, -40865, 402 } },
+			{ 1224000000UL, { 1573009, -42145, 402 } },
+			{ 1326000000UL, { 1629068, -43435, 402 } },
+			{ 1428000000UL, { 1686950, -44715, 402 } },
+			{ 1530000000UL, { 1746653, -46005, 402 } },
+			{ 1632000000UL, { 1808179, -47285, 402 } },
+			{ 1734000000UL, { 1871526, -48575, 402 } },
+			{ 1836000000UL, { 1936696, -49855, 402 } },
+			{ 1938000000UL, { 2003687, -51145, 402 } },
+			{ 2014500000UL, { 2054787, -52095, 402 } },
+			{ 2116500000UL, { 2124957, -53385, 402 } },
+			{ 2218500000UL, { 2196950, -54665, 402 } },
+			{ 2320500000UL, { 2270765, -55955, 402 } },
+			{ 2422500000UL, { 2346401, -57235, 402 } },
+			{ 2524500000UL, { 2437299, -58535, 402 } },
+			{          0UL, {       0,      0,   0 } },
 		},
 		.cpu_dfll_data = {
 			.tune0_low = 0x005020ff,
@@ -84,9 +84,8 @@
 
 static int tegra124_dfll_fcpu_probe(struct platform_device *pdev)
 {
-	int process_id, speedo_id, speedo_value;
+	int process_id, speedo_id, speedo_value, err;
 	struct tegra_dfll_soc_data *soc;
-	const struct cvb_table *cvb;
 
 	process_id = tegra_sku_info.cpu_process_id;
 	speedo_id = tegra_sku_info.cpu_speedo_id;
@@ -108,23 +107,41 @@
 		return -ENODEV;
 	}
 
-	cvb = tegra_cvb_build_opp_table(tegra124_cpu_cvb_tables,
-					ARRAY_SIZE(tegra124_cpu_cvb_tables),
-					process_id, speedo_id, speedo_value,
-					cpu_max_freq_table[speedo_id],
-					soc->dev);
-	if (IS_ERR(cvb)) {
-		dev_err(&pdev->dev, "couldn't build OPP table: %ld\n",
-			PTR_ERR(cvb));
-		return PTR_ERR(cvb);
+	soc->max_freq = cpu_max_freq_table[speedo_id];
+
+	soc->cvb = tegra_cvb_add_opp_table(soc->dev, tegra124_cpu_cvb_tables,
+					   ARRAY_SIZE(tegra124_cpu_cvb_tables),
+					   process_id, speedo_id, speedo_value,
+					   soc->max_freq);
+	if (IS_ERR(soc->cvb)) {
+		dev_err(&pdev->dev, "couldn't add OPP table: %ld\n",
+			PTR_ERR(soc->cvb));
+		return PTR_ERR(soc->cvb);
 	}
 
-	soc->min_millivolts = cvb->min_millivolts;
-	soc->tune0_low = cvb->cpu_dfll_data.tune0_low;
-	soc->tune0_high = cvb->cpu_dfll_data.tune0_high;
-	soc->tune1 = cvb->cpu_dfll_data.tune1;
+	err = tegra_dfll_register(pdev, soc);
+	if (err < 0) {
+		tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq);
+		return err;
+	}
 
-	return tegra_dfll_register(pdev, soc);
+	platform_set_drvdata(pdev, soc);
+
+	return 0;
+}
+
+static int tegra124_dfll_fcpu_remove(struct platform_device *pdev)
+{
+	struct tegra_dfll_soc_data *soc = platform_get_drvdata(pdev);
+	int err;
+
+	err = tegra_dfll_unregister(pdev);
+	if (err < 0)
+		dev_err(&pdev->dev, "failed to unregister DFLL: %d\n", err);
+
+	tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq);
+
+	return 0;
 }
 
 static const struct of_device_id tegra124_dfll_fcpu_of_match[] = {
@@ -140,7 +157,7 @@
 
 static struct platform_driver tegra124_dfll_fcpu_driver = {
 	.probe = tegra124_dfll_fcpu_probe,
-	.remove = tegra_dfll_unregister,
+	.remove = tegra124_dfll_fcpu_remove,
 	.driver = {
 		.name = "tegra124-dfll",
 		.of_match_table = tegra124_dfll_fcpu_of_match,
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index 1627258..f4fbbf1 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -1155,6 +1155,10 @@
 					1, 2);
 	clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk;
 
+	clk = tegra_clk_register_periph_fixed("dpaux", "pll_p", 0, clk_base,
+					      1, 17, 181);
+	clks[TEGRA124_CLK_DPAUX] = clk;
+
 	clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0,
 				clk_base + PLLD_MISC, 30, 0, &pll_d_lock);
 	clks[TEGRA124_CLK_PLL_D_DSI_OUT] = clk;
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 637041f..b855181 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -92,6 +92,7 @@
 #define PLLE_AUX 0x48c
 #define PLLRE_BASE 0x4c4
 #define PLLRE_MISC0 0x4c8
+#define PLLRE_OUT1 0x4cc
 #define PLLDP_BASE 0x590
 #define PLLDP_MISC 0x594
 
@@ -175,6 +176,19 @@
 #define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14)
 #define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12)
 
+#define SATA_PLL_CFG0				0x490
+#define SATA_PLL_CFG0_PADPLL_RESET_SWCTL	BIT(0)
+#define SATA_PLL_CFG0_PADPLL_USE_LOCKDET	BIT(2)
+#define SATA_PLL_CFG0_PADPLL_SLEEP_IDDQ		BIT(13)
+#define SATA_PLL_CFG0_SEQ_ENABLE		BIT(24)
+
+#define XUSBIO_PLL_CFG0				0x51c
+#define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL	BIT(0)
+#define XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL	BIT(2)
+#define XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET	BIT(6)
+#define XUSBIO_PLL_CFG0_PADPLL_SLEEP_IDDQ	BIT(13)
+#define XUSBIO_PLL_CFG0_SEQ_ENABLE		BIT(24)
+
 #define UTMIPLL_HW_PWRDN_CFG0			0x52c
 #define UTMIPLL_HW_PWRDN_CFG0_UTMIPLL_LOCK	BIT(31)
 #define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE	BIT(25)
@@ -416,6 +430,51 @@
 #define PLLU_MISC0_WRITE_MASK		0xbfffffff
 #define PLLU_MISC1_WRITE_MASK		0x00000007
 
+void tegra210_xusb_pll_hw_control_enable(void)
+{
+	u32 val;
+
+	val = readl_relaxed(clk_base + XUSBIO_PLL_CFG0);
+	val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL |
+		 XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL);
+	val |= XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET |
+	       XUSBIO_PLL_CFG0_PADPLL_SLEEP_IDDQ;
+	writel_relaxed(val, clk_base + XUSBIO_PLL_CFG0);
+}
+EXPORT_SYMBOL_GPL(tegra210_xusb_pll_hw_control_enable);
+
+void tegra210_xusb_pll_hw_sequence_start(void)
+{
+	u32 val;
+
+	val = readl_relaxed(clk_base + XUSBIO_PLL_CFG0);
+	val |= XUSBIO_PLL_CFG0_SEQ_ENABLE;
+	writel_relaxed(val, clk_base + XUSBIO_PLL_CFG0);
+}
+EXPORT_SYMBOL_GPL(tegra210_xusb_pll_hw_sequence_start);
+
+void tegra210_sata_pll_hw_control_enable(void)
+{
+	u32 val;
+
+	val = readl_relaxed(clk_base + SATA_PLL_CFG0);
+	val &= ~SATA_PLL_CFG0_PADPLL_RESET_SWCTL;
+	val |= SATA_PLL_CFG0_PADPLL_USE_LOCKDET |
+	       SATA_PLL_CFG0_PADPLL_SLEEP_IDDQ;
+	writel_relaxed(val, clk_base + SATA_PLL_CFG0);
+}
+EXPORT_SYMBOL_GPL(tegra210_sata_pll_hw_control_enable);
+
+void tegra210_sata_pll_hw_sequence_start(void)
+{
+	u32 val;
+
+	val = readl_relaxed(clk_base + SATA_PLL_CFG0);
+	val |= SATA_PLL_CFG0_SEQ_ENABLE;
+	writel_relaxed(val, clk_base + SATA_PLL_CFG0);
+}
+EXPORT_SYMBOL_GPL(tegra210_sata_pll_hw_sequence_start);
+
 static inline void _pll_misc_chk_default(void __iomem *base,
 					struct tegra_clk_pll_params *params,
 					u8 misc_num, u32 default_val, u32 mask)
@@ -2092,6 +2151,7 @@
 	[tegra_clk_clk72Mhz_8] = { .dt_id = TEGRA210_CLK_CLK72MHZ, .present = true },
 	[tegra_clk_vic03_8] = { .dt_id = TEGRA210_CLK_VIC03, .present = true },
 	[tegra_clk_dpaux] = { .dt_id = TEGRA210_CLK_DPAUX, .present = true },
+	[tegra_clk_dpaux1] = { .dt_id = TEGRA210_CLK_DPAUX1, .present = true },
 	[tegra_clk_sor0] = { .dt_id = TEGRA210_CLK_SOR0, .present = true },
 	[tegra_clk_sor0_lvds] = { .dt_id = TEGRA210_CLK_SOR0_LVDS, .present = true },
 	[tegra_clk_gpu] = { .dt_id = TEGRA210_CLK_GPU, .present = true },
@@ -2403,6 +2463,18 @@
 					1, 2);
 	clks[TEGRA210_CLK_XUSB_SS_DIV2] = clk;
 
+	clk = tegra_clk_register_periph_fixed("dpaux", "pll_p", 0, clk_base,
+					      1, 17, 181);
+	clks[TEGRA210_CLK_DPAUX] = clk;
+
+	clk = tegra_clk_register_periph_fixed("dpaux1", "pll_p", 0, clk_base,
+					      1, 17, 207);
+	clks[TEGRA210_CLK_DPAUX1] = clk;
+
+	clk = tegra_clk_register_periph_fixed("sor_safe", "pll_p", 0, clk_base,
+					      1, 17, 222);
+	clks[TEGRA210_CLK_SOR_SAFE] = clk;
+
 	/* pll_d_dsi_out */
 	clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0,
 				clk_base + PLLD_MISC0, 21, 0, &pll_d_lock);
@@ -2582,8 +2654,10 @@
 	clks[TEGRA210_CLK_PLL_D_OUT0] = clk;
 
 	/* PLLRE */
-	clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc,
-			     0, &pll_re_vco_params, &pll_re_lock, pll_ref_freq);
+	clk = tegra_clk_register_pllre_tegra210("pll_re_vco", "pll_ref",
+						clk_base, pmc, 0,
+						&pll_re_vco_params,
+						&pll_re_lock, pll_ref_freq);
 	clk_register_clkdev(clk, "pll_re_vco", NULL);
 	clks[TEGRA210_CLK_PLL_RE_VCO] = clk;
 
@@ -2593,6 +2667,15 @@
 	clk_register_clkdev(clk, "pll_re_out", NULL);
 	clks[TEGRA210_CLK_PLL_RE_OUT] = clk;
 
+	clk = tegra_clk_register_divider("pll_re_out1_div", "pll_re_vco",
+					 clk_base + PLLRE_OUT1, 0,
+					 TEGRA_DIVIDER_ROUND_UP,
+					 8, 8, 1, NULL);
+	clk = tegra_clk_register_pll_out("pll_re_out1", "pll_re_out1_div",
+					 clk_base + PLLRE_OUT1, 1, 0,
+					 CLK_SET_RATE_PARENT, 0, NULL);
+	clks[TEGRA210_CLK_PLL_RE_OUT1] = clk;
+
 	/* PLLE */
 	clk = tegra_clk_register_plle_tegra210("pll_e", "pll_ref",
 				      clk_base, 0, &pll_e_params, NULL);
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 0478565..9396f49 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -339,11 +339,11 @@
 };
 
 static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
-	{ 12000000, 480000000, 960, 12, 1, 12 },
-	{ 13000000, 480000000, 960, 13, 1, 12 },
-	{ 16800000, 480000000, 400,  7, 1,  5 },
-	{ 19200000, 480000000, 200,  4, 1,  3 },
-	{ 26000000, 480000000, 960, 26, 1, 12 },
+	{ 12000000, 480000000, 960, 12, 2, 12 },
+	{ 13000000, 480000000, 960, 13, 2, 12 },
+	{ 16800000, 480000000, 400,  7, 2,  5 },
+	{ 19200000, 480000000, 200,  4, 2,  3 },
+	{ 26000000, 480000000, 960, 26, 2, 12 },
 	{        0,         0,   0,  0, 0,  0 },
 };
 
@@ -1372,6 +1372,7 @@
 	{ TEGRA30_CLK_SBC4, TEGRA30_CLK_PLL_P, 100000000, 0 },
 	{ TEGRA30_CLK_SBC5, TEGRA30_CLK_PLL_P, 100000000, 0 },
 	{ TEGRA30_CLK_SBC6, TEGRA30_CLK_PLL_P, 100000000, 0 },
+	{ TEGRA30_CLK_PLL_C, TEGRA30_CLK_CLK_MAX, 600000000, 0 },
 	{ TEGRA30_CLK_HOST1X, TEGRA30_CLK_PLL_C, 150000000, 0 },
 	{ TEGRA30_CLK_DISP1, TEGRA30_CLK_PLL_P, 600000000, 0 },
 	{ TEGRA30_CLK_DISP2, TEGRA30_CLK_PLL_P, 600000000, 0 },
@@ -1379,6 +1380,7 @@
 	{ TEGRA30_CLK_GR2D, TEGRA30_CLK_PLL_C, 300000000, 0 },
 	{ TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 },
 	{ TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 },
+	{ TEGRA30_CLK_PLL_U, TEGRA30_CLK_CLK_MAX, 480000000, 0 },
 	/* must be the last entry */
 	{ TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
 };
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
index 2a3a4fe..b2cdd9a 100644
--- a/drivers/clk/tegra/clk.c
+++ b/drivers/clk/tegra/clk.c
@@ -84,7 +84,7 @@
 static int (*special_reset_deassert)(unsigned long);
 static unsigned int num_special_reset;
 
-static struct tegra_clk_periph_regs periph_regs[] = {
+static const struct tegra_clk_periph_regs periph_regs[] = {
 	[0] = {
 		.enb_reg = CLK_OUT_ENB_L,
 		.enb_set_reg = CLK_OUT_ENB_SET_L,
@@ -182,7 +182,7 @@
 	return -EINVAL;
 }
 
-struct tegra_clk_periph_regs *get_reg_bank(int clkid)
+const struct tegra_clk_periph_regs *get_reg_bank(int clkid)
 {
 	int reg_bank = clkid / 32;
 
@@ -271,7 +271,7 @@
 	}
 }
 
-static struct reset_control_ops rst_ops = {
+static const struct reset_control_ops rst_ops = {
 	.assert = tegra_clk_rst_assert,
 	.deassert = tegra_clk_rst_deassert,
 };
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 4dbcfae..9421f03 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -386,6 +386,12 @@
 			   struct tegra_clk_pll_params *pll_params,
 			   spinlock_t *lock, unsigned long parent_rate);
 
+struct clk *tegra_clk_register_pllre_tegra210(const char *name,
+			   const char *parent_name, void __iomem *clk_base,
+			   void __iomem *pmc, unsigned long flags,
+			   struct tegra_clk_pll_params *pll_params,
+			   spinlock_t *lock, unsigned long parent_rate);
+
 struct clk *tegra_clk_register_plle_tegra114(const char *name,
 				const char *parent_name,
 				void __iomem *clk_base, unsigned long flags,
@@ -496,7 +502,7 @@
 	u8			flags;
 	int			clk_num;
 	int			*enable_refcnt;
-	struct tegra_clk_periph_regs	*regs;
+	const struct tegra_clk_periph_regs *regs;
 };
 
 #define to_clk_periph_gate(_hw)					\
@@ -516,6 +522,23 @@
 		const char *parent_name, u8 gate_flags, void __iomem *clk_base,
 		unsigned long flags, int clk_num, int *enable_refcnt);
 
+struct tegra_clk_periph_fixed {
+	struct clk_hw hw;
+	void __iomem *base;
+	const struct tegra_clk_periph_regs *regs;
+	unsigned int mul;
+	unsigned int div;
+	unsigned int num;
+};
+
+struct clk *tegra_clk_register_periph_fixed(const char *name,
+					    const char *parent,
+					    unsigned long flags,
+					    void __iomem *base,
+					    unsigned int mul,
+					    unsigned int div,
+					    unsigned int num);
+
 /**
  * struct clk-periph - peripheral clock
  *
@@ -716,7 +739,7 @@
 void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
 		struct clk *clks[], int clk_max);
 
-struct tegra_clk_periph_regs *get_reg_bank(int clkid);
+const struct tegra_clk_periph_regs *get_reg_bank(int clkid);
 struct clk **tegra_clk_init(void __iomem *clk_base, int num, int periph_banks);
 
 struct clk **tegra_lookup_dt_id(int clk_id, struct tegra_clk *tegra_clk);
diff --git a/drivers/clk/tegra/cvb.c b/drivers/clk/tegra/cvb.c
index 69c74ee..624115e 100644
--- a/drivers/clk/tegra/cvb.c
+++ b/drivers/clk/tegra/cvb.c
@@ -61,29 +61,28 @@
 	return mv;
 }
 
-static int build_opp_table(const struct cvb_table *d,
-			   int speedo_value,
-			   unsigned long max_freq,
-			   struct device *opp_dev)
+static int build_opp_table(struct device *dev, const struct cvb_table *table,
+			   int speedo_value, unsigned long max_freq)
 {
+	const struct rail_alignment *align = &table->alignment;
 	int i, ret, dfll_mv, min_mv, max_mv;
-	const struct cvb_table_freq_entry *table = NULL;
-	const struct rail_alignment *align = &d->alignment;
 
-	min_mv = round_voltage(d->min_millivolts, align, UP);
-	max_mv = round_voltage(d->max_millivolts, align, DOWN);
+	min_mv = round_voltage(table->min_millivolts, align, UP);
+	max_mv = round_voltage(table->max_millivolts, align, DOWN);
 
 	for (i = 0; i < MAX_DVFS_FREQS; i++) {
-		table = &d->cvb_table[i];
-		if (!table->freq || (table->freq > max_freq))
+		const struct cvb_table_freq_entry *entry = &table->entries[i];
+
+		if (!entry->freq || (entry->freq > max_freq))
 			break;
 
-		dfll_mv = get_cvb_voltage(
-			speedo_value, d->speedo_scale, &table->coefficients);
-		dfll_mv = round_cvb_voltage(dfll_mv, d->voltage_scale, align);
+		dfll_mv = get_cvb_voltage(speedo_value, table->speedo_scale,
+					  &entry->coefficients);
+		dfll_mv = round_cvb_voltage(dfll_mv, table->voltage_scale,
+					    align);
 		dfll_mv = clamp(dfll_mv, min_mv, max_mv);
 
-		ret = dev_pm_opp_add(opp_dev, table->freq, dfll_mv * 1000);
+		ret = dev_pm_opp_add(dev, entry->freq, dfll_mv * 1000);
 		if (ret)
 			return ret;
 	}
@@ -92,7 +91,7 @@
 }
 
 /**
- * tegra_cvb_build_opp_table - build OPP table from Tegra CVB tables
+ * tegra_cvb_add_opp_table - build OPP table from Tegra CVB tables
  * @cvb_tables: array of CVB tables
  * @sz: size of the previously mentioned array
  * @process_id: process id of the HW module
@@ -108,26 +107,42 @@
  * given @opp_dev. Returns a pointer to the struct cvb_table that matched
  * or an ERR_PTR on failure.
  */
-const struct cvb_table *tegra_cvb_build_opp_table(
-		const struct cvb_table *cvb_tables,
-		size_t sz, int process_id,
-		int speedo_id, int speedo_value,
-		unsigned long max_rate,
-		struct device *opp_dev)
+const struct cvb_table *
+tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *tables,
+			size_t count, int process_id, int speedo_id,
+			int speedo_value, unsigned long max_freq)
 {
-	int i, ret;
+	size_t i;
+	int ret;
 
-	for (i = 0; i < sz; i++) {
-		const struct cvb_table *d = &cvb_tables[i];
+	for (i = 0; i < count; i++) {
+		const struct cvb_table *table = &tables[i];
 
-		if (d->speedo_id != -1 && d->speedo_id != speedo_id)
-			continue;
-		if (d->process_id != -1 && d->process_id != process_id)
+		if (table->speedo_id != -1 && table->speedo_id != speedo_id)
 			continue;
 
-		ret = build_opp_table(d, speedo_value, max_rate, opp_dev);
-		return ret ? ERR_PTR(ret) : d;
+		if (table->process_id != -1 && table->process_id != process_id)
+			continue;
+
+		ret = build_opp_table(dev, table, speedo_value, max_freq);
+		return ret ? ERR_PTR(ret) : table;
 	}
 
 	return ERR_PTR(-EINVAL);
 }
+
+void tegra_cvb_remove_opp_table(struct device *dev,
+				const struct cvb_table *table,
+				unsigned long max_freq)
+{
+	unsigned int i;
+
+	for (i = 0; i < MAX_DVFS_FREQS; i++) {
+		const struct cvb_table_freq_entry *entry = &table->entries[i];
+
+		if (!entry->freq || (entry->freq > max_freq))
+			break;
+
+		dev_pm_opp_remove(dev, entry->freq);
+	}
+}
diff --git a/drivers/clk/tegra/cvb.h b/drivers/clk/tegra/cvb.h
index f62cdc4..c1f0779 100644
--- a/drivers/clk/tegra/cvb.h
+++ b/drivers/clk/tegra/cvb.h
@@ -53,15 +53,16 @@
 
 	int speedo_scale;
 	int voltage_scale;
-	struct cvb_table_freq_entry cvb_table[MAX_DVFS_FREQS];
+	struct cvb_table_freq_entry entries[MAX_DVFS_FREQS];
 	struct cvb_cpu_dfll_data cpu_dfll_data;
 };
 
-const struct cvb_table *tegra_cvb_build_opp_table(
-		const struct cvb_table *cvb_tables,
-		size_t sz, int process_id,
-		int speedo_id, int speedo_value,
-		unsigned long max_rate,
-		struct device *opp_dev);
+const struct cvb_table *
+tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *cvb_tables,
+			size_t count, int process_id, int speedo_id,
+			int speedo_value, unsigned long max_freq);
+void tegra_cvb_remove_opp_table(struct device *dev,
+				const struct cvb_table *table,
+				unsigned long max_freq);
 
 #endif
diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c
index 59ce2fa..294bc03 100644
--- a/drivers/clk/ti/clk-54xx.c
+++ b/drivers/clk/ti/clk-54xx.c
@@ -210,6 +210,7 @@
 	DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"),
 	DT_CLK("omap_wdt", "ick", "dummy_ck"),
 	DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"),
+	DT_CLK(NULL, "sys_clkin_ck", "sys_clkin"),
 	DT_CLK("4ae18000.timer", "timer_sys_ck", "sys_clkin"),
 	DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin"),
 	DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin"),
diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c
index a911d7d..87a87b5 100644
--- a/drivers/clk/ti/clk-7xx.c
+++ b/drivers/clk/ti/clk-7xx.c
@@ -289,6 +289,7 @@
 	DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"),
 	DT_CLK("omap_wdt", "ick", "dummy_ck"),
 	DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"),
+	DT_CLK(NULL, "sys_clkin_ck", "timer_sys_clk_div"),
 	DT_CLK("4ae18000.timer", "timer_sys_ck", "timer_sys_clk_div"),
 	DT_CLK("48032000.timer", "timer_sys_ck", "timer_sys_clk_div"),
 	DT_CLK("48034000.timer", "timer_sys_ck", "timer_sys_clk_div"),
diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c
index 2e14dfb..c773332 100644
--- a/drivers/clk/ti/clk-dra7-atl.c
+++ b/drivers/clk/ti/clk-dra7-atl.c
@@ -265,6 +265,7 @@
 
 		/* Get configuration for the ATL instances */
 		snprintf(prop, sizeof(prop), "atl%u", i);
+		of_node_get(node);
 		cfg_node = of_find_node_by_name(node, prop);
 		if (cfg_node) {
 			ret = of_property_read_u32(cfg_node, "bws",
@@ -278,6 +279,7 @@
 				atl_write(cinfo, DRA7_ATL_AWSMUX_REG(i),
 					  cdesc->aws);
 			}
+			of_node_put(cfg_node);
 		}
 
 		cdesc->probed = true;
diff --git a/drivers/clk/ti/clkt_dflt.c b/drivers/clk/ti/clkt_dflt.c
index 1ddc288..c6ae563 100644
--- a/drivers/clk/ti/clkt_dflt.c
+++ b/drivers/clk/ti/clkt_dflt.c
@@ -222,7 +222,7 @@
 		}
 	}
 
-	if (unlikely(IS_ERR(clk->enable_reg))) {
+	if (IS_ERR(clk->enable_reg)) {
 		pr_err("%s: %s missing enable_reg\n", __func__,
 		       clk_hw_get_name(hw));
 		ret = -EINVAL;
diff --git a/drivers/clk/ti/clkt_dpll.c b/drivers/clk/ti/clkt_dpll.c
index 032c658..b919fdf 100644
--- a/drivers/clk/ti/clkt_dpll.c
+++ b/drivers/clk/ti/clkt_dpll.c
@@ -301,6 +301,9 @@
 
 	dd = clk->dpll_data;
 
+	if (dd->max_rate && target_rate > dd->max_rate)
+		target_rate = dd->max_rate;
+
 	ref_rate = clk_hw_get_rate(dd->clk_ref);
 	clk_name = clk_hw_get_name(hw);
 	pr_debug("clock: %s: starting DPLL round_rate, target rate %lu\n",
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
index 3bc9959..9fc8754 100644
--- a/drivers/clk/ti/dpll.c
+++ b/drivers/clk/ti/dpll.c
@@ -655,6 +655,7 @@
 		.max_multiplier = 2047,
 		.max_divider = 128,
 		.min_divider = 1,
+		.max_rate = 1000000000,
 		.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	};
 
@@ -674,6 +675,7 @@
 		.max_divider = 256,
 		.min_divider = 2,
 		.flags = DPLL_J_TYPE,
+		.max_rate = 2000000000,
 		.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	};
 
@@ -692,6 +694,7 @@
 		.max_multiplier = 2047,
 		.max_divider = 128,
 		.min_divider = 1,
+		.max_rate = 2000000000,
 		.flags = DPLL_J_TYPE,
 		.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	};
@@ -712,6 +715,7 @@
 		.max_multiplier = 2047,
 		.max_divider = 128,
 		.min_divider = 1,
+		.max_rate = 1000000000,
 		.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	};
 
@@ -729,6 +733,7 @@
 		.max_multiplier = 2047,
 		.max_divider = 128,
 		.min_divider = 1,
+		.max_rate = 1000000000,
 		.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	};
 
diff --git a/drivers/clk/zte/clk-zx296702.c b/drivers/clk/zte/clk-zx296702.c
index ebd20d8..76e967c 100644
--- a/drivers/clk/zte/clk-zx296702.c
+++ b/drivers/clk/zte/clk-zx296702.c
@@ -234,8 +234,7 @@
 	WARN_ON(!topcrm_base);
 
 	clk[ZX296702_OSC] =
-		clk_register_fixed_rate(NULL, "osc", NULL, CLK_IS_ROOT,
-				30000000);
+		clk_register_fixed_rate(NULL, "osc", NULL, 0, 30000000);
 	clk[ZX296702_PLL_A9] =
 		clk_register_zx_pll("pll_a9", "osc", 0, topcrm_base
 				+ 0x01c, pll_a9_config,
diff --git a/include/dt-bindings/clock/axis,artpec6-clkctrl.h b/include/dt-bindings/clock/axis,artpec6-clkctrl.h
new file mode 100644
index 0000000..f9f04dc
--- /dev/null
+++ b/include/dt-bindings/clock/axis,artpec6-clkctrl.h
@@ -0,0 +1,38 @@
+/*
+ * ARTPEC-6 clock controller indexes
+ *
+ * Copyright 2016 Axis Comunications AB.
+ *
+ * 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.
+ */
+
+#ifndef DT_BINDINGS_CLK_ARTPEC6_CLKCTRL_H
+#define DT_BINDINGS_CLK_ARTPEC6_CLKCTRL_H
+
+#define ARTPEC6_CLK_CPU			0
+#define ARTPEC6_CLK_CPU_PERIPH		1
+#define ARTPEC6_CLK_NAND_CLKA		2
+#define ARTPEC6_CLK_NAND_CLKB		3
+#define ARTPEC6_CLK_ETH_ACLK		4
+#define ARTPEC6_CLK_DMA_ACLK		5
+#define ARTPEC6_CLK_PTP_REF		6
+#define ARTPEC6_CLK_SD_PCLK		7
+#define ARTPEC6_CLK_SD_IMCLK		8
+#define ARTPEC6_CLK_I2S_HST		9
+#define ARTPEC6_CLK_I2S0_CLK		10
+#define ARTPEC6_CLK_I2S1_CLK		11
+#define ARTPEC6_CLK_UART_PCLK		12
+#define ARTPEC6_CLK_UART_REFCLK		13
+#define ARTPEC6_CLK_I2C			14
+#define ARTPEC6_CLK_SPI_PCLK		15
+#define ARTPEC6_CLK_SPI_SSPCLK		16
+#define ARTPEC6_CLK_SYS_TIMER		17
+#define ARTPEC6_CLK_FRACDIV_IN		18
+#define ARTPEC6_CLK_DBG_PCLK		19
+
+/* This must be the highest clock index plus one. */
+#define ARTPEC6_CLK_NUMCLOCKS		20
+
+#endif
diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h
index 61f1d20..360e00c 100644
--- a/include/dt-bindings/clock/bcm2835.h
+++ b/include/dt-bindings/clock/bcm2835.h
@@ -44,5 +44,23 @@
 #define BCM2835_CLOCK_EMMC		28
 #define BCM2835_CLOCK_PERI_IMAGE	29
 #define BCM2835_CLOCK_PWM		30
+#define BCM2835_CLOCK_PCM		31
 
-#define BCM2835_CLOCK_COUNT		31
+#define BCM2835_PLLA_DSI0		32
+#define BCM2835_PLLA_CCP2		33
+#define BCM2835_PLLD_DSI0		34
+#define BCM2835_PLLD_DSI1		35
+
+#define BCM2835_CLOCK_AVEO		36
+#define BCM2835_CLOCK_DFT		37
+#define BCM2835_CLOCK_GP0		38
+#define BCM2835_CLOCK_GP1		39
+#define BCM2835_CLOCK_GP2		40
+#define BCM2835_CLOCK_SLIM		41
+#define BCM2835_CLOCK_SMI		42
+#define BCM2835_CLOCK_TEC		43
+#define BCM2835_CLOCK_DPI		44
+#define BCM2835_CLOCK_CAM0		45
+#define BCM2835_CLOCK_CAM1		46
+#define BCM2835_CLOCK_DSI0E		47
+#define BCM2835_CLOCK_DSI1E		48
diff --git a/include/dt-bindings/clock/exynos3250.h b/include/dt-bindings/clock/exynos3250.h
index 63d01c1..c796ff0 100644
--- a/include/dt-bindings/clock/exynos3250.h
+++ b/include/dt-bindings/clock/exynos3250.h
@@ -79,6 +79,8 @@
 #define CLK_MOUT_CORE			58
 #define CLK_MOUT_APLL			59
 #define CLK_MOUT_ACLK_266_SUB		60
+#define CLK_MOUT_UART2			61
+#define CLK_MOUT_MMC2			62
 
 /* Dividers */
 #define CLK_DIV_GPL			64
@@ -127,6 +129,9 @@
 #define CLK_DIV_CORE			107
 #define CLK_DIV_HPM			108
 #define CLK_DIV_COPY			109
+#define CLK_DIV_UART2			110
+#define CLK_DIV_MMC2_PRE		111
+#define CLK_DIV_MMC2			112
 
 /* Gates */
 #define CLK_ASYNC_G3D			128
@@ -223,6 +228,8 @@
 #define CLK_BLOCK_MFC			219
 #define CLK_BLOCK_CAM			220
 #define CLK_SMIES			221
+#define CLK_UART2			222
+#define CLK_SDMMC2			223
 
 /* Special clocks */
 #define CLK_SCLK_JPEG			224
@@ -249,12 +256,14 @@
 #define CLK_SCLK_SPI0			245
 #define CLK_SCLK_UART1			246
 #define CLK_SCLK_UART0			247
+#define CLK_SCLK_UART2			248
+#define CLK_SCLK_MMC2			249
 
 /*
  * Total number of clocks of main CMU.
  * NOTE: Must be equal to last clock ID increased by one.
  */
-#define CLK_NR_CLKS			248
+#define CLK_NR_CLKS			250
 
 /*
  * CMU DMC
diff --git a/include/dt-bindings/clock/exynos5420.h b/include/dt-bindings/clock/exynos5420.h
index 7699ee9..17ab839 100644
--- a/include/dt-bindings/clock/exynos5420.h
+++ b/include/dt-bindings/clock/exynos5420.h
@@ -217,8 +217,30 @@
 
 /* divider clocks */
 #define CLK_DOUT_PIXEL		768
+#define CLK_DOUT_ACLK400_WCORE	769
+#define CLK_DOUT_ACLK400_ISP	770
+#define CLK_DOUT_ACLK400_MSCL	771
+#define CLK_DOUT_ACLK200	772
+#define CLK_DOUT_ACLK200_FSYS2	773
+#define CLK_DOUT_ACLK100_NOC	774
+#define CLK_DOUT_PCLK200_FSYS	775
+#define CLK_DOUT_ACLK200_FSYS	776
+#define CLK_DOUT_ACLK333_432_GSCL	777
+#define CLK_DOUT_ACLK333_432_ISP	778
+#define CLK_DOUT_ACLK66		779
+#define CLK_DOUT_ACLK333_432_ISP0	780
+#define CLK_DOUT_ACLK266	781
+#define CLK_DOUT_ACLK166	782
+#define CLK_DOUT_ACLK333	783
+#define CLK_DOUT_ACLK333_G2D	784
+#define CLK_DOUT_ACLK266_G2D	785
+#define CLK_DOUT_ACLK_G3D	786
+#define CLK_DOUT_ACLK300_JPEG	787
+#define CLK_DOUT_ACLK300_DISP1	788
+#define CLK_DOUT_ACLK300_GSCL	789
+#define CLK_DOUT_ACLK400_DISP1	790
 
 /* must be greater than maximal clock id */
-#define CLK_NR_CLKS		769
+#define CLK_NR_CLKS		791
 
 #endif /* _DT_BINDINGS_CLOCK_EXYNOS_5420_H */
diff --git a/include/dt-bindings/clock/imx7d-clock.h b/include/dt-bindings/clock/imx7d-clock.h
index edca8985c..1183347 100644
--- a/include/dt-bindings/clock/imx7d-clock.h
+++ b/include/dt-bindings/clock/imx7d-clock.h
@@ -448,5 +448,6 @@
 #define IMX7D_PLL_DRAM_TEST_DIV		435
 #define IMX7D_ADC_ROOT_CLK		436
 #define IMX7D_CLK_ARM			437
-#define IMX7D_CLK_END			438
+#define IMX7D_CKIL			438
+#define IMX7D_CLK_END			439
 #endif /* __DT_BINDINGS_CLOCK_IMX7D_H */
diff --git a/include/dt-bindings/clock/rk3399-cru.h b/include/dt-bindings/clock/rk3399-cru.h
new file mode 100644
index 0000000..50a44cf
--- /dev/null
+++ b/include/dt-bindings/clock/rk3399-cru.h
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.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.
+ */
+
+#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3399_H
+#define _DT_BINDINGS_CLK_ROCKCHIP_RK3399_H
+
+/* core clocks */
+#define PLL_APLLL			1
+#define PLL_APLLB			2
+#define PLL_DPLL			3
+#define PLL_CPLL			4
+#define PLL_GPLL			5
+#define PLL_NPLL			6
+#define PLL_VPLL			7
+#define ARMCLKL				8
+#define ARMCLKB				9
+
+/* sclk gates (special clocks) */
+#define SCLK_I2C1			65
+#define SCLK_I2C2			66
+#define SCLK_I2C3			67
+#define SCLK_I2C5			68
+#define SCLK_I2C6			69
+#define SCLK_I2C7			70
+#define SCLK_SPI0			71
+#define SCLK_SPI1			72
+#define SCLK_SPI2			73
+#define SCLK_SPI4			74
+#define SCLK_SPI5			75
+#define SCLK_SDMMC			76
+#define SCLK_SDIO			77
+#define SCLK_EMMC			78
+#define SCLK_TSADC			79
+#define SCLK_SARADC			80
+#define SCLK_UART0			81
+#define SCLK_UART1			82
+#define SCLK_UART2			83
+#define SCLK_UART3			84
+#define SCLK_SPDIF_8CH			85
+#define SCLK_I2S0_8CH			86
+#define SCLK_I2S1_8CH			87
+#define SCLK_I2S2_8CH			88
+#define SCLK_I2S_8CH_OUT		89
+#define SCLK_TIMER00			90
+#define SCLK_TIMER01			91
+#define SCLK_TIMER02			92
+#define SCLK_TIMER03			93
+#define SCLK_TIMER04			94
+#define SCLK_TIMER05			95
+#define SCLK_TIMER06			96
+#define SCLK_TIMER07			97
+#define SCLK_TIMER08			98
+#define SCLK_TIMER09			99
+#define SCLK_TIMER10			100
+#define SCLK_TIMER11			101
+#define SCLK_MACREF			102
+#define SCLK_MAC_RX			103
+#define SCLK_MAC_TX			104
+#define SCLK_MAC			105
+#define SCLK_MACREF_OUT			106
+#define SCLK_VOP0_PWM			107
+#define SCLK_VOP1_PWM			108
+#define SCLK_RGA_CORE			109
+#define SCLK_ISP0			110
+#define SCLK_ISP1			111
+#define SCLK_HDMI_CEC			112
+#define SCLK_HDMI_SFR			113
+#define SCLK_DP_CORE			114
+#define SCLK_PVTM_CORE_L		115
+#define SCLK_PVTM_CORE_B		116
+#define SCLK_PVTM_GPU			117
+#define SCLK_PVTM_DDR			118
+#define SCLK_MIPIDPHY_REF		119
+#define SCLK_MIPIDPHY_CFG		120
+#define SCLK_HSICPHY			121
+#define SCLK_USBPHY480M			122
+#define SCLK_USB2PHY0_REF		123
+#define SCLK_USB2PHY1_REF		124
+#define SCLK_UPHY0_TCPDPHY_REF		125
+#define SCLK_UPHY0_TCPDCORE		126
+#define SCLK_UPHY1_TCPDPHY_REF		127
+#define SCLK_UPHY1_TCPDCORE		128
+#define SCLK_USB3OTG0_REF		129
+#define SCLK_USB3OTG1_REF		130
+#define SCLK_USB3OTG0_SUSPEND		131
+#define SCLK_USB3OTG1_SUSPEND		132
+#define SCLK_CRYPTO0			133
+#define SCLK_CRYPTO1			134
+#define SCLK_CCI_TRACE			135
+#define SCLK_CS				136
+#define SCLK_CIF_OUT			137
+#define SCLK_PCIEPHY_REF		138
+#define SCLK_PCIE_CORE			139
+#define SCLK_M0_PERILP			140
+#define SCLK_M0_PERILP_DEC		141
+#define SCLK_CM0S			142
+#define SCLK_DBG_NOC			143
+#define SCLK_DBG_PD_CORE_B		144
+#define SCLK_DBG_PD_CORE_L		145
+#define SCLK_DFIMON0_TIMER		146
+#define SCLK_DFIMON1_TIMER		147
+#define SCLK_INTMEM0			148
+#define SCLK_INTMEM1			149
+#define SCLK_INTMEM2			150
+#define SCLK_INTMEM3			151
+#define SCLK_INTMEM4			152
+#define SCLK_INTMEM5			153
+#define SCLK_SDMMC_DRV			154
+#define SCLK_SDMMC_SAMPLE		155
+#define SCLK_SDIO_DRV			156
+#define SCLK_SDIO_SAMPLE		157
+#define SCLK_VDU_CORE			158
+#define SCLK_VDU_CA			159
+#define SCLK_PCIE_PM			160
+#define SCLK_SPDIF_REC_DPTX		161
+#define SCLK_DPHY_PLL			162
+#define SCLK_DPHY_TX0_CFG		163
+#define SCLK_DPHY_TX1RX1_CFG		164
+#define SCLK_DPHY_RX0_CFG		165
+#define SCLK_RMII_SRC			166
+#define SCLK_PCIEPHY_REF100M		167
+
+#define DCLK_VOP0			180
+#define DCLK_VOP1			181
+#define DCLK_VOP0_DIV			182
+#define DCLK_VOP1_DIV			183
+#define DCLK_M0_PERILP			184
+
+#define FCLK_CM0S			190
+
+/* aclk gates */
+#define ACLK_PERIHP			192
+#define ACLK_PERIHP_NOC			193
+#define ACLK_PERILP0			194
+#define ACLK_PERILP0_NOC		195
+#define ACLK_PERF_PCIE			196
+#define ACLK_PCIE			197
+#define ACLK_INTMEM			198
+#define ACLK_TZMA			199
+#define ACLK_DCF			200
+#define ACLK_CCI			201
+#define ACLK_CCI_NOC0			202
+#define ACLK_CCI_NOC1			203
+#define ACLK_CCI_GRF			204
+#define ACLK_CENTER			205
+#define ACLK_CENTER_MAIN_NOC		206
+#define ACLK_CENTER_PERI_NOC		207
+#define ACLK_GPU			208
+#define ACLK_PERF_GPU			209
+#define ACLK_GPU_GRF			210
+#define ACLK_DMAC0_PERILP		211
+#define ACLK_DMAC1_PERILP		212
+#define ACLK_GMAC			213
+#define ACLK_GMAC_NOC			214
+#define ACLK_PERF_GMAC			215
+#define ACLK_VOP0_NOC			216
+#define ACLK_VOP0			217
+#define ACLK_VOP1_NOC			218
+#define ACLK_VOP1			219
+#define ACLK_RGA			220
+#define ACLK_RGA_NOC			221
+#define ACLK_HDCP			222
+#define ACLK_HDCP_NOC			223
+#define ACLK_HDCP22			224
+#define ACLK_IEP			225
+#define ACLK_IEP_NOC			226
+#define ACLK_VIO			227
+#define ACLK_VIO_NOC			228
+#define ACLK_ISP0			229
+#define ACLK_ISP1			230
+#define ACLK_ISP0_NOC			231
+#define ACLK_ISP1_NOC			232
+#define ACLK_ISP0_WRAPPER		233
+#define ACLK_ISP1_WRAPPER		234
+#define ACLK_VCODEC			235
+#define ACLK_VCODEC_NOC			236
+#define ACLK_VDU			237
+#define ACLK_VDU_NOC			238
+#define ACLK_PERI			239
+#define ACLK_EMMC			240
+#define ACLK_EMMC_CORE			241
+#define ACLK_EMMC_NOC			242
+#define ACLK_EMMC_GRF			243
+#define ACLK_USB3			244
+#define ACLK_USB3_NOC			245
+#define ACLK_USB3OTG0			246
+#define ACLK_USB3OTG1			247
+#define ACLK_USB3_RKSOC_AXI_PERF	248
+#define ACLK_USB3_GRF			249
+#define ACLK_GIC			250
+#define ACLK_GIC_NOC			251
+#define ACLK_GIC_ADB400_CORE_L_2_GIC	252
+#define ACLK_GIC_ADB400_CORE_B_2_GIC	253
+#define ACLK_GIC_ADB400_GIC_2_CORE_L	254
+#define ACLK_GIC_ADB400_GIC_2_CORE_B	255
+#define ACLK_CORE_ADB400_CORE_L_2_CCI500 256
+#define ACLK_CORE_ADB400_CORE_B_2_CCI500 257
+#define ACLK_ADB400M_PD_CORE_L		258
+#define ACLK_ADB400M_PD_CORE_B		259
+#define ACLK_PERF_CORE_L		260
+#define ACLK_PERF_CORE_B		261
+#define ACLK_GIC_PRE			262
+#define ACLK_VOP0_PRE			263
+#define ACLK_VOP1_PRE			264
+
+/* pclk gates */
+#define PCLK_PERIHP			320
+#define PCLK_PERIHP_NOC			321
+#define PCLK_PERILP0			322
+#define PCLK_PERILP1			323
+#define PCLK_PERILP1_NOC		324
+#define PCLK_PERILP_SGRF		325
+#define PCLK_PERIHP_GRF			326
+#define PCLK_PCIE			327
+#define PCLK_SGRF			328
+#define PCLK_INTR_ARB			329
+#define PCLK_CENTER_MAIN_NOC		330
+#define PCLK_CIC			331
+#define PCLK_COREDBG_B			332
+#define PCLK_COREDBG_L			333
+#define PCLK_DBG_CXCS_PD_CORE_B		334
+#define PCLK_DCF			335
+#define PCLK_GPIO2			336
+#define PCLK_GPIO3			337
+#define PCLK_GPIO4			338
+#define PCLK_GRF			339
+#define PCLK_HSICPHY			340
+#define PCLK_I2C1			341
+#define PCLK_I2C2			342
+#define PCLK_I2C3			343
+#define PCLK_I2C5			344
+#define PCLK_I2C6			345
+#define PCLK_I2C7			346
+#define PCLK_SPI0			347
+#define PCLK_SPI1			348
+#define PCLK_SPI2			349
+#define PCLK_SPI4			350
+#define PCLK_SPI5			351
+#define PCLK_UART0			352
+#define PCLK_UART1			353
+#define PCLK_UART2			354
+#define PCLK_UART3			355
+#define PCLK_TSADC			356
+#define PCLK_SARADC			357
+#define PCLK_GMAC			358
+#define PCLK_GMAC_NOC			359
+#define PCLK_TIMER0			360
+#define PCLK_TIMER1			361
+#define PCLK_EDP			362
+#define PCLK_EDP_NOC			363
+#define PCLK_EDP_CTRL			364
+#define PCLK_VIO			365
+#define PCLK_VIO_NOC			366
+#define PCLK_VIO_GRF			367
+#define PCLK_MIPI_DSI0			368
+#define PCLK_MIPI_DSI1			369
+#define PCLK_HDCP			370
+#define PCLK_HDCP_NOC			371
+#define PCLK_HDMI_CTRL			372
+#define PCLK_DP_CTRL			373
+#define PCLK_HDCP22			374
+#define PCLK_GASKET			375
+#define PCLK_DDR			376
+#define PCLK_DDR_MON			377
+#define PCLK_DDR_SGRF			378
+#define PCLK_ISP1_WRAPPER		379
+#define PCLK_WDT			380
+#define PCLK_EFUSE1024NS		381
+#define PCLK_EFUSE1024S			382
+#define PCLK_PMU_INTR_ARB		383
+#define PCLK_MAILBOX0			384
+#define PCLK_USBPHY_MUX_G		385
+#define PCLK_UPHY0_TCPHY_G		386
+#define PCLK_UPHY0_TCPD_G		387
+#define PCLK_UPHY1_TCPHY_G		388
+#define PCLK_UPHY1_TCPD_G		389
+#define PCLK_ALIVE			390
+
+/* hclk gates */
+#define HCLK_PERIHP			448
+#define HCLK_PERILP0			449
+#define HCLK_PERILP1			450
+#define HCLK_PERILP0_NOC		451
+#define HCLK_PERILP1_NOC		452
+#define HCLK_M0_PERILP			453
+#define HCLK_M0_PERILP_NOC		454
+#define HCLK_AHB1TOM			455
+#define HCLK_HOST0			456
+#define HCLK_HOST0_ARB			457
+#define HCLK_HOST1			458
+#define HCLK_HOST1_ARB			459
+#define HCLK_HSIC			460
+#define HCLK_SD				461
+#define HCLK_SDMMC			462
+#define HCLK_SDMMC_NOC			463
+#define HCLK_M_CRYPTO0			464
+#define HCLK_M_CRYPTO1			465
+#define HCLK_S_CRYPTO0			466
+#define HCLK_S_CRYPTO1			467
+#define HCLK_I2S0_8CH			468
+#define HCLK_I2S1_8CH			469
+#define HCLK_I2S2_8CH			470
+#define HCLK_SPDIF			471
+#define HCLK_VOP0_NOC			472
+#define HCLK_VOP0			473
+#define HCLK_VOP1_NOC			474
+#define HCLK_VOP1			475
+#define HCLK_ROM			476
+#define HCLK_IEP			477
+#define HCLK_IEP_NOC			478
+#define HCLK_ISP0			479
+#define HCLK_ISP1			480
+#define HCLK_ISP0_NOC			481
+#define HCLK_ISP1_NOC			482
+#define HCLK_ISP0_WRAPPER		483
+#define HCLK_ISP1_WRAPPER		484
+#define HCLK_RGA			485
+#define HCLK_RGA_NOC			486
+#define HCLK_HDCP			487
+#define HCLK_HDCP_NOC			488
+#define HCLK_HDCP22			489
+#define HCLK_VCODEC			490
+#define HCLK_VCODEC_NOC			491
+#define HCLK_VDU			492
+#define HCLK_VDU_NOC			493
+#define HCLK_SDIO			494
+#define HCLK_SDIO_NOC			495
+#define HCLK_SDIOAUDIO_NOC		496
+
+#define CLK_NR_CLKS			(HCLK_SDIOAUDIO_NOC + 1)
+
+/* pmu-clocks indices */
+
+#define PLL_PPLL			1
+
+#define SCLK_32K_SUSPEND_PMU		2
+#define SCLK_SPI3_PMU			3
+#define SCLK_TIMER12_PMU		4
+#define SCLK_TIMER13_PMU		5
+#define SCLK_UART4_PMU			6
+#define SCLK_PVTM_PMU			7
+#define SCLK_WIFI_PMU			8
+#define SCLK_I2C0_PMU			9
+#define SCLK_I2C4_PMU			10
+#define SCLK_I2C8_PMU			11
+
+#define PCLK_SRC_PMU			19
+#define PCLK_PMU			20
+#define PCLK_PMUGRF_PMU			21
+#define PCLK_INTMEM1_PMU		22
+#define PCLK_GPIO0_PMU			23
+#define PCLK_GPIO1_PMU			24
+#define PCLK_SGRF_PMU			25
+#define PCLK_NOC_PMU			26
+#define PCLK_I2C0_PMU			27
+#define PCLK_I2C4_PMU			28
+#define PCLK_I2C8_PMU			29
+#define PCLK_RKPWM_PMU			30
+#define PCLK_SPI3_PMU			31
+#define PCLK_TIMER_PMU			32
+#define PCLK_MAILBOX_PMU		33
+#define PCLK_UART4_PMU			34
+#define PCLK_WDT_M0_PMU			35
+
+#define FCLK_CM0S_SRC_PMU		44
+#define FCLK_CM0S_PMU			45
+#define SCLK_CM0S_PMU			46
+#define HCLK_CM0S_PMU			47
+#define DCLK_CM0S_PMU			48
+#define PCLK_INTR_ARB_PMU		49
+#define HCLK_NOC_PMU			50
+
+#define CLKPMU_NR_CLKS			(HCLK_NOC_PMU + 1)
+
+/* soft-reset indices */
+
+/* cru_softrst_con0 */
+#define SRST_CORE_L0			0
+#define SRST_CORE_B0			1
+#define SRST_CORE_PO_L0			2
+#define SRST_CORE_PO_B0			3
+#define SRST_L2_L			4
+#define SRST_L2_B			5
+#define SRST_ADB_L			6
+#define SRST_ADB_B			7
+#define SRST_A_CCI			8
+#define SRST_A_CCIM0_NOC		9
+#define SRST_A_CCIM1_NOC		10
+#define SRST_DBG_NOC			11
+
+/* cru_softrst_con1 */
+#define SRST_CORE_L0_T			16
+#define SRST_CORE_L1			17
+#define SRST_CORE_L2			18
+#define SRST_CORE_L3			19
+#define SRST_CORE_PO_L0_T		20
+#define SRST_CORE_PO_L1			21
+#define SRST_CORE_PO_L2			22
+#define SRST_CORE_PO_L3			23
+#define SRST_A_ADB400_GIC2COREL		24
+#define SRST_A_ADB400_COREL2GIC		25
+#define SRST_P_DBG_L			26
+#define SRST_L2_L_T			28
+#define SRST_ADB_L_T			29
+#define SRST_A_RKPERF_L			30
+#define SRST_PVTM_CORE_L		31
+
+/* cru_softrst_con2 */
+#define SRST_CORE_B0_T			32
+#define SRST_CORE_B1			33
+#define SRST_CORE_PO_B0_T		36
+#define SRST_CORE_PO_B1			37
+#define SRST_A_ADB400_GIC2COREB		40
+#define SRST_A_ADB400_COREB2GIC		41
+#define SRST_P_DBG_B			42
+#define SRST_L2_B_T			43
+#define SRST_ADB_B_T			45
+#define SRST_A_RKPERF_B			46
+#define SRST_PVTM_CORE_B		47
+
+/* cru_softrst_con3 */
+#define SRST_A_CCI_T			50
+#define SRST_A_CCIM0_NOC_T		51
+#define SRST_A_CCIM1_NOC_T		52
+#define SRST_A_ADB400M_PD_CORE_B_T	53
+#define SRST_A_ADB400M_PD_CORE_L_T	54
+#define SRST_DBG_NOC_T			55
+#define SRST_DBG_CXCS			56
+#define SRST_CCI_TRACE			57
+#define SRST_P_CCI_GRF			58
+
+/* cru_softrst_con4 */
+#define SRST_A_CENTER_MAIN_NOC		64
+#define SRST_A_CENTER_PERI_NOC		65
+#define SRST_P_CENTER_MAIN		66
+#define SRST_P_DDRMON			67
+#define SRST_P_CIC			68
+#define SRST_P_CENTER_SGRF		69
+#define SRST_DDR0_MSCH			70
+#define SRST_DDRCFG0_MSCH		71
+#define SRST_DDR0			72
+#define SRST_DDRPHY0			73
+#define SRST_DDR1_MSCH			74
+#define SRST_DDRCFG1_MSCH		75
+#define SRST_DDR1			76
+#define SRST_DDRPHY1			77
+#define SRST_DDR_CIC			78
+#define SRST_PVTM_DDR			79
+
+/* cru_softrst_con5 */
+#define SRST_A_VCODEC_NOC		80
+#define SRST_A_VCODEC			81
+#define SRST_H_VCODEC_NOC		82
+#define SRST_H_VCODEC			83
+#define SRST_A_VDU_NOC			88
+#define SRST_A_VDU			89
+#define SRST_H_VDU_NOC			90
+#define SRST_H_VDU			91
+#define SRST_VDU_CORE			92
+#define SRST_VDU_CA			93
+
+/* cru_softrst_con6 */
+#define SRST_A_IEP_NOC			96
+#define SRST_A_VOP_IEP			97
+#define SRST_A_IEP			98
+#define SRST_H_IEP_NOC			99
+#define SRST_H_IEP			100
+#define SRST_A_RGA_NOC			102
+#define SRST_A_RGA			103
+#define SRST_H_RGA_NOC			104
+#define SRST_H_RGA			105
+#define SRST_RGA_CORE			106
+#define SRST_EMMC_NOC			108
+#define SRST_EMMC			109
+#define SRST_EMMC_GRF			110
+
+/* cru_softrst_con7 */
+#define SRST_A_PERIHP_NOC		112
+#define SRST_P_PERIHP_GRF		113
+#define SRST_H_PERIHP_NOC		114
+#define SRST_USBHOST0			115
+#define SRST_HOSTC0_AUX			116
+#define SRST_HOST0_ARB			117
+#define SRST_USBHOST1			118
+#define SRST_HOSTC1_AUX			119
+#define SRST_HOST1_ARB			120
+#define SRST_SDIO0			121
+#define SRST_SDMMC			122
+#define SRST_HSIC			123
+#define SRST_HSIC_AUX			124
+#define SRST_AHB1TOM			125
+#define SRST_P_PERIHP_NOC		126
+#define SRST_HSICPHY			127
+
+/* cru_softrst_con8 */
+#define SRST_A_PCIE			128
+#define SRST_P_PCIE			129
+#define SRST_PCIE_CORE			130
+#define SRST_PCIE_MGMT			131
+#define SRST_PCIE_MGMT_STICKY		132
+#define SRST_PCIE_PIPE			133
+#define SRST_PCIE_PM			134
+#define SRST_PCIEPHY			135
+#define SRST_A_GMAC_NOC			136
+#define SRST_A_GMAC			137
+#define SRST_P_GMAC_NOC			138
+#define SRST_P_GMAC_GRF			140
+#define SRST_HSICPHY_POR		142
+#define SRST_HSICPHY_UTMI		143
+
+/* cru_softrst_con9 */
+#define SRST_USB2PHY0_POR		144
+#define SRST_USB2PHY0_UTMI_PORT0	145
+#define SRST_USB2PHY0_UTMI_PORT1	146
+#define SRST_USB2PHY0_EHCIPHY		147
+#define SRST_UPHY0_PIPE_L00		148
+#define SRST_UPHY0			149
+#define SRST_UPHY0_TCPDPWRUP		150
+#define SRST_USB2PHY1_POR		152
+#define SRST_USB2PHY1_UTMI_PORT0	153
+#define SRST_USB2PHY1_UTMI_PORT1	154
+#define SRST_USB2PHY1_EHCIPHY		155
+#define SRST_UPHY1_PIPE_L00		156
+#define SRST_UPHY1			157
+#define SRST_UPHY1_TCPDPWRUP		158
+
+/* cru_softrst_con10 */
+#define SRST_A_PERILP0_NOC		160
+#define SRST_A_DCF			161
+#define SRST_GIC500			162
+#define SRST_DMAC0_PERILP0		163
+#define SRST_DMAC1_PERILP0		164
+#define SRST_TZMA			165
+#define SRST_INTMEM			166
+#define SRST_ADB400_MST0		167
+#define SRST_ADB400_MST1		168
+#define SRST_ADB400_SLV0		169
+#define SRST_ADB400_SLV1		170
+#define SRST_H_PERILP0			171
+#define SRST_H_PERILP0_NOC		172
+#define SRST_ROM			173
+#define SRST_CRYPTO_S			174
+#define SRST_CRYPTO_M			175
+
+/* cru_softrst_con11 */
+#define SRST_P_DCF			176
+#define SRST_CM0S_NOC			177
+#define SRST_CM0S			178
+#define SRST_CM0S_DBG			179
+#define SRST_CM0S_PO			180
+#define SRST_CRYPTO			181
+#define SRST_P_PERILP1_SGRF		182
+#define SRST_P_PERILP1_GRF		183
+#define SRST_CRYPTO1_S			184
+#define SRST_CRYPTO1_M			185
+#define SRST_CRYPTO1			186
+#define SRST_GIC_NOC			188
+#define SRST_SD_NOC			189
+#define SRST_SDIOAUDIO_BRG		190
+
+/* cru_softrst_con12 */
+#define SRST_H_PERILP1			192
+#define SRST_H_PERILP1_NOC		193
+#define SRST_H_I2S0_8CH			194
+#define SRST_H_I2S1_8CH			195
+#define SRST_H_I2S2_8CH			196
+#define SRST_H_SPDIF_8CH		197
+#define SRST_P_PERILP1_NOC		198
+#define SRST_P_EFUSE_1024		199
+#define SRST_P_EFUSE_1024S		200
+#define SRST_P_I2C0			201
+#define SRST_P_I2C1			202
+#define SRST_P_I2C2			203
+#define SRST_P_I2C3			204
+#define SRST_P_I2C4			205
+#define SRST_P_I2C5			206
+#define SRST_P_MAILBOX0			207
+
+/* cru_softrst_con13 */
+#define SRST_P_UART0			208
+#define SRST_P_UART1			209
+#define SRST_P_UART2			210
+#define SRST_P_UART3			211
+#define SRST_P_SARADC			212
+#define SRST_P_TSADC			213
+#define SRST_P_SPI0			214
+#define SRST_P_SPI1			215
+#define SRST_P_SPI2			216
+#define SRST_P_SPI3			217
+#define SRST_P_SPI4			218
+#define SRST_SPI0			219
+#define SRST_SPI1			220
+#define SRST_SPI2			221
+#define SRST_SPI3			222
+#define SRST_SPI4			223
+
+/* cru_softrst_con14 */
+#define SRST_I2S0_8CH			224
+#define SRST_I2S1_8CH			225
+#define SRST_I2S2_8CH			226
+#define SRST_SPDIF_8CH			227
+#define SRST_UART0			228
+#define SRST_UART1			229
+#define SRST_UART2			230
+#define SRST_UART3			231
+#define SRST_TSADC			232
+#define SRST_I2C0			233
+#define SRST_I2C1			234
+#define SRST_I2C2			235
+#define SRST_I2C3			236
+#define SRST_I2C4			237
+#define SRST_I2C5			238
+#define SRST_SDIOAUDIO_NOC		239
+
+/* cru_softrst_con15 */
+#define SRST_A_VIO_NOC			240
+#define SRST_A_HDCP_NOC			241
+#define SRST_A_HDCP			242
+#define SRST_H_HDCP_NOC			243
+#define SRST_H_HDCP			244
+#define SRST_P_HDCP_NOC			245
+#define SRST_P_HDCP			246
+#define SRST_P_HDMI_CTRL		247
+#define SRST_P_DP_CTRL			248
+#define SRST_S_DP_CTRL			249
+#define SRST_C_DP_CTRL			250
+#define SRST_P_MIPI_DSI0		251
+#define SRST_P_MIPI_DSI1		252
+#define SRST_DP_CORE			253
+#define SRST_DP_I2S			254
+
+/* cru_softrst_con16 */
+#define SRST_GASKET			256
+#define SRST_VIO_GRF			258
+#define SRST_DPTX_SPDIF_REC		259
+#define SRST_HDMI_CTRL			260
+#define SRST_HDCP_CTRL			261
+#define SRST_A_ISP0_NOC			262
+#define SRST_A_ISP1_NOC			263
+#define SRST_H_ISP0_NOC			266
+#define SRST_H_ISP1_NOC			267
+#define SRST_H_ISP0			268
+#define SRST_H_ISP1			269
+#define SRST_ISP0			270
+#define SRST_ISP1			271
+
+/* cru_softrst_con17 */
+#define SRST_A_VOP0_NOC			272
+#define SRST_A_VOP1_NOC			273
+#define SRST_A_VOP0			274
+#define SRST_A_VOP1			275
+#define SRST_H_VOP0_NOC			276
+#define SRST_H_VOP1_NOC			277
+#define SRST_H_VOP0			278
+#define SRST_H_VOP1			279
+#define SRST_D_VOP0			280
+#define SRST_D_VOP1			281
+#define SRST_VOP0_PWM			282
+#define SRST_VOP1_PWM			283
+#define SRST_P_EDP_NOC			284
+#define SRST_P_EDP_CTRL			285
+
+/* cru_softrst_con18 */
+#define SRST_A_GPU			288
+#define SRST_A_GPU_NOC			289
+#define SRST_A_GPU_GRF			290
+#define SRST_PVTM_GPU			291
+#define SRST_A_USB3_NOC			292
+#define SRST_A_USB3_OTG0		293
+#define SRST_A_USB3_OTG1		294
+#define SRST_A_USB3_GRF			295
+#define SRST_PMU			296
+
+/* cru_softrst_con19 */
+#define SRST_P_TIMER0_5			304
+#define SRST_TIMER0			305
+#define SRST_TIMER1			306
+#define SRST_TIMER2			307
+#define SRST_TIMER3			308
+#define SRST_TIMER4			309
+#define SRST_TIMER5			310
+#define SRST_P_TIMER6_11		311
+#define SRST_TIMER6			312
+#define SRST_TIMER7			313
+#define SRST_TIMER8			314
+#define SRST_TIMER9			315
+#define SRST_TIMER10			316
+#define SRST_TIMER11			317
+#define SRST_P_INTR_ARB_PMU		318
+#define SRST_P_ALIVE_SGRF		319
+
+/* cru_softrst_con20 */
+#define SRST_P_GPIO2			320
+#define SRST_P_GPIO3			321
+#define SRST_P_GPIO4			322
+#define SRST_P_GRF			323
+#define SRST_P_ALIVE_NOC		324
+#define SRST_P_WDT0			325
+#define SRST_P_WDT1			326
+#define SRST_P_INTR_ARB			327
+#define SRST_P_UPHY0_DPTX		328
+#define SRST_P_UPHY0_APB		330
+#define SRST_P_UPHY0_TCPHY		332
+#define SRST_P_UPHY1_TCPHY		333
+#define SRST_P_UPHY0_TCPDCTRL		334
+#define SRST_P_UPHY1_TCPDCTRL		335
+
+/* pmu soft-reset indices */
+
+/* pmu_cru_softrst_con0 */
+#define SRST_P_NOC			0
+#define SRST_P_INTMEM			1
+#define SRST_H_CM0S			2
+#define SRST_H_CM0S_NOC			3
+#define SRST_DBG_CM0S			4
+#define SRST_PO_CM0S			5
+#define SRST_P_SPI6			6
+#define SRST_SPI6			7
+#define SRST_P_TIMER_0_1		8
+#define SRST_P_TIMER_0			9
+#define SRST_P_TIMER_1			10
+#define SRST_P_UART4			11
+#define SRST_UART4			12
+#define SRST_P_WDT			13
+
+/* pmu_cru_softrst_con1 */
+#define SRST_P_I2C6			16
+#define SRST_P_I2C7			17
+#define SRST_P_I2C8			18
+#define SRST_P_MAILBOX			19
+#define SRST_P_RKPWM			20
+#define SRST_P_PMUGRF			21
+#define SRST_P_SGRF			22
+#define SRST_P_GPIO0			23
+#define SRST_P_GPIO1			24
+#define SRST_P_CRU			25
+#define SRST_P_INTR			26
+#define SRST_PVTM			27
+#define SRST_I2C6			28
+#define SRST_I2C7			29
+#define SRST_I2C8			30
+
+#endif
diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h
index 0a05b0d..bd3530e 100644
--- a/include/dt-bindings/clock/tegra210-car.h
+++ b/include/dt-bindings/clock/tegra210-car.h
@@ -346,7 +346,7 @@
 #define TEGRA210_CLK_PLL_P_OUT_HSIO 316
 #define TEGRA210_CLK_PLL_P_OUT_XUSB 317
 #define TEGRA210_CLK_XUSB_SSP_SRC 318
-/* 319 */
+#define TEGRA210_CLK_PLL_RE_OUT1 319
 /* 320 */
 /* 321 */
 /* 322 */
diff --git a/include/dt-bindings/clock/vf610-clock.h b/include/dt-bindings/clock/vf610-clock.h
index 56c16aa..4599775 100644
--- a/include/dt-bindings/clock/vf610-clock.h
+++ b/include/dt-bindings/clock/vf610-clock.h
@@ -194,7 +194,11 @@
 #define VF610_PLL7_BYPASS		181
 #define VF610_CLK_SNVS			182
 #define VF610_CLK_DAP			183
-#define VF610_CLK_OCOTP         184
-#define VF610_CLK_END			185
+#define VF610_CLK_OCOTP			184
+#define VF610_CLK_DDRMC			185
+#define VF610_CLK_WKPU			186
+#define VF610_CLK_TCON0			187
+#define VF610_CLK_TCON1			188
+#define VF610_CLK_END			189
 
 #endif /* __DT_BINDINGS_CLOCK_VF610_H */
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 26a8c9b..0c72204 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 */
 #define CLK_RECALC_NEW_RATES	BIT(9) /* recalc rates after notifications */
 #define CLK_SET_RATE_UNGATE	BIT(10) /* clock needs to run to set rate */
+#define CLK_IS_CRITICAL		BIT(11) /* do not gate, ever */
 
 struct clk;
 struct clk_hw;
@@ -282,10 +283,17 @@
 struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		unsigned long fixed_rate);
+struct clk_hw *clk_hw_register_fixed_rate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		unsigned long fixed_rate);
 struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev,
 		const char *name, const char *parent_name, unsigned long flags,
 		unsigned long fixed_rate, unsigned long fixed_accuracy);
 void clk_unregister_fixed_rate(struct clk *clk);
+struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev,
+		const char *name, const char *parent_name, unsigned long flags,
+		unsigned long fixed_rate, unsigned long fixed_accuracy);
+
 void of_fixed_clk_setup(struct device_node *np);
 
 /**
@@ -326,7 +334,12 @@
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 bit_idx,
 		u8 clk_gate_flags, spinlock_t *lock);
+struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock);
 void clk_unregister_gate(struct clk *clk);
+void clk_hw_unregister_gate(struct clk_hw *hw);
 
 struct clk_div_table {
 	unsigned int	val;
@@ -407,12 +420,22 @@
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 shift, u8 width,
 		u8 clk_divider_flags, spinlock_t *lock);
+struct clk_hw *clk_hw_register_divider(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, spinlock_t *lock);
 struct clk *clk_register_divider_table(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 shift, u8 width,
 		u8 clk_divider_flags, const struct clk_div_table *table,
 		spinlock_t *lock);
+struct clk_hw *clk_hw_register_divider_table(struct device *dev,
+		const char *name, const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, const struct clk_div_table *table,
+		spinlock_t *lock);
 void clk_unregister_divider(struct clk *clk);
+void clk_hw_unregister_divider(struct clk_hw *hw);
 
 /**
  * struct clk_mux - multiplexer clock
@@ -463,14 +486,25 @@
 		unsigned long flags,
 		void __iomem *reg, u8 shift, u8 width,
 		u8 clk_mux_flags, spinlock_t *lock);
+struct clk_hw *clk_hw_register_mux(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_mux_flags, spinlock_t *lock);
 
 struct clk *clk_register_mux_table(struct device *dev, const char *name,
 		const char * const *parent_names, u8 num_parents,
 		unsigned long flags,
 		void __iomem *reg, u8 shift, u32 mask,
 		u8 clk_mux_flags, u32 *table, spinlock_t *lock);
+struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags,
+		void __iomem *reg, u8 shift, u32 mask,
+		u8 clk_mux_flags, u32 *table, spinlock_t *lock);
 
 void clk_unregister_mux(struct clk *clk);
+void clk_hw_unregister_mux(struct clk_hw *hw);
 
 void of_fixed_factor_clk_setup(struct device_node *node);
 
@@ -499,6 +533,10 @@
 		const char *parent_name, unsigned long flags,
 		unsigned int mult, unsigned int div);
 void clk_unregister_fixed_factor(struct clk *clk);
+struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
+		const char *name, const char *parent_name, unsigned long flags,
+		unsigned int mult, unsigned int div);
+void clk_hw_unregister_fixed_factor(struct clk_hw *hw);
 
 /**
  * struct clk_fractional_divider - adjustable fractional divider clock
@@ -533,6 +571,11 @@
 		const char *name, const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
 		u8 clk_divider_flags, spinlock_t *lock);
+struct clk_hw *clk_hw_register_fractional_divider(struct device *dev,
+		const char *name, const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
+		u8 clk_divider_flags, spinlock_t *lock);
+void clk_hw_unregister_fractional_divider(struct clk_hw *hw);
 
 /**
  * struct clk_multiplier - adjustable multiplier clock
@@ -604,6 +647,13 @@
 		struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
 		unsigned long flags);
 void clk_unregister_composite(struct clk *clk);
+struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name,
+		const char * const *parent_names, int num_parents,
+		struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
+		struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
+		struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+		unsigned long flags);
+void clk_hw_unregister_composite(struct clk_hw *hw);
 
 /***
  * struct clk_gpio_gate - gpio gated clock
@@ -626,6 +676,10 @@
 struct clk *clk_register_gpio_gate(struct device *dev, const char *name,
 		const char *parent_name, unsigned gpio, bool active_low,
 		unsigned long flags);
+struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name,
+		const char *parent_name, unsigned gpio, bool active_low,
+		unsigned long flags);
+void clk_hw_unregister_gpio_gate(struct clk_hw *hw);
 
 /**
  * struct clk_gpio_mux - gpio controlled clock multiplexer
@@ -641,6 +695,10 @@
 struct clk *clk_register_gpio_mux(struct device *dev, const char *name,
 		const char * const *parent_names, u8 num_parents, unsigned gpio,
 		bool active_low, unsigned long flags);
+struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents, unsigned gpio,
+		bool active_low, unsigned long flags);
+void clk_hw_unregister_gpio_mux(struct clk_hw *hw);
 
 /**
  * clk_register - allocate a new clock, register it and return an opaque cookie
@@ -656,9 +714,15 @@
 struct clk *clk_register(struct device *dev, struct clk_hw *hw);
 struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw);
 
+int __must_check clk_hw_register(struct device *dev, struct clk_hw *hw);
+int __must_check devm_clk_hw_register(struct device *dev, struct clk_hw *hw);
+
 void clk_unregister(struct clk *clk);
 void devm_clk_unregister(struct device *dev, struct clk *clk);
 
+void clk_hw_unregister(struct clk_hw *hw);
+void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw);
+
 /* helper functions */
 const char *__clk_get_name(const struct clk *clk);
 const char *clk_hw_get_name(const struct clk_hw *hw);
@@ -704,6 +768,11 @@
 	unsigned int clk_num;
 };
 
+struct clk_hw_onecell_data {
+	size_t num;
+	struct clk_hw *hws[];
+};
+
 extern struct of_device_id __clk_of_table;
 
 #define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)
@@ -713,15 +782,24 @@
 			struct clk *(*clk_src_get)(struct of_phandle_args *args,
 						   void *data),
 			void *data);
+int of_clk_add_hw_provider(struct device_node *np,
+			   struct clk_hw *(*get)(struct of_phandle_args *clkspec,
+						 void *data),
+			   void *data);
 void of_clk_del_provider(struct device_node *np);
 struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
 				  void *data);
+struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec,
+				    void *data);
 struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
+struct clk_hw *of_clk_hw_onecell_get(struct of_phandle_args *clkspec,
+				     void *data);
 unsigned int of_clk_get_parent_count(struct device_node *np);
 int of_clk_parent_fill(struct device_node *np, const char **parents,
 		       unsigned int size);
 const char *of_clk_get_parent_name(struct device_node *np, int index);
-
+int of_clk_detect_critical(struct device_node *np, int index,
+			    unsigned long *flags);
 void of_clk_init(const struct of_device_id *matches);
 
 #else /* !CONFIG_OF */
@@ -733,17 +811,34 @@
 {
 	return 0;
 }
+static inline int of_clk_add_hw_provider(struct device_node *np,
+			struct clk_hw *(*get)(struct of_phandle_args *clkspec,
+					      void *data),
+			void *data)
+{
+	return 0;
+}
 static inline void of_clk_del_provider(struct device_node *np) {}
 static inline struct clk *of_clk_src_simple_get(
 	struct of_phandle_args *clkspec, void *data)
 {
 	return ERR_PTR(-ENOENT);
 }
+static inline struct clk_hw *
+of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data)
+{
+	return ERR_PTR(-ENOENT);
+}
 static inline struct clk *of_clk_src_onecell_get(
 	struct of_phandle_args *clkspec, void *data)
 {
 	return ERR_PTR(-ENOENT);
 }
+static inline struct clk_hw *
+of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data)
+{
+	return ERR_PTR(-ENOENT);
+}
 static inline int of_clk_get_parent_count(struct device_node *np)
 {
 	return 0;
@@ -758,6 +853,11 @@
 {
 	return NULL;
 }
+static inline int of_clk_detect_critical(struct device_node *np, int index,
+					  unsigned long *flags)
+{
+	return 0;
+}
 static inline void of_clk_init(const struct of_device_id *matches) {}
 #endif /* CONFIG_OF */
 
diff --git a/include/linux/clk/renesas.h b/include/linux/clk/renesas.h
index 7adfd80..ba6fa41 100644
--- a/include/linux/clk/renesas.h
+++ b/include/linux/clk/renesas.h
@@ -24,12 +24,20 @@
 void r8a7779_clocks_init(u32 mode);
 void rcar_gen2_clocks_init(u32 mode);
 
-#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
 void cpg_mstp_add_clk_domain(struct device_node *np);
-int cpg_mstp_attach_dev(struct generic_pm_domain *domain, struct device *dev);
-void cpg_mstp_detach_dev(struct generic_pm_domain *domain, struct device *dev);
+#ifdef CONFIG_CLK_RENESAS_CPG_MSTP
+int cpg_mstp_attach_dev(struct generic_pm_domain *unused, struct device *dev);
+void cpg_mstp_detach_dev(struct generic_pm_domain *unused, struct device *dev);
 #else
-static inline void cpg_mstp_add_clk_domain(struct device_node *np) {}
+#define cpg_mstp_attach_dev	NULL
+#define cpg_mstp_detach_dev	NULL
 #endif
 
+#ifdef CONFIG_CLK_RENESAS_CPG_MSSR
+int cpg_mssr_attach_dev(struct generic_pm_domain *unused, struct device *dev);
+void cpg_mssr_detach_dev(struct generic_pm_domain *unused, struct device *dev);
+#else
+#define cpg_mssr_attach_dev	NULL
+#define cpg_mssr_detach_dev	NULL
+#endif
 #endif
diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h
index 57bf7aa..7007a5f 100644
--- a/include/linux/clk/tegra.h
+++ b/include/linux/clk/tegra.h
@@ -121,4 +121,9 @@
 }
 #endif
 
+extern void tegra210_xusb_pll_hw_control_enable(void);
+extern void tegra210_xusb_pll_hw_sequence_start(void);
+extern void tegra210_sata_pll_hw_control_enable(void);
+extern void tegra210_sata_pll_hw_sequence_start(void);
+
 #endif /* __LINUX_CLK_TEGRA_H_ */
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
index dc5164a..6110fe0 100644
--- a/include/linux/clk/ti.h
+++ b/include/linux/clk/ti.h
@@ -37,6 +37,7 @@
  * @last_rounded_n: cache of the last N result of omap2_dpll_round_rate()
  * @min_divider: minimum valid non-bypass divider value (actual)
  * @max_divider: maximum valid non-bypass divider value (actual)
+ * @max_rate: maximum clock rate for the DPLL
  * @modes: possible values of @enable_mask
  * @autoidle_reg: register containing the DPLL autoidle mode bitfield
  * @idlest_reg: register containing the DPLL idle status bitfield
@@ -81,6 +82,7 @@
 	u8			last_rounded_n;
 	u8			min_divider;
 	u16			max_divider;
+	unsigned long		max_rate;
 	u8			modes;
 	void __iomem		*autoidle_reg;
 	void __iomem		*idlest_reg;
diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h
index c2c04f7..2eabc86 100644
--- a/include/linux/clkdev.h
+++ b/include/linux/clkdev.h
@@ -15,6 +15,7 @@
 #include <asm/clkdev.h>
 
 struct clk;
+struct clk_hw;
 struct device;
 
 struct clk_lookup {
@@ -34,18 +35,22 @@
 
 struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
 	const char *dev_fmt, ...) __printf(3, 4);
+struct clk_lookup *clkdev_hw_alloc(struct clk_hw *hw, const char *con_id,
+	const char *dev_fmt, ...) __printf(3, 4);
 
 void clkdev_add(struct clk_lookup *cl);
 void clkdev_drop(struct clk_lookup *cl);
 
 struct clk_lookup *clkdev_create(struct clk *clk, const char *con_id,
 	const char *dev_fmt, ...) __printf(3, 4);
+struct clk_lookup *clkdev_hw_create(struct clk_hw *hw, const char *con_id,
+	const char *dev_fmt, ...) __printf(3, 4);
 
 void clkdev_add_table(struct clk_lookup *, size_t);
 int clk_add_alias(const char *, const char *, const char *, struct device *);
 
 int clk_register_clkdev(struct clk *, const char *, const char *);
-int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t);
+int clk_hw_register_clkdev(struct clk_hw *, const char *, const char *);
 
 #ifdef CONFIG_COMMON_CLK
 int __clk_get(struct clk *clk);