linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: vw@iommu.org (Wan Zongshun)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 04/10] clk: add Clock driver for nuc970
Date: Sun, 10 Jul 2016 15:27:24 +0800	[thread overview]
Message-ID: <1468135649-19980-5-git-send-email-vw@iommu.org> (raw)
In-Reply-To: <1468135649-19980-1-git-send-email-vw@iommu.org>

This patch is to add clock framework driver for nuc970.
The clock controller generates all clocks for Video, Audio,
CPU, system bus and all functionalities, nuc970 includes
two PLL modules.

Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
---
 drivers/clk/Makefile            |   1 +
 drivers/clk/nuc900/Makefile     |   6 +
 drivers/clk/nuc900/clk-apll.c   | 168 ++++++++
 drivers/clk/nuc900/clk-ccf.h    |  53 +++
 drivers/clk/nuc900/clk-nuc970.c | 925 ++++++++++++++++++++++++++++++++++++++++
 drivers/clk/nuc900/clk-upll.c   |  83 ++++
 6 files changed, 1236 insertions(+)
 create mode 100644 drivers/clk/nuc900/Makefile
 create mode 100644 drivers/clk/nuc900/clk-apll.c
 create mode 100644 drivers/clk/nuc900/clk-ccf.h
 create mode 100644 drivers/clk/nuc900/clk-nuc970.c
 create mode 100644 drivers/clk/nuc900/clk-upll.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index dcc5e69..042377d 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -88,3 +88,4 @@ obj-$(CONFIG_ARCH_ZX)			+= zte/
 obj-$(CONFIG_ARCH_ZYNQ)			+= zynq/
 obj-$(CONFIG_H8300)		+= h8300/
 obj-$(CONFIG_ARC_PLAT_AXS10X)		+= axs10x/
+obj-$(CONFIG_ARCH_W90X900)		+= nuc900/
diff --git a/drivers/clk/nuc900/Makefile b/drivers/clk/nuc900/Makefile
new file mode 100644
index 0000000..a6785ab
--- /dev/null
+++ b/drivers/clk/nuc900/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for nuvoton specific clk
+#
+
+obj-$(CONFIG_SOC_NUC970) += clk-apll.o clk-upll.o clk-nuc970.o
+
diff --git a/drivers/clk/nuc900/clk-apll.c b/drivers/clk/nuc900/clk-apll.c
new file mode 100644
index 0000000..a05aec7
--- /dev/null
+++ b/drivers/clk/nuc900/clk-apll.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+
+#include "clk-ccf.h"
+
+struct clk_apll {
+	struct clk_hw	hw;
+	void __iomem	*base;
+};
+
+#define to_clk_apll(clk) (container_of(clk, struct clk_apll, clk))
+
+static int clk_apll_set_rate(struct clk_hw *hw, unsigned long rate,
+			     unsigned long parent_rate)
+{
+	struct clk_apll *pll = to_clk_apll(hw);
+	unsigned long reg;
+
+	reg = readl(pll->base) & ~0x0FFFFFFF;
+
+	switch (rate) {
+	/*usbh*/
+	case 96000000:
+		reg |= 0x8027;
+		break;
+	/*i2s*/
+	case 98400000:
+		reg |= 0x8028;
+		break;
+	/*i2s*/
+	case 169500000:
+		reg |= 0x21f0;
+		break;
+	/*system default, 264MHz*/
+	case 264000000:
+		reg |= 0x15;
+		break;
+	case 300000000:
+		reg |= 0x18;
+		break;
+	default:
+		reg |= 0x15;
+		break;
+	}
+
+	writel(reg, pll->base);
+
+	return 0;
+}
+
+static unsigned long clk_apll_recalc_rate(struct clk_hw *hw,
+					  unsigned long parent_rate)
+{
+	struct clk_apll *pll = to_clk_apll(hw);
+	unsigned long reg = readl(pll->base) & 0x0FFFFFFF;
+	unsigned long rate;
+
+	if (parent_rate != 12000000)
+		return 0;
+
+	switch (reg) {
+	/*system default, 264MHz*/
+	case 0x15:
+		rate = 264000000;
+		break;
+	case 0x18:
+		rate = 300000000;
+		break;
+	/*usbh*/
+	case 0x8027:
+		rate = 96000000;
+		break;
+	/*i2s*/
+	case 0x8028:
+		rate = 98400000;
+		break;
+	/*i2s*/
+	case 0x21f0:
+		rate = 169500000;
+		break;
+	default:
+		rate = 264000000;
+		break;
+	}
+
+	return rate;
+}
+
+static long clk_apll_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	return rate;
+}
+
+static int clk_apll_enable(struct clk_hw *hw)
+{
+	struct clk_apll *pll = to_clk_apll(hw);
+	unsigned long val;
+
+	val = readl(pll->base);
+	val &= ~0x10000000;
+	val |= 0x40000000;
+	writel(val, pll->base);
+
+	return 0;
+}
+
+static void clk_apll_disable(struct clk_hw *hw)
+{
+	struct clk_apll *pll = to_clk_apll(hw);
+	unsigned long val;
+
+	val = readl(pll->base);
+	val |= 0x10000000;
+	val &= ~0x40000000;
+	writel(val, pll->base);
+}
+
+static struct clk_ops clk_apll_ops = {
+	.recalc_rate = clk_apll_recalc_rate,
+	.enable = clk_apll_enable,
+	.disable = clk_apll_disable,
+	.set_rate = clk_apll_set_rate,
+	.round_rate = clk_apll_round_rate,
+};
+
+struct clk *nuc970_clk_apll(const char *name, const char *parent,
+			    void __iomem *base)
+{
+	struct clk_apll *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	pll->base = base;
+
+	init.name = name;
+	init.ops = &clk_apll_ops;
+	init.flags = 0;
+	init.parent_names = &parent;
+	init.num_parents = 1;
+
+	pll->hw.init = &init;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
diff --git a/drivers/clk/nuc900/clk-ccf.h b/drivers/clk/nuc900/clk-ccf.h
new file mode 100644
index 0000000..2808933
--- /dev/null
+++ b/drivers/clk/nuc900/clk-ccf.h
@@ -0,0 +1,53 @@
+#ifndef __MACH_NUC970_CLK_H
+#define __MACH_NUC970_CLK_H
+
+#include <linux/spinlock.h>
+#include <linux/clk-provider.h>
+
+static spinlock_t nuc970_lock;
+
+extern struct clk *nuc970_clk_apll(const char *name, const char *parent,
+				   void __iomem *base);
+extern struct clk *nuc970_clk_upll(const char *name, const char *parent,
+				   void __iomem *base);
+
+static inline struct clk *nuc970_clk_fixed(const char *name, int rate)
+{
+	return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
+}
+
+static inline struct clk *nuc970_clk_mux(const char *name, void __iomem *reg,
+					 u8 shift, u8 width,
+					 const char * const *parents,
+					 int num_parents)
+{
+	return clk_register_mux(NULL, name, parents, num_parents, 0, reg, shift,
+				width, 0, &nuc970_lock);
+}
+
+static inline struct clk *nuc970_clk_divider(const char *name,
+					     const char *parent,
+					     void __iomem *reg, u8 shift,
+					     u8 width)
+{
+	return clk_register_divider(NULL, name, parent, 0,
+				    reg, shift, width, 0, &nuc970_lock);
+}
+
+static inline struct clk *nuc970_clk_fixed_factor(const char *name,
+						  const char *parent,
+						  unsigned int mult,
+						  unsigned int div)
+{
+	return clk_register_fixed_factor(NULL, name, parent,
+					 CLK_SET_RATE_PARENT, mult, div);
+}
+
+static inline struct clk *nuc970_clk_gate(const char *name, const char *parent,
+					  void __iomem *reg, u8 shift)
+{
+	return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+				 shift, 0, &nuc970_lock);
+}
+
+#endif
diff --git a/drivers/clk/nuc900/clk-nuc970.c b/drivers/clk/nuc900/clk-nuc970.c
new file mode 100644
index 0000000..55f02c8
--- /dev/null
+++ b/drivers/clk/nuc900/clk-nuc970.c
@@ -0,0 +1,925 @@
+/*
+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <dt-bindings/clock/nuc970-clock.h>
+#include "clk-ccf.h"
+
+/* Clock Control Registers  */
+static void __iomem *clkctrl;
+#define CLK_BA clkctrl
+
+#define REG_CLK_PMCON	(CLK_BA + 0x000)
+#define REG_CLK_HCLKEN	(CLK_BA + 0x010)
+#define REG_CLK_PCLKEN0	(CLK_BA + 0x018)
+#define REG_CLK_PCLKEN1	(CLK_BA + 0x01C)
+#define REG_CLK_DIV0	(CLK_BA + 0x020)
+#define REG_CLK_DIV1	(CLK_BA + 0x024)
+#define REG_CLK_DIV2	(CLK_BA + 0x028)
+#define REG_CLK_DIV3	(CLK_BA + 0x02C)
+#define REG_CLK_DIV4	(CLK_BA + 0x030)
+#define REG_CLK_DIV5	(CLK_BA + 0x034)
+#define REG_CLK_DIV6	(CLK_BA + 0x038)
+#define REG_CLK_DIV7	(CLK_BA + 0x03C)
+#define REG_CLK_DIV8	(CLK_BA + 0x040)
+#define REG_CLK_DIV9	(CLK_BA + 0x044)
+#define REG_CLK_APLLCON	(CLK_BA + 0x060)
+#define REG_CLK_UPLLCON	(CLK_BA + 0x064)
+
+static const char *const sys_sel_clks[] = { "xin",
+					    "dummy",
+					    "apll",
+					    "upll" };
+
+static const char *const lcd_sel_clks[] = { "xin",
+					    "dummy",
+					    "lcd_aplldiv",
+					    "lcd_uplldiv" };
+
+static const char *const audio_sel_clks[] = { "xin",
+					      "dummy",
+					      "audio_aplldiv",
+					      "audio_uplldiv" };
+
+static const char *const usb_sel_clks[] = { "xin",
+					    "dummy",
+					    "usb_aplldiv",
+					    "usb_uplldiv" };
+
+static const char *const adc_sel_clks[] = { "xin",
+					    "dummy",
+					    "adc_aplldiv",
+					    "adc_uplldiv" };
+
+static const char *const cap_sel_clks[] = { "xin",
+					    "dummy",
+					    "cap_aplldiv",
+					    "cap_uplldiv" };
+
+static const char *const sdh_sel_clks[] = { "xin",
+					    "dummy",
+					    "sdh_aplldiv",
+					    "sdh_uplldiv" };
+
+static const char *const emmc_sel_clks[] = { "xin",
+					     "dummy",
+					     "emmc_aplldiv",
+					     "emmc_uplldiv" };
+
+static const char *const uart0_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart0_aplldiv",
+					      "uart0_uplldiv" };
+
+static const char *const uart1_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart1_aplldiv",
+					      "uart1_uplldiv" };
+
+static const char *const uart2_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart2_aplldiv",
+					      "uart2_uplldiv" };
+
+static const char *const uart3_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart3_aplldiv",
+					      "uart3_uplldiv" };
+
+static const char *const uart4_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart4_aplldiv",
+					      "uart4_uplldiv" };
+
+static const char *const uart5_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart5_aplldiv",
+					      "uart5_uplldiv" };
+
+static const char *const uart6_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart6_aplldiv",
+					      "uart6_uplldiv" };
+
+static const char *const uart7_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart7_aplldiv",
+					      "uart7_uplldiv" };
+
+static const char *const uart8_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart8_aplldiv",
+					      "uart8_uplldiv" };
+
+static const char *const uart9_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart9_aplldiv",
+					      "uart9_uplldiv" };
+
+static const char *const uart10_sel_clks[] = { "xin",
+					       "dummy",
+					       "uart10_aplldiv",
+					       "uart10_uplldiv" };
+
+static const char *const system_sel_clks[] = { "xin",
+					       "dummy",
+					       "system_aplldiv",
+					       "system_uplldiv" };
+
+static const char *const gpio_sel_clks[] = { "xin", "xin32k"};
+static const char *const kpi_sel_clks[] = { "xin", "xin32k"};
+static const char *const etimer_sel_clks[] = { "xin",
+					       "pclk_div",
+					      "pclk4096_div",
+					      "xin32k" };
+
+static const char *const wwdt_sel_clks[] = { "xin",
+					     "xin128_div",
+					     "pclk4096_div",
+					     "xin32k" };
+
+static struct clk *clk[NUC970_CLK_MAX];
+static struct clk_onecell_data clk_data;
+
+static void __init nuc970_clocks_init(struct device_node *np)
+{
+	int i, ret;
+
+	clkctrl = of_iomap(np, 0);
+	if (!clkctrl)
+		pr_err("%s: unable to map registers\n", np->full_name);
+
+
+	/* source */
+	clk[XIN]	= nuc970_clk_fixed("xin", 12000000);
+	clk[XIN32K]	= nuc970_clk_fixed("xin32k", 32768);
+	clk[APLL]	= nuc970_clk_apll("apll", "xin", REG_CLK_APLLCON);
+	clk[UPLL]	= nuc970_clk_upll("upll", "xin", REG_CLK_UPLLCON);
+	clk[XIN128_DIV]	= nuc970_clk_fixed_factor("xin128_div", "xin", 1, 128);
+	clk[SYS_MUX]	= nuc970_clk_mux("sys_mux", REG_CLK_DIV0, 3, 2,
+					 sys_sel_clks,
+					 ARRAY_SIZE(sys_sel_clks));
+	clk[SYS_DIV]	= nuc970_clk_divider("sys_div", "sys_mux",
+					     REG_CLK_DIV0, 0, 2);
+	clk[DDR_GATE]	= nuc970_clk_gate("ddr_gate", "sys_div",
+					  REG_CLK_HCLKEN, 10);
+	/* CPU */
+	clk[CPU_DIV]  = nuc970_clk_divider("cpu_div", "sys_div",
+					   REG_CLK_DIV0, 16, 1);
+	clk[CPU_GATE] = nuc970_clk_gate("cpu_gate", "cpu_div",
+					REG_CLK_HCLKEN, 0);
+	/*HCLK1 & PCLK*/
+	clk[HCLK1_DIV]	= nuc970_clk_fixed_factor("hclk1_div", "cpu_div", 1, 2);
+	clk[GDMA_GATE]	= nuc970_clk_gate("gdma_hclk_gate", "hclk1_div",
+					  REG_CLK_HCLKEN, 12);
+	clk[EBI_GATE]	= nuc970_clk_gate("ebi_hclk_gate", "hclk1_div",
+					  REG_CLK_HCLKEN, 9);
+	clk[TIC_GATE]	= nuc970_clk_gate("tic_hclk_gate", "hclk1_div",
+					  REG_CLK_HCLKEN, 7);
+	/* HCLK & HCLK234 */
+	clk[HCLKN_DIV]		= nuc970_clk_fixed_factor("hclkn_div",
+							  "sys_div", 1, 2);
+	clk[DRAM_GATE]		= nuc970_clk_gate("dram_gate", "hclkn_div",
+						  REG_CLK_HCLKEN, 10);
+	clk[HCLK_GATE]		= nuc970_clk_gate("hclk_gate", "hclkn_div",
+						  REG_CLK_HCLKEN, 1);
+	clk[SRAM_GATE]		= nuc970_clk_gate("sram_gate", "hclk_gate",
+						  REG_CLK_HCLKEN, 8);
+	clk[HCLK234_DIV]	= nuc970_clk_divider("hclk234_div", "hclkn_div",
+						     REG_CLK_DIV0, 20, 4);
+	/* HCLK3 */
+	clk[USBH_GATE]		= nuc970_clk_gate("usbh_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 18);
+	clk[USBD_GATE]		= nuc970_clk_gate("usbd_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 19);
+	clk[FMI_GATE]		= nuc970_clk_gate("fmi_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 20);
+	clk[NAND_GATE]		= nuc970_clk_gate("nand_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 21);
+	clk[EMMC_GATE]		= nuc970_clk_gate("emmc_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 22);
+	clk[CRYPTO_GATE]	= nuc970_clk_gate("crypto_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 23);
+	clk[EMAC1_GATE]		= nuc970_clk_gate("emac1_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 17);
+	clk[EMAC1_ECLK_DIV]	= nuc970_clk_divider("emac1_eclk_div",
+						     "hclk234_div",
+						     REG_CLK_DIV8, 0, 8);
+	clk[EMAC1_ECLK_GATE]	= nuc970_clk_gate("emac1_eclk_gate",
+						  "emac1_eclk_div",
+						  REG_CLK_HCLKEN, 17);
+	clk[JPEG_GATE]		= nuc970_clk_gate("jpeg_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 29);
+	clk[JPEG_ECLK_DIV]	= nuc970_clk_divider("jpeg_eclk_div",
+						     "hclk234_div",
+						     REG_CLK_DIV3, 28, 3);
+	clk[JPEG_ECLK_GATE]	= nuc970_clk_gate("jpeg_eclk_gate",
+						  "jpeg_eclk_div",
+						  REG_CLK_HCLKEN, 29);
+	clk[GE2D_GATE]		= nuc970_clk_gate("ge2d_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 28);
+	clk[GE2D_ECLK_DIV]	= nuc970_clk_divider("ge2d_eclk_div",
+						     "hclk234_div",
+						     REG_CLK_DIV2, 28, 2);
+	clk[GE2D_ECLK_GATE]	= nuc970_clk_gate("ge2d_eclk_gate",
+						  "ge2d_eclk_div",
+						  REG_CLK_HCLKEN, 28);
+	/* HCLK4 */
+	clk[SDH_GATE]		= nuc970_clk_gate("sdh_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 30);
+	clk[AUDIO_GATE]		= nuc970_clk_gate("audio_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 24);
+	clk[LCD_GATE]		= nuc970_clk_gate("lcd_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 25);
+	clk[CAP_GATE]		= nuc970_clk_gate("cap_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 26);
+	clk[SENSOR_GATE]	= nuc970_clk_gate("sensor_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 27);
+	clk[EMAC0_GATE]		= nuc970_clk_gate("emac0_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 16);
+	clk[EMAC0_ECLK_DIV]	= nuc970_clk_divider("emac0_eclk_div",
+						     "hclk234_div",
+						     REG_CLK_DIV8, 0, 8);
+	clk[EMAC0_ECLK_GATE]	= nuc970_clk_gate("emac0_eclk_gate",
+						  "emac0_eclk_div",
+						  REG_CLK_HCLKEN, 16);
+	/* ECLK */
+	/* USB */
+	clk[USB_APLLDIV]	= nuc970_clk_divider("usb_aplldiv", "apll",
+						     REG_CLK_DIV2, 0, 3);
+	clk[USB_UPLLDIV]	= nuc970_clk_divider("usb_uplldiv", "upll",
+						     REG_CLK_DIV2, 0, 3);
+	clk[USB_ECLK_MUX]	= nuc970_clk_mux("usb_eclk_mux", REG_CLK_DIV2,
+						 3, 2, usb_sel_clks,
+						 ARRAY_SIZE(usb_sel_clks));
+	clk[USB_ECLK_DIV]	= nuc970_clk_divider("usb_eclk_div",
+						     "usb_eclk_mux",
+						     REG_CLK_DIV2, 8, 4);
+	clk[USB_ECLK_GATE]	= nuc970_clk_gate("usb_eclk_gate",
+						  "usb_eclk_div",
+						  REG_CLK_HCLKEN, 18);
+	/* SDH */
+	clk[SDH_APLLDIV]	= nuc970_clk_divider("sdh_aplldiv", "apll",
+						     REG_CLK_DIV9, 0, 3);
+	clk[SDH_UPLLDIV]	= nuc970_clk_divider("sdh_uplldiv", "upll",
+						     REG_CLK_DIV9, 0, 3);
+	clk[SDH_ECLK_MUX]	= nuc970_clk_mux("sdh_eclk_mux", REG_CLK_DIV9,
+						 3, 2, sdh_sel_clks,
+						 ARRAY_SIZE(sdh_sel_clks));
+	clk[SDH_ECLK_DIV]	= nuc970_clk_divider("sdh_eclk_div",
+						     "sdh_eclk_mux",
+						     REG_CLK_DIV9, 8, 8);
+	clk[SDH_ECLK_GATE]	= nuc970_clk_gate("sdh_eclk_gate",
+						  "sdh_eclk_div",
+						  REG_CLK_HCLKEN, 30);
+	/* EMMC */
+	clk[EMMC_APLLDIV]	= nuc970_clk_divider("emmc_aplldiv", "apll",
+						     REG_CLK_DIV3, 0, 3);
+	clk[EMMC_UPLLDIV]	= nuc970_clk_divider("emmc_uplldiv", "upll",
+						     REG_CLK_DIV3, 0, 3);
+	clk[EMMC_ECLK_MUX]	= nuc970_clk_mux("emmc_eclk_mux", REG_CLK_DIV3,
+						 3, 2, emmc_sel_clks,
+						 ARRAY_SIZE(emmc_sel_clks));
+	clk[EMMC_ECLK_DIV]	= nuc970_clk_divider("emmc_eclk_div",
+						     "emmc_eclk_mux",
+						     REG_CLK_DIV3, 8, 8);
+	clk[EMMC_ECLK_GATE]	= nuc970_clk_gate("emmc_eclk_gate",
+						  "emmc_eclk_div",
+						  REG_CLK_HCLKEN, 22);
+	/* ADC */
+	clk[ADC_APLLDIV]	= nuc970_clk_divider("adc_aplldiv", "apll",
+						     REG_CLK_DIV7, 16, 3);
+	clk[ADC_UPLLDIV]	= nuc970_clk_divider("adc_uplldiv", "upll",
+						     REG_CLK_DIV7, 16, 3);
+	clk[ADC_ECLK_MUX]	= nuc970_clk_mux("adc_eclk_mux", REG_CLK_DIV7,
+						 19, 2, adc_sel_clks,
+						 ARRAY_SIZE(adc_sel_clks));
+	clk[ADC_ECLK_DIV]	= nuc970_clk_divider("adc_eclk_div",
+						     "adc_eclk_mux",
+						     REG_CLK_DIV7, 24, 8);
+	clk[ADC_ECLK_GATE]	= nuc970_clk_gate("adc_eclk_gate",
+						  "adc_eclk_div",
+						  REG_CLK_PCLKEN1, 24);
+	/* LCD */
+	clk[LCD_APLLDIV]	= nuc970_clk_divider("lcd_aplldiv", "apll",
+						     REG_CLK_DIV1, 0, 3);
+	clk[LCD_UPLLDIV]	= nuc970_clk_divider("lcd_uplldiv", "upll",
+					     REG_CLK_DIV1, 0, 3);
+	clk[LCD_ECLK_MUX]	= nuc970_clk_mux("lcd_eclk_mux", REG_CLK_DIV1,
+						 3, 2, lcd_sel_clks,
+						 ARRAY_SIZE(lcd_sel_clks));
+	clk[LCD_ECLK_DIV]	= nuc970_clk_divider("lcd_eclk_div",
+						     "lcd_eclk_mux",
+						     REG_CLK_DIV1, 8, 8);
+	clk[LCD_ECLK_GATE]	= nuc970_clk_gate("lcd_eclk_gate",
+						  "lcd_eclk_div",
+						  REG_CLK_HCLKEN, 25);
+	/* AUDIO */
+	clk[AUDIO_APLLDIV]	= nuc970_clk_divider("audio_aplldiv", "apll",
+						     REG_CLK_DIV1, 16, 3);
+	clk[AUDIO_UPLLDIV]	= nuc970_clk_divider("audio_uplldiv", "upll",
+						     REG_CLK_DIV1, 16, 3);
+	clk[AUDIO_ECLK_MUX]	= nuc970_clk_mux("audio_eclk_mux", REG_CLK_DIV1,
+						 19, 2, audio_sel_clks,
+						 ARRAY_SIZE(audio_sel_clks));
+	clk[AUDIO_ECLK_DIV]	= nuc970_clk_divider("audio_eclk_div",
+						     "audio_eclk_mux",
+						     REG_CLK_DIV1, 24, 8);
+	clk[AUDIO_ECLK_GATE]	= nuc970_clk_gate("audio_eclk_gate",
+						  "audio_eclk_div",
+						  REG_CLK_HCLKEN, 24);
+	/* CAP */
+	clk[CAP_APLLDIV]	= nuc970_clk_divider("cap_aplldiv", "apll",
+						     REG_CLK_DIV3, 16, 3);
+	clk[CAP_UPLLDIV]	= nuc970_clk_divider("cap_uplldiv", "upll",
+						     REG_CLK_DIV3, 16, 3);
+	clk[CAP_ECLK_MUX]	= nuc970_clk_mux("cap_eclk_mux", REG_CLK_DIV3,
+						 19, 2, cap_sel_clks,
+						 ARRAY_SIZE(cap_sel_clks));
+	clk[CAP_ECLK_DIV]	= nuc970_clk_divider("cap_eclk_div",
+						     "cap_eclk_mux",
+						     REG_CLK_DIV3, 24, 4);
+	clk[CAP_ECLK_GATE]	= nuc970_clk_gate("cap_eclk_gate",
+						  "cap_eclk_div",
+						  REG_CLK_HCLKEN, 26);
+	/* UART0 */
+	clk[UART0_APLLDIV]	= nuc970_clk_divider("uart0_aplldiv",
+						     "apll", REG_CLK_DIV4,
+						     0, 3);
+	clk[UART0_UPLLDIV]	= nuc970_clk_divider("uart0_uplldiv", "upll",
+						     REG_CLK_DIV4, 0, 3);
+	clk[UART0_ECLK_MUX]	= nuc970_clk_mux("uart0_eclk_mux", REG_CLK_DIV4,
+						 3, 2, uart0_sel_clks,
+						 ARRAY_SIZE(uart0_sel_clks));
+	clk[UART0_ECLK_DIV]	= nuc970_clk_divider("uart0_eclk_div",
+						     "uart0_eclk_mux",
+						     REG_CLK_DIV4, 5, 3);
+	clk[UART0_ECLK_GATE]	= nuc970_clk_gate("uart0_eclk_gate",
+						  "uart0_eclk_div",
+						  REG_CLK_PCLKEN0, 16);
+	/* UART1 */
+	clk[UART1_APLLDIV]	= nuc970_clk_divider("uart1_aplldiv", "apll",
+						     REG_CLK_DIV4, 8, 3);
+	clk[UART1_UPLLDIV]	= nuc970_clk_divider("uart1_uplldiv", "upll",
+						     REG_CLK_DIV4, 8, 3);
+	clk[UART1_ECLK_MUX]	= nuc970_clk_mux("uart1_eclk_mux", REG_CLK_DIV4,
+						 11, 2, uart1_sel_clks,
+						 ARRAY_SIZE(uart1_sel_clks));
+	clk[UART1_ECLK_DIV]	= nuc970_clk_divider("uart1_eclk_div",
+						     "uart1_eclk_mux",
+						     REG_CLK_DIV4, 13, 3);
+	clk[UART1_ECLK_GATE]	= nuc970_clk_gate("uart1_eclk_gate",
+						  "uart1_eclk_div",
+						  REG_CLK_PCLKEN0, 17);
+	/* UART2 */
+	clk[UART2_APLLDIV]	= nuc970_clk_divider("uart2_aplldiv", "apll",
+						     REG_CLK_DIV4, 16, 3);
+	clk[UART2_UPLLDIV]	= nuc970_clk_divider("uart2_uplldiv", "upll",
+						     REG_CLK_DIV4, 16, 3);
+	clk[UART2_ECLK_MUX]	= nuc970_clk_mux("uart2_eclk_mux", REG_CLK_DIV4,
+						 19, 2, uart2_sel_clks,
+						 ARRAY_SIZE(uart2_sel_clks));
+	clk[UART2_ECLK_DIV]	= nuc970_clk_divider("uart2_eclk_div",
+						     "uart2_eclk_mux",
+						     REG_CLK_DIV4, 21, 3);
+	clk[UART2_ECLK_GATE]	= nuc970_clk_gate("uart2_eclk_gate",
+						  "uart2_eclk_div",
+						  REG_CLK_PCLKEN0, 18);
+	/* UART3 */
+	clk[UART3_APLLDIV]	= nuc970_clk_divider("uart3_aplldiv", "apll",
+						     REG_CLK_DIV4, 24, 3);
+	clk[UART3_UPLLDIV]	= nuc970_clk_divider("uart3_uplldiv", "upll",
+						     REG_CLK_DIV4, 24, 3);
+	clk[UART3_ECLK_MUX]	= nuc970_clk_mux("uart3_eclk_mux", REG_CLK_DIV4,
+						 27, 2, uart3_sel_clks,
+						 ARRAY_SIZE(uart3_sel_clks));
+	clk[UART3_ECLK_DIV]	= nuc970_clk_divider("uart3_eclk_div",
+						     "uart3_eclk_mux",
+						     REG_CLK_DIV4, 29, 3);
+	clk[UART3_ECLK_GATE]	= nuc970_clk_gate("uart3_eclk_gate",
+						  "uart3_eclk_div",
+						  REG_CLK_PCLKEN0, 19);
+	/* UART4 */
+	clk[UART4_APLLDIV]	= nuc970_clk_divider("uart4_aplldiv", "apll",
+						     REG_CLK_DIV5, 0, 3);
+	clk[UART4_UPLLDIV]	= nuc970_clk_divider("uart4_uplldiv", "upll",
+						     REG_CLK_DIV5, 0, 3);
+	clk[UART4_ECLK_MUX]	= nuc970_clk_mux("uart4_eclk_mux", REG_CLK_DIV5,
+						 3, 2, uart4_sel_clks,
+						 ARRAY_SIZE(uart4_sel_clks));
+	clk[UART4_ECLK_DIV]	= nuc970_clk_divider("uart4_eclk_div",
+						     "uart4_eclk_mux",
+						     REG_CLK_DIV5, 5, 3);
+	clk[UART4_ECLK_GATE]	= nuc970_clk_gate("uart4_eclk_gate",
+						  "uart4_eclk_div",
+						  REG_CLK_PCLKEN0, 20);
+	/* UART5 */
+	clk[UART5_APLLDIV]	= nuc970_clk_divider("uart5_aplldiv", "apll",
+						     REG_CLK_DIV5, 8, 3);
+	clk[UART5_UPLLDIV]	= nuc970_clk_divider("uart5_uplldiv", "upll",
+						     REG_CLK_DIV5, 8, 3);
+	clk[UART5_ECLK_MUX]	= nuc970_clk_mux("uart5_eclk_mux", REG_CLK_DIV5,
+						 11, 2, uart5_sel_clks,
+						 ARRAY_SIZE(uart5_sel_clks));
+	clk[UART5_ECLK_DIV]	= nuc970_clk_divider("uart5_eclk_div",
+						     "uart5_eclk_mux",
+						     REG_CLK_DIV5, 13, 3);
+	clk[UART5_ECLK_GATE]	= nuc970_clk_gate("uart5_eclk_gate",
+						  "uart5_eclk_div",
+						  REG_CLK_PCLKEN0, 21);
+	/* UART6 */
+	clk[UART6_APLLDIV]	= nuc970_clk_divider("uart6_aplldiv", "apll",
+						     REG_CLK_DIV5, 16, 3);
+	clk[UART6_UPLLDIV]	= nuc970_clk_divider("uart6_uplldiv", "upll",
+						     REG_CLK_DIV5, 16, 3);
+	clk[UART6_ECLK_MUX]	= nuc970_clk_mux("uart6_eclk_mux", REG_CLK_DIV5,
+						 19, 2, uart6_sel_clks,
+						 ARRAY_SIZE(uart6_sel_clks));
+	clk[UART6_ECLK_DIV]	= nuc970_clk_divider("uart6_eclk_div",
+						     "uart6_eclk_mux",
+						     REG_CLK_DIV5, 21, 3);
+	clk[UART6_ECLK_GATE]	= nuc970_clk_gate("uart6_eclk_gate",
+						  "uart6_eclk_div",
+						  REG_CLK_PCLKEN0, 22);
+	/* UART7 */
+	clk[UART7_APLLDIV]	= nuc970_clk_divider("uart7_aplldiv", "apll",
+						     REG_CLK_DIV5, 24, 3);
+	clk[UART7_UPLLDIV]	= nuc970_clk_divider("uart7_uplldiv", "upll",
+						     REG_CLK_DIV5, 24, 3);
+	clk[UART7_ECLK_MUX]	= nuc970_clk_mux("uart7_eclk_mux", REG_CLK_DIV5,
+						 27, 2, uart7_sel_clks,
+						 ARRAY_SIZE(uart7_sel_clks));
+	clk[UART7_ECLK_DIV]	= nuc970_clk_divider("uart7_eclk_div",
+						     "uart7_eclk_mux",
+						     REG_CLK_DIV5, 29, 3);
+	clk[UART7_ECLK_GATE]	= nuc970_clk_gate("uart7_eclk_gate",
+						  "uart7_eclk_div",
+						  REG_CLK_PCLKEN0, 23);
+	/* UART8 */
+	clk[UART8_APLLDIV]	= nuc970_clk_divider("uart8_aplldiv", "apll",
+						     REG_CLK_DIV6, 0, 3);
+	clk[UART8_UPLLDIV]	= nuc970_clk_divider("uart8_uplldiv", "upll",
+						     REG_CLK_DIV6, 0, 3);
+	clk[UART8_ECLK_MUX]	= nuc970_clk_mux("uart8_eclk_mux", REG_CLK_DIV6,
+						 3, 2, uart8_sel_clks,
+						 ARRAY_SIZE(uart8_sel_clks));
+	clk[UART8_ECLK_DIV]	= nuc970_clk_divider("uart8_eclk_div",
+						     "uart8_eclk_mux",
+						     REG_CLK_DIV6, 5, 3);
+	clk[UART8_ECLK_GATE]	= nuc970_clk_gate("uart8_eclk_gate",
+						  "uart8_eclk_div",
+						  REG_CLK_PCLKEN0, 24);
+	/* UART9 */
+	clk[UART9_APLLDIV]	= nuc970_clk_divider("uart9_aplldiv", "apll",
+						     REG_CLK_DIV6, 8, 3);
+	clk[UART9_UPLLDIV]	= nuc970_clk_divider("uart9_uplldiv", "upll",
+						     REG_CLK_DIV6, 8, 3);
+	clk[UART9_ECLK_MUX]	= nuc970_clk_mux("uart9_eclk_mux", REG_CLK_DIV6,
+						 11, 2, uart9_sel_clks,
+						 ARRAY_SIZE(uart9_sel_clks));
+	clk[UART9_ECLK_DIV]	= nuc970_clk_divider("uart9_eclk_div",
+						     "uart9_eclk_mux",
+						     REG_CLK_DIV6, 13, 3);
+	clk[UART9_ECLK_GATE]	= nuc970_clk_gate("uart9_eclk_gate",
+						  "uart9_eclk_div",
+						  REG_CLK_PCLKEN0, 25);
+	/* UART10 */
+	clk[UART10_APLLDIV]	 = nuc970_clk_divider("uart10_aplldiv", "apll",
+						      REG_CLK_DIV6, 16, 3);
+	clk[UART10_UPLLDIV]	 = nuc970_clk_divider("uart10_uplldiv", "upll",
+						      REG_CLK_DIV6, 16, 3);
+	clk[UART10_ECLK_MUX]	= nuc970_clk_mux("uart10_eclk_mux",
+						 REG_CLK_DIV6, 19, 2,
+						 uart10_sel_clks,
+						 ARRAY_SIZE(uart10_sel_clks));
+	clk[UART10_ECLK_DIV]	= nuc970_clk_divider("uart10_eclk_div",
+						     "uart10_eclk_mux",
+						     REG_CLK_DIV6, 21, 3);
+	clk[UART10_ECLK_GATE]	= nuc970_clk_gate("uart10_eclk_gate",
+						  "uart10_eclk_div",
+						  REG_CLK_PCLKEN0, 26);
+	/* SYSTEM */
+	clk[SYSTEM_APLLDIV]	= nuc970_clk_divider("system_aplldiv", "apll",
+						     REG_CLK_DIV0, 0, 3);
+	clk[SYSTEM_UPLLDIV]	= nuc970_clk_divider("system_uplldiv", "upll",
+						     REG_CLK_DIV0, 0, 3);
+	clk[SYSTEM_ECLK_MUX]	= nuc970_clk_mux("system_eclk_mux",
+						 REG_CLK_DIV0, 3, 2,
+						 system_sel_clks,
+						 ARRAY_SIZE(system_sel_clks));
+	clk[SYSTEM_ECLK_DIV]	= nuc970_clk_divider("system_eclk_div",
+						     "system_eclk_mux",
+						     REG_CLK_DIV0, 8, 4);
+	/* GPIO */
+	clk[GPIO_ECLK_MUX]	= nuc970_clk_mux("gpio_eclk_mux", REG_CLK_DIV7,
+						 7, 1, gpio_sel_clks,
+						 ARRAY_SIZE(gpio_sel_clks));
+	clk[GPIO_ECLK_DIV]	= nuc970_clk_divider("gpio_eclk_div",
+						     "gpio_eclk_mux",
+						     REG_CLK_DIV7, 0, 7);
+	clk[GPIO_ECLK_GATE]	= nuc970_clk_gate("gpio_eclk_gate",
+						  "gpio_eclk_div",
+						  REG_CLK_PCLKEN0, 3);
+	/* KPI */
+	clk[KPI_ECLK_MUX]	= nuc970_clk_mux("kpi_eclk_mux", REG_CLK_DIV7,
+						 15, 1, kpi_sel_clks,
+						 ARRAY_SIZE(kpi_sel_clks));
+	clk[KPI_ECLK_DIV]	= nuc970_clk_divider("kpi_eclk_div",
+						     "kpi_eclk_mux",
+						     REG_CLK_DIV7, 8, 7);
+	clk[KPI_ECLK_GATE]	= nuc970_clk_gate("kpi_eclk_gate",
+						  "kpi_eclk_div",
+						  REG_CLK_PCLKEN1, 25);
+	/* ETIMER0 */
+	clk[ETIMER0_ECLK_MUX]	= nuc970_clk_mux("etimer0_eclk_mux",
+						 REG_CLK_DIV8, 16, 2,
+						 etimer_sel_clks,
+						 ARRAY_SIZE(etimer_sel_clks));
+	clk[ETIMER0_ECLK_GATE]	= nuc970_clk_gate("etimer0_eclk_gate",
+						  "etimer0_eclk_mux",
+						  REG_CLK_PCLKEN0, 4);
+	/* ETIMER1 */
+	clk[ETIMER1_ECLK_MUX]	= nuc970_clk_mux("etimer1_eclk_mux",
+						 REG_CLK_DIV8, 18, 2,
+						 etimer_sel_clks,
+						 ARRAY_SIZE(etimer_sel_clks));
+	clk[ETIMER1_ECLK_GATE]	= nuc970_clk_gate("etimer1_eclk_gate",
+						  "etimer1_eclk_mux",
+						  REG_CLK_PCLKEN0, 5);
+	/* ETIMER2 */
+	clk[ETIMER2_ECLK_MUX]	= nuc970_clk_mux("etimer2_eclk_mux",
+						 REG_CLK_DIV8, 20, 2,
+						 etimer_sel_clks,
+						 ARRAY_SIZE(etimer_sel_clks));
+	clk[ETIMER2_ECLK_GATE]	= nuc970_clk_gate("etimer2_eclk_gate",
+						  "etimer2_eclk_mux",
+						  REG_CLK_PCLKEN0, 6);
+	/* ETIMER3 */
+	clk[ETIMER3_ECLK_MUX]	= nuc970_clk_mux("etimer3_eclk_mux",
+						 REG_CLK_DIV8, 22, 2,
+						 etimer_sel_clks,
+						 ARRAY_SIZE(etimer_sel_clks));
+	clk[ETIMER3_ECLK_GATE]	= nuc970_clk_gate("etimer3_eclk_gate",
+						  "etimer3_eclk_mux",
+						  REG_CLK_PCLKEN0, 7);
+	/* WWDT */
+	clk[WWDT_ECLK_MUX]	= nuc970_clk_mux("wwdt_eclk_mux", REG_CLK_DIV8,
+						 10, 2, wwdt_sel_clks,
+						 ARRAY_SIZE(wwdt_sel_clks));
+	clk[WWDT_ECLK_GATE]	= nuc970_clk_gate("wwdt_eclk_gate",
+						  "wwdt_eclk_mux",
+						  REG_CLK_PCLKEN0, 1);
+	/* WDT */
+	clk[WDT_ECLK_MUX]	= nuc970_clk_mux("wdt_eclk_mux", REG_CLK_DIV8,
+						 8, 2, wwdt_sel_clks,
+						 ARRAY_SIZE(wwdt_sel_clks));
+	clk[WDT_ECLK_GATE]	= nuc970_clk_gate("wdt_eclk_gate",
+						  "wdt_eclk_mux",
+						  REG_CLK_PCLKEN0, 0);
+	/* SMARTCARD */
+	clk[SMC0_ECLK_DIV]	= nuc970_clk_divider("smc0_eclk_div", "xin",
+						     REG_CLK_DIV6, 24, 4);
+	clk[SMC0_ECLK_GATE]	= nuc970_clk_gate("smc0_eclk_gate",
+						  "smc0_eclk_div",
+						  REG_CLK_PCLKEN1, 12);
+	clk[SMC1_ECLK_DIV]	= nuc970_clk_divider("smc1_eclk_div", "xin",
+						     REG_CLK_DIV6, 28, 4);
+	clk[SMC1_ECLK_GATE]	= nuc970_clk_gate("smc1_eclk_gate",
+						  "smc1_eclk_div",
+						  REG_CLK_PCLKEN1, 13);
+	/* PCLK */
+	clk[PCLK_DIV]		= nuc970_clk_divider("pclk_div", "hclk1_div",
+						     REG_CLK_DIV0, 24, 4);
+	clk[PCLK4096_DIV]	= nuc970_clk_fixed_factor("pclk4096_div",
+							  "pclk_div", 1, 4096);
+	clk[I2C0_GATE]		= nuc970_clk_gate("i2c0_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 0);
+	clk[I2C1_GATE]		= nuc970_clk_gate("i2c1_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 1);
+	clk[SPI0_GATE]		= nuc970_clk_gate("spi0_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 4);
+	clk[SPI1_GATE]		= nuc970_clk_gate("spi1_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 5);
+	clk[UART0_GATE]		= nuc970_clk_gate("uart0_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 16);
+	clk[UART1_GATE]		= nuc970_clk_gate("uart1_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 17);
+	clk[UART2_GATE]		= nuc970_clk_gate("uart2_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 18);
+	clk[UART3_GATE]		= nuc970_clk_gate("uart3_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 19);
+	clk[UART4_GATE]		= nuc970_clk_gate("uart4_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 20);
+	clk[UART5_GATE]		= nuc970_clk_gate("uart5_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 21);
+	clk[UART6_GATE]		= nuc970_clk_gate("uart6_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 22);
+	clk[UART7_GATE]		= nuc970_clk_gate("uart7_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 23);
+	clk[UART8_GATE]		= nuc970_clk_gate("uart8_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 24);
+	clk[UART9_GATE]		= nuc970_clk_gate("uart9_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 25);
+	clk[UART10_GATE]	= nuc970_clk_gate("uart10_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 26);
+	clk[WDT_GATE]		= nuc970_clk_gate("wdt_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 0);
+	clk[WWDT_GATE]		= nuc970_clk_gate("wwdt_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 1);
+	clk[RTC_GATE]		= nuc970_clk_gate("rtc_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 2);
+	clk[GPIO_GATE]		= nuc970_clk_gate("gpio_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 3);
+	clk[ADC_GATE]		= nuc970_clk_gate("adc_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 24);
+	clk[KPI_GATE]		= nuc970_clk_gate("kpi_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 25);
+	clk[MTPC_GATE]		= nuc970_clk_gate("mtpc_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 26);
+	clk[PWM_GATE]		= nuc970_clk_gate("pwm_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 27);
+	clk[ETIMER0_GATE]	= nuc970_clk_gate("etimer0_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 4);
+	clk[ETIMER1_GATE]	= nuc970_clk_gate("etimer1_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 5);
+	clk[ETIMER2_GATE]	= nuc970_clk_gate("etimer2_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 6);
+	clk[ETIMER3_GATE]	= nuc970_clk_gate("etimer3_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 7);
+	clk[CAN0_GATE]		= nuc970_clk_gate("can0_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 8);
+	clk[CAN1_GATE]		= nuc970_clk_gate("can1_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 9);
+	clk[TIMER0_GATE]	= nuc970_clk_gate("timer0_gate", "xin",
+						  REG_CLK_PCLKEN0, 8);
+	clk[TIMER1_GATE]	= nuc970_clk_gate("timer1_gate", "xin",
+						  REG_CLK_PCLKEN0, 9);
+	clk[TIMER2_GATE]	= nuc970_clk_gate("timer2_gate", "xin",
+						  REG_CLK_PCLKEN0, 10);
+	clk[TIMER3_GATE]	= nuc970_clk_gate("timer3_gate", "xin",
+						  REG_CLK_PCLKEN0, 11);
+	clk[TIMER4_GATE]	= nuc970_clk_gate("timer4_gate", "xin",
+						  REG_CLK_PCLKEN0, 12);
+	clk[SMC0_GATE]		= nuc970_clk_gate("smc0_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 12);
+	clk[SMC1_GATE]		= nuc970_clk_gate("smc1_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 13);
+
+	for (i = 0; i < ARRAY_SIZE(clk); i++)
+		if (IS_ERR(clk[i]))
+			pr_err("nuc970 clk %d: register failed with %ld\n",
+				i, PTR_ERR(clk[i]));
+
+	clk_data.clks = clk;
+	clk_data.clk_num = ARRAY_SIZE(clk);
+
+	ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	if (ret)
+		pr_err("Failed to register OF clock provider\n");
+
+	/* Register clock device */
+	clk_register_clkdev(clk[TIMER0_GATE], "timer0", NULL);
+	clk_register_clkdev(clk[TIMER1_GATE], "timer1", NULL);
+	clk_register_clkdev(clk[PCLK4096_DIV], "pclk4096_div", NULL);
+	clk_register_clkdev(clk[XIN], "xin", NULL);
+	clk_register_clkdev(clk[XIN32K], "xin32k", NULL);
+	clk_register_clkdev(clk[APLL], "apll", NULL);
+	clk_register_clkdev(clk[UPLL], "upll", NULL);
+	clk_register_clkdev(clk[SYS_MUX], "sysmux", NULL);
+	clk_register_clkdev(clk[SYS_DIV], "sysdiv", NULL);
+	clk_register_clkdev(clk[XIN128_DIV], "xin128div", NULL);
+	/* CPU */
+	clk_register_clkdev(clk[CPU_DIV], "cpudiv", NULL);
+	clk_register_clkdev(clk[CPU_GATE], "cpu", NULL);
+	/* HCLK1 */
+	clk_register_clkdev(clk[HCLK_GATE], "hclk", NULL);
+	clk_register_clkdev(clk[SRAM_GATE], "sram", NULL);
+	clk_register_clkdev(clk[HCLK1_DIV], "hclk1div", NULL);
+	clk_register_clkdev(clk[DDR_GATE], "ddr_hclk", NULL);
+	clk_register_clkdev(clk[GDMA_GATE], "gdma_hclk", NULL);
+	clk_register_clkdev(clk[EBI_GATE], "ebi_hclk", NULL);
+	clk_register_clkdev(clk[TIC_GATE], "tic_hclk", NULL);
+	/* HCLK234 */
+	clk_register_clkdev(clk[HCLKN_DIV], "hclkndiv", NULL);
+	clk_register_clkdev(clk[DRAM_GATE], "dram", NULL);
+	clk_register_clkdev(clk[HCLK234_DIV], "hclk234div", NULL);
+	/* HCLK3 */
+	clk_register_clkdev(clk[USBH_GATE], "usbh_hclk", NULL);
+	clk_register_clkdev(clk[EMAC1_GATE], "emac1_hclk", NULL);
+	clk_register_clkdev(clk[EMAC1_ECLK_DIV], "emac1_eclk_div", NULL);
+	clk_register_clkdev(clk[EMAC1_ECLK_GATE], "emac1_eclk", NULL);
+	clk_register_clkdev(clk[USBD_GATE], "usbd_hclk", NULL);
+	clk_register_clkdev(clk[FMI_GATE], "fmi_hclk", NULL);
+	clk_register_clkdev(clk[NAND_GATE], "nand_hclk", NULL);
+	clk_register_clkdev(clk[EMMC_GATE], "emmc_hclk", NULL);
+	clk_register_clkdev(clk[CRYPTO_GATE], "crypto_hclk", NULL);
+	clk_register_clkdev(clk[JPEG_GATE], "jpeg_hclk", NULL);
+	clk_register_clkdev(clk[JPEG_ECLK_DIV], "jpeg_eclk_div", NULL);
+	clk_register_clkdev(clk[JPEG_ECLK_GATE], "jpeg_eclk", NULL);
+	clk_register_clkdev(clk[GE2D_GATE], "ge2d_hclk", NULL);
+	clk_register_clkdev(clk[GE2D_ECLK_DIV], "ge2d_eclk_div", NULL);
+	clk_register_clkdev(clk[GE2D_ECLK_GATE], "ge2d_eclk", NULL);
+	/* HCLK4 */
+	clk_register_clkdev(clk[EMAC0_GATE], "emac0_hclk", NULL);
+	clk_register_clkdev(clk[EMAC0_ECLK_DIV], "emac0_eclk_div", NULL);
+	clk_register_clkdev(clk[EMAC0_ECLK_GATE], "emac0_eclk", NULL);
+	clk_register_clkdev(clk[SDH_GATE], "sdh_hclk", NULL);
+	clk_register_clkdev(clk[AUDIO_GATE], "audio_hclk", NULL);
+	clk_register_clkdev(clk[LCD_GATE], "lcd_hclk", NULL);
+	clk_register_clkdev(clk[SENSOR_GATE], "sensor_hclk", NULL);
+	clk_register_clkdev(clk[CAP_GATE], "cap_hclk", NULL);
+	/* ECLK */
+	clk_register_clkdev(clk[LCD_APLLDIV], "lcd_aplldiv", NULL);
+	clk_register_clkdev(clk[LCD_UPLLDIV], "lcd_uplldiv", NULL);
+	clk_register_clkdev(clk[LCD_ECLK_MUX], "lcd_eclk_mux", NULL);
+	clk_register_clkdev(clk[LCD_ECLK_DIV], "lcd_eclk_div", NULL);
+	clk_register_clkdev(clk[LCD_ECLK_GATE], "lcd_eclk", NULL);
+	clk_register_clkdev(clk[AUDIO_APLLDIV], "audio_aplldiv", NULL);
+	clk_register_clkdev(clk[AUDIO_UPLLDIV], "audio_uplldiv", NULL);
+	clk_register_clkdev(clk[AUDIO_ECLK_MUX], "audio_eclk_mux", NULL);
+	clk_register_clkdev(clk[AUDIO_ECLK_DIV], "audio_eclk_div", NULL);
+	clk_register_clkdev(clk[AUDIO_ECLK_GATE], "audio_eclk", NULL);
+	clk_register_clkdev(clk[USB_APLLDIV], "usb_aplldiv", NULL);
+	clk_register_clkdev(clk[USB_UPLLDIV], "usb_uplldiv", NULL);
+	clk_register_clkdev(clk[USB_ECLK_MUX], "usb_eclk_mux", NULL);
+	clk_register_clkdev(clk[USB_ECLK_DIV], "usb_eclk_div", NULL);
+	clk_register_clkdev(clk[USB_ECLK_GATE], "usb_eclk", NULL);
+	clk_register_clkdev(clk[SDH_APLLDIV], "sdh_aplldiv", NULL);
+	clk_register_clkdev(clk[SDH_UPLLDIV], "sdh_uplldiv", NULL);
+	clk_register_clkdev(clk[SDH_ECLK_MUX], "sdh_eclk_mux", NULL);
+	clk_register_clkdev(clk[SDH_ECLK_DIV], "sdh_eclk_div", NULL);
+	clk_register_clkdev(clk[SDH_ECLK_GATE], "sdh_eclk", NULL);
+	clk_register_clkdev(clk[EMMC_APLLDIV], "emmc_aplldiv", NULL);
+	clk_register_clkdev(clk[EMMC_UPLLDIV], "emmc_uplldiv", NULL);
+	clk_register_clkdev(clk[EMMC_ECLK_MUX], "emmc_eclk_mux", NULL);
+	clk_register_clkdev(clk[EMMC_ECLK_DIV], "emmc_eclk_div", NULL);
+	clk_register_clkdev(clk[EMMC_ECLK_GATE], "emmc_eclk", NULL);
+	clk_register_clkdev(clk[ADC_APLLDIV], "adc_aplldiv", NULL);
+	clk_register_clkdev(clk[ADC_UPLLDIV], "adc_uplldiv", NULL);
+	clk_register_clkdev(clk[ADC_ECLK_MUX], "adc_eclk_mux", NULL);
+	clk_register_clkdev(clk[ADC_ECLK_DIV], "adc_eclk_div", NULL);
+	clk_register_clkdev(clk[ADC_ECLK_GATE], "adc_eclk", NULL);
+	clk_register_clkdev(clk[CAP_APLLDIV], "cap_aplldiv", NULL);
+	clk_register_clkdev(clk[CAP_UPLLDIV], "cap_uplldiv", NULL);
+	clk_register_clkdev(clk[CAP_ECLK_MUX], "cap_eclk_mux", NULL);
+	clk_register_clkdev(clk[CAP_ECLK_DIV], "cap_eclk_div", NULL);
+	clk_register_clkdev(clk[CAP_ECLK_GATE], "cap_eclk", NULL);
+	clk_register_clkdev(clk[UART0_APLLDIV], "uart0_aplldiv", NULL);
+	clk_register_clkdev(clk[UART0_UPLLDIV], "uart0_uplldiv", NULL);
+	clk_register_clkdev(clk[UART0_ECLK_MUX], "uart0_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART0_ECLK_DIV], "uart0_eclk_div", NULL);
+	clk_register_clkdev(clk[UART0_ECLK_GATE], "uart0_eclk", NULL);
+	clk_register_clkdev(clk[UART1_APLLDIV], "uart1_aplldiv", NULL);
+	clk_register_clkdev(clk[UART1_UPLLDIV], "uart1_uplldiv", NULL);
+	clk_register_clkdev(clk[UART1_ECLK_MUX], "uart1_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART1_ECLK_DIV], "uart1_eclk_div", NULL);
+	clk_register_clkdev(clk[UART1_ECLK_GATE], "uart1_eclk", NULL);
+	clk_register_clkdev(clk[UART2_APLLDIV], "uart2_aplldiv", NULL);
+	clk_register_clkdev(clk[UART2_UPLLDIV], "uart2_uplldiv", NULL);
+	clk_register_clkdev(clk[UART2_ECLK_MUX], "uart2_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART2_ECLK_DIV], "uart2_eclk_div", NULL);
+	clk_register_clkdev(clk[UART2_ECLK_GATE], "uart2_eclk", NULL);
+	clk_register_clkdev(clk[UART3_APLLDIV], "uart3_aplldiv", NULL);
+	clk_register_clkdev(clk[UART3_UPLLDIV], "uart3_uplldiv", NULL);
+	clk_register_clkdev(clk[UART3_ECLK_MUX], "uart3_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART3_ECLK_DIV], "uart3_eclk_div", NULL);
+	clk_register_clkdev(clk[UART3_ECLK_GATE], "uart3_eclk", NULL);
+	clk_register_clkdev(clk[UART4_APLLDIV], "uart4_aplldiv", NULL);
+	clk_register_clkdev(clk[UART4_UPLLDIV], "uart4_uplldiv", NULL);
+	clk_register_clkdev(clk[UART4_ECLK_MUX], "uart4_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART4_ECLK_DIV], "uart4_eclk_div", NULL);
+	clk_register_clkdev(clk[UART4_ECLK_GATE], "uart4_eclk", NULL);
+	clk_register_clkdev(clk[UART5_APLLDIV], "uart5_aplldiv", NULL);
+	clk_register_clkdev(clk[UART5_UPLLDIV], "uart5_uplldiv", NULL);
+	clk_register_clkdev(clk[UART5_ECLK_MUX], "uart5_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART5_ECLK_DIV], "uart5_eclk_div", NULL);
+	clk_register_clkdev(clk[UART5_ECLK_GATE], "uart5_eclk", NULL);
+	clk_register_clkdev(clk[UART6_APLLDIV], "uart6_aplldiv", NULL);
+	clk_register_clkdev(clk[UART6_UPLLDIV], "uart6_uplldiv", NULL);
+	clk_register_clkdev(clk[UART6_ECLK_MUX], "uart6_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART6_ECLK_DIV], "uart6_eclk_div", NULL);
+	clk_register_clkdev(clk[UART6_ECLK_GATE], "uart6_eclk", NULL);
+	clk_register_clkdev(clk[UART7_APLLDIV], "uart7_aplldiv", NULL);
+	clk_register_clkdev(clk[UART7_UPLLDIV], "uart7_uplldiv", NULL);
+	clk_register_clkdev(clk[UART7_ECLK_MUX], "uart7_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART7_ECLK_DIV], "uart7_eclk_div", NULL);
+	clk_register_clkdev(clk[UART7_ECLK_GATE], "uart7_eclk", NULL);
+	clk_register_clkdev(clk[UART8_APLLDIV], "uart8_aplldiv", NULL);
+	clk_register_clkdev(clk[UART8_UPLLDIV], "uart8_uplldiv", NULL);
+	clk_register_clkdev(clk[UART8_ECLK_MUX], "uart8_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART8_ECLK_DIV], "uart8_eclk_div", NULL);
+	clk_register_clkdev(clk[UART8_ECLK_GATE], "uart8_eclk", NULL);
+	clk_register_clkdev(clk[UART9_APLLDIV], "uart9_aplldiv", NULL);
+	clk_register_clkdev(clk[UART9_UPLLDIV], "uart9_uplldiv", NULL);
+	clk_register_clkdev(clk[UART9_ECLK_MUX], "uart9_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART9_ECLK_DIV], "uart9_eclk_div", NULL);
+	clk_register_clkdev(clk[UART9_ECLK_GATE], "uart9_eclk", NULL);
+	clk_register_clkdev(clk[UART10_APLLDIV], "uart10_aplldiv", NULL);
+	clk_register_clkdev(clk[UART10_UPLLDIV], "uart10_uplldiv", NULL);
+	clk_register_clkdev(clk[UART10_ECLK_MUX], "uart10_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART10_ECLK_DIV], "uart10_eclk_div", NULL);
+	clk_register_clkdev(clk[UART10_ECLK_GATE], "uart10_eclk", NULL);
+	clk_register_clkdev(clk[SYSTEM_APLLDIV], "system_aplldiv", NULL);
+	clk_register_clkdev(clk[SYSTEM_UPLLDIV], "system_uplldiv", NULL);
+	clk_register_clkdev(clk[SYSTEM_ECLK_MUX], "system_eclk_mux", NULL);
+	clk_register_clkdev(clk[SYSTEM_ECLK_DIV], "system_eclk_div", NULL);
+	clk_register_clkdev(clk[SYSTEM_ECLK_GATE], "system_eclk", NULL);
+	clk_register_clkdev(clk[GPIO_ECLK_MUX], "gpio_eclk_mux", NULL);
+	clk_register_clkdev(clk[GPIO_ECLK_DIV], "gpio_eclk_div", NULL);
+	clk_register_clkdev(clk[GPIO_ECLK_GATE], "gpio_eclk", NULL);
+	clk_register_clkdev(clk[KPI_ECLK_MUX], "kpi_eclk_mux", NULL);
+	clk_register_clkdev(clk[KPI_ECLK_DIV], "kpi_eclk_div", NULL);
+	clk_register_clkdev(clk[KPI_ECLK_GATE], "kpi_eclk", NULL);
+	clk_register_clkdev(clk[ETIMER0_ECLK_MUX], "etmr0_eclk_mux", NULL);
+	clk_register_clkdev(clk[ETIMER0_ECLK_GATE], "etmr0_eclk", NULL);
+	clk_register_clkdev(clk[ETIMER1_ECLK_MUX], "etmr1_eclk_mux", NULL);
+	clk_register_clkdev(clk[ETIMER1_ECLK_GATE], "etmr1_eclk", NULL);
+	clk_register_clkdev(clk[ETIMER2_ECLK_MUX], "etmr2_eclk_mux", NULL);
+	clk_register_clkdev(clk[ETIMER2_ECLK_GATE], "etmr2_eclk", NULL);
+	clk_register_clkdev(clk[ETIMER3_ECLK_MUX], "etmr3_eclk_mux", NULL);
+	clk_register_clkdev(clk[ETIMER3_ECLK_GATE], "etmr3_eclk", NULL);
+	clk_register_clkdev(clk[WWDT_ECLK_MUX], "wwdt_eclk_mux", NULL);
+	clk_register_clkdev(clk[WWDT_ECLK_GATE], "wwdt_eclk", NULL);
+	clk_register_clkdev(clk[WDT_ECLK_MUX], "wdt_eclk_mux", NULL);
+	clk_register_clkdev(clk[WDT_ECLK_GATE], "wdt_eclk", NULL);
+	clk_register_clkdev(clk[SMC0_ECLK_DIV], "smc0_eclk_div", NULL);
+	clk_register_clkdev(clk[SMC0_ECLK_GATE], "smc0_eclk", NULL);
+	clk_register_clkdev(clk[SMC1_ECLK_DIV], "smc1_eclk_div", NULL);
+	clk_register_clkdev(clk[SMC1_ECLK_GATE], "smc1_eclk", NULL);
+	/* PCLK */
+	clk_register_clkdev(clk[PCLK_DIV], "pclkdiv", NULL);
+	clk_register_clkdev(clk[RTC_GATE], "rtc", NULL);
+	clk_register_clkdev(clk[I2C0_GATE], "i2c0", NULL);
+	clk_register_clkdev(clk[I2C1_GATE], "i2c1", NULL);
+	clk_register_clkdev(clk[SPI0_GATE], "spi0", NULL);
+	clk_register_clkdev(clk[SPI1_GATE], "spi1", NULL);
+	clk_register_clkdev(clk[UART0_GATE], "uart0", NULL);
+	clk_register_clkdev(clk[UART1_GATE], "uart1", NULL);
+	clk_register_clkdev(clk[UART2_GATE], "uart2", NULL);
+	clk_register_clkdev(clk[UART3_GATE], "uart3", NULL);
+	clk_register_clkdev(clk[UART4_GATE], "uart4", NULL);
+	clk_register_clkdev(clk[UART5_GATE], "uart5", NULL);
+	clk_register_clkdev(clk[UART6_GATE], "uart6", NULL);
+	clk_register_clkdev(clk[UART7_GATE], "uart7", NULL);
+	clk_register_clkdev(clk[UART8_GATE], "uart8", NULL);
+	clk_register_clkdev(clk[UART9_GATE], "uart9", NULL);
+	clk_register_clkdev(clk[UART10_GATE], "uart10", NULL);
+	clk_register_clkdev(clk[WDT_GATE], "wdt", NULL);
+	clk_register_clkdev(clk[WWDT_GATE], "wwdt", NULL);
+	clk_register_clkdev(clk[GPIO_GATE], "gpio", NULL);
+	clk_register_clkdev(clk[SMC0_GATE], "smc0", NULL);
+	clk_register_clkdev(clk[SMC1_GATE], "smc1", NULL);
+	clk_register_clkdev(clk[ADC_GATE], "adc", NULL);
+	clk_register_clkdev(clk[KPI_GATE], "kpi", NULL);
+	clk_register_clkdev(clk[MTPC_GATE], "mtpc", NULL);
+	clk_register_clkdev(clk[PWM_GATE], "pwm", NULL);
+	clk_register_clkdev(clk[ETIMER0_GATE], "etimer0", NULL);
+	clk_register_clkdev(clk[ETIMER1_GATE], "etimer1", NULL);
+	clk_register_clkdev(clk[ETIMER2_GATE], "etimer2", NULL);
+	clk_register_clkdev(clk[ETIMER3_GATE], "etimer3", NULL);
+	clk_register_clkdev(clk[TIMER2_GATE], "timer2", NULL);
+	clk_register_clkdev(clk[TIMER3_GATE], "timer3", NULL);
+	clk_register_clkdev(clk[TIMER4_GATE], "timer4", NULL);
+	clk_register_clkdev(clk[CAN0_GATE], "can0", NULL);
+	clk_register_clkdev(clk[CAN1_GATE], "can1", NULL);
+
+	/* enable some important clocks */
+	clk_prepare_enable(clk_get(NULL, "cpu"));
+	clk_prepare_enable(clk_get(NULL, "hclk"));
+	clk_prepare_enable(clk_get(NULL, "sram"));
+	clk_prepare_enable(clk_get(NULL, "dram"));
+	clk_prepare_enable(clk_get(NULL, "ddr_hclk"));
+}
+
+CLK_OF_DECLARE(nuc970_clk, "nuvoton,nuc970-clk", nuc970_clocks_init);
diff --git a/drivers/clk/nuc900/clk-upll.c b/drivers/clk/nuc900/clk-upll.c
new file mode 100644
index 0000000..563fdcd
--- /dev/null
+++ b/drivers/clk/nuc900/clk-upll.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+
+#include "clk-ccf.h"
+
+struct clk_upll {
+	struct clk_hw	hw;
+	void __iomem	*base;
+};
+
+#define to_clk_upll(clk) (container_of(clk, struct clk_upll, clk))
+
+static unsigned long clk_upll_recalc_rate(struct clk_hw *hw,
+					  unsigned long parent_rate)
+{
+	struct clk_upll *pll = to_clk_upll(hw);
+	unsigned long rate;
+	unsigned long reg = readl(pll->base) & 0x0FFFFFFF;
+
+	if (parent_rate != 12000000)
+		return 0;
+
+	switch (reg) {
+	case 0x15:
+		rate = 264000000;
+		break;
+	case 0x18:
+		rate = 300000000;
+		break;
+	default:
+		rate = 264000000;
+		break;
+	}
+
+	return rate;
+}
+
+static struct clk_ops clk_upll_ops = {
+	.recalc_rate = clk_upll_recalc_rate,
+};
+
+struct clk *nuc970_clk_upll(const char *name, const char *parent,
+			    void __iomem *base)
+{
+	struct clk_upll *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	pll->base = base;
+
+	init.name = name;
+	init.ops = &clk_upll_ops;
+	init.flags = 0;
+	init.parent_names = &parent;
+	init.num_parents = 1;
+
+	pll->hw.init = &init;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
-- 
2.7.4

  parent reply	other threads:[~2016-07-10  7:27 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-10  7:27 [PATCH v2 00/10] ARM: NUC900: Add NUC970 SoC support Wan Zongshun
2016-07-10  7:27 ` [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support Wan Zongshun
2016-07-10 22:11   ` Arnd Bergmann
2016-07-11 16:04   ` Arnd Bergmann
2016-07-12  4:30     ` Wan Zongshun
2016-07-12  7:14       ` Wan Zongshun
2016-07-12  8:23         ` Arnd Bergmann
2016-07-10  7:27 ` [PATCH v2 02/10] irqchip: add irqchip driver for nuc900 Wan Zongshun
2016-07-10 21:51   ` Paul Gortmaker
2016-07-11  2:19     ` Wan Zongshun
2016-07-11 15:46   ` Arnd Bergmann
2016-07-12  7:04     ` Wan Zongshun
2016-07-12  8:26       ` Arnd Bergmann
2016-07-14  8:52         ` Wan Zongshun
2016-07-14 11:09           ` Arnd Bergmann
2016-07-13 20:09   ` Jason Cooper
2016-07-14  3:36     ` Wan Zongshun
2016-07-14 13:54       ` Jason Cooper
2016-07-15  5:15         ` Wan Zongshun
2016-07-15  7:00           ` Arnd Bergmann
2016-07-15  9:44             ` Wan ZongShun
2016-07-15 10:02               ` Arnd Bergmann
2016-07-21 18:45                 ` Jason Cooper
2016-07-15 15:45               ` Jason Cooper
2016-07-10  7:27 ` [PATCH v2 03/10] Clocksource: add nuc970 clocksource driver Wan Zongshun
2016-07-11 15:36   ` Arnd Bergmann
2016-07-12  7:32     ` Wan Zongshun
2016-07-12  8:28       ` Arnd Bergmann
2016-07-21 12:52         ` Daniel Lezcano
2016-07-21 12:54           ` Arnd Bergmann
2016-07-10  7:27 ` Wan Zongshun [this message]
2016-07-11 22:14   ` [PATCH v2 04/10] clk: add Clock driver for nuc970 Michael Turquette
2016-07-10  7:27 ` [PATCH v2 05/10] power/reset: Add reset driver support for nuc900 Wan Zongshun
2016-07-10 21:56   ` Paul Gortmaker
2016-07-11  2:30     ` Wan Zongshun
2016-07-11  2:58       ` Paul Gortmaker
2016-07-10  7:27 ` [PATCH v2 06/10] soc: Add SoC specific " Wan Zongshun
2016-07-11  8:03   ` Arnd Bergmann
2016-07-11  9:07     ` Wan Zongshun
2016-07-11 10:24       ` Arnd Bergmann
2016-07-11 10:28         ` Wan ZongShun
2016-07-11 10:36           ` Arnd Bergmann
2016-07-12  9:06     ` Wan Zongshun
2016-07-12  9:50       ` Arnd Bergmann
2016-07-10  7:27 ` [PATCH v2 07/10] ARM: dts: Add clock header file into dt-bindings Wan Zongshun

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1468135649-19980-5-git-send-email-vw@iommu.org \
    --to=vw@iommu.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --subject='Re: [PATCH v2 04/10] clk: add Clock driver for nuc970' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).