Signed-off-by: Wan Zongshun <mcuos.com@xxxxxxxxx> --- 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 | 920 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/nuc900/clk-upll.c | 83 ++++ 6 files changed, 1231 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..4e1c202 --- /dev/null +++ b/drivers/clk/nuc900/clk-apll.c @@ -0,0 +1,168 @@ +/* + * Copyright 2016 Wan Zongshun <mcuos.com@xxxxxxxxx> + * + * 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 = __raw_readl(pll->base); + val &= ~0x10000000; + val |= 0x40000000; + __raw_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 = __raw_readl(pll->base); + val |= 0x10000000; + val &= ~0x40000000; + __raw_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 = kmalloc(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..a4faf0d --- /dev/null +++ b/drivers/clk/nuc900/clk-nuc970.c @@ -0,0 +1,920 @@ +/* + * Copyright 2016 Wan Zongshun <mcuos.com@xxxxxxxxx> + * + * 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; + + clkctrl = of_iomap(np, 0); + WARN_ON(!clkctrl); + + /* 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); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + /* 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,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..d0c6fc2 --- /dev/null +++ b/drivers/clk/nuc900/clk-upll.c @@ -0,0 +1,83 @@ +/* + * Copyright 2016 Wan Zongshun <mcuos.com@xxxxxxxxx> + * + * 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 = kmalloc(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 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html