Add support for the clocks provided by the CGU in the Ingenic X2000 SoC, making use of the cgu code to do the heavy lifting. Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouyanjie@xxxxxxxxxxxxxx> --- Notes: v5: New patch. v5->v6: No change. v6->v7: No change. drivers/clk/ingenic/Kconfig | 10 + drivers/clk/ingenic/Makefile | 1 + drivers/clk/ingenic/x2000-cgu.c | 790 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 801 insertions(+) create mode 100644 drivers/clk/ingenic/x2000-cgu.c diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig index 7fda7bb..f5dd2f2 100644 --- a/drivers/clk/ingenic/Kconfig +++ b/drivers/clk/ingenic/Kconfig @@ -85,6 +85,16 @@ config INGENIC_CGU_X1830 If building for a X1830 SoC, you want to say Y here. +config INGENIC_CGU_X2000 + bool "Ingenic X2000 CGU driver" + default MACH_X2000 + select INGENIC_CGU_COMMON + help + Support the clocks provided by the CGU hardware on Ingenic X2000 + and compatible SoCs. + + If building for a X2000 SoC, you want to say Y here. + config INGENIC_TCU_CLK bool "Ingenic JZ47xx TCU clocks driver" default MACH_INGENIC diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile index aed8da4..de265ae 100644 --- a/drivers/clk/ingenic/Makefile +++ b/drivers/clk/ingenic/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_INGENIC_CGU_JZ4775) += jz4775-cgu.o obj-$(CONFIG_INGENIC_CGU_JZ4780) += jz4780-cgu.o obj-$(CONFIG_INGENIC_CGU_X1000) += x1000-cgu.o obj-$(CONFIG_INGENIC_CGU_X1830) += x1830-cgu.o +obj-$(CONFIG_INGENIC_CGU_X2000) += x2000-cgu.o obj-$(CONFIG_INGENIC_TCU_CLK) += tcu.o diff --git a/drivers/clk/ingenic/x2000-cgu.c b/drivers/clk/ingenic/x2000-cgu.c new file mode 100644 index 00000000..1e79af1 --- /dev/null +++ b/drivers/clk/ingenic/x2000-cgu.c @@ -0,0 +1,790 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * X2000 SoC CGU driver + * Copyright (C) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@xxxxxxxxxxxxxx> + */ + +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> + +#include <dt-bindings/clock/x2000-cgu.h> + +#include "cgu.h" +#include "pm.h" + +/* CGU register offsets */ +#define CGU_REG_CPCCR 0x00 +#define CGU_REG_LCR 0x04 +#define CGU_REG_CPPCR 0x0c +#define CGU_REG_CPAPCR 0x10 +#define CGU_REG_CPMPCR 0x14 +#define CGU_REG_CPEPCR 0x18 +#define CGU_REG_CLKGR0 0x20 +#define CGU_REG_OPCR 0x24 +#define CGU_REG_CLKGR1 0x28 +#define CGU_REG_DDRCDR 0x2c +#define CGU_REG_ISPCDR 0x30 +#define CGU_REG_CPSPR 0x34 +#define CGU_REG_CPSPPR 0x38 +#define CGU_REG_USBPCR 0x3c +#define CGU_REG_USBRDT 0x40 +#define CGU_REG_USBVBFIL 0x44 +#define CGU_REG_USBPCR1 0x48 +#define CGU_REG_MACPTPCDR 0x4c +#define CGU_REG_RSACDR 0x50 +#define CGU_REG_MACCDR 0x54 +#define CGU_REG_MAC0TXCDR 0x58 +#define CGU_REG_SSICDR 0x5c +#define CGU_REG_I2S0CDR 0x60 +#define CGU_REG_LPCDR 0x64 +#define CGU_REG_MSC0CDR 0x68 +#define CGU_REG_PWMCDR 0x6c +#define CGU_REG_I2S0CDR1 0x70 +#define CGU_REG_SFCCDR 0x74 +#define CGU_REG_CIMCDR 0x78 +#define CGU_REG_I2S1CDR 0x7c +#define CGU_REG_I2S1CDR1 0x80 +#define CGU_REG_I2S2CDR 0x84 +#define CGU_REG_I2S2CDR1 0x88 +#define CGU_REG_I2S3CDR 0x8c +#define CGU_REG_PSWC0ST 0x90 +#define CGU_REG_PSWC1ST 0x94 +#define CGU_REG_PSWC2ST 0x98 +#define CGU_REG_PSWC3ST 0x9c +#define CGU_REG_I2S3CDR1 0xa0 +#define CGU_REG_MSC1CDR 0xa4 +#define CGU_REG_MSC2CDR 0xa8 +#define CGU_REG_AUDIOCR 0xac +#define CGU_REG_CMP_INTR 0xb0 +#define CGU_REG_CMP_INTRE 0xb4 +#define CGU_REG_CMP_SFTINT 0xbc +#define CGU_REG_SRBC 0xc4 +#define CGU_REG_SLBC 0xc8 +#define CGU_REG_SLPC 0xcc +#define CGU_REG_DRCG 0xd0 +#define CGU_REG_CPCSR 0xd4 +#define CGU_REG_MAC1TXCDR 0xdc +#define CGU_REG_MAC0PHYC 0xe4 +#define CGU_REG_MAC1PHYC 0xe8 +#define CGU_REG_MESTSEL 0xec +#define CGU_REG_MEMPD0 0xf8 +#define CGU_REG_MEMPD1 0xfc + +/* bits within the OPCR register */ +#define OPCR_GATE_USBPHYCLK BIT(23) +#define OPCR_SPENDN BIT(7) + +/* bits within the I2SCDR register */ +#define I2SCDR_I2PCS_SHIFT 30 +#define I2SCDR_I2PCS_MASK (0x1 << I2SCDR_I2PCS_SHIFT) +#define I2SCDR_I2SDIV_M_SHIFT 20 +#define I2SCDR_I2SDIV_M_MASK (0x1ff << I2SCDR_I2SDIV_M_SHIFT) +#define I2SCDR_I2SDIV_N_SHIFT 0 +#define I2SCDR_I2SDIV_N_MASK (0xfffff << I2SCDR_I2SDIV_N_SHIFT) +#define I2SCDR_CE_I2S BIT(29) + +/* bits within the CLKGR1 register */ +#define CLKGR1_I2S0 BIT(8) +#define CLKGR1_I2S1 BIT(9) +#define CLKGR1_I2S2 BIT(10) +#define CLKGR1_I2S3 BIT(11) + +static struct ingenic_cgu *cgu; + +static void x2000_i2s_calc_m_n(const struct ingenic_cgu_pll_info *pll_info, + unsigned long rate, unsigned long parent_rate, + unsigned int *pm, unsigned int *pn, unsigned int *pod) +{ + unsigned int delta, m, n; + u64 curr_delta, curr_m, curr_n; + + if ((parent_rate % rate == 0) && ((parent_rate / rate) > 1)) { + m = 1; + n = parent_rate / rate; + goto out; + } + + delta = rate; + + /* + * The length of M is 9 bits, its value must be between 1 and 511. + * The length of N is 20 bits, its value must be between 2 and 1048575, + * and must not be less than 2 times of the value of M. + */ + for (curr_m = 511; curr_m >= 1; curr_m--) { + curr_n = parent_rate * curr_m; + curr_delta = do_div(curr_n, rate); + + if (curr_n < 2 * curr_m || curr_n > 1048575) + continue; + + if (curr_delta == 0) + break; + + if (curr_delta < delta) { + m = curr_m; + n = curr_n; + delta = curr_delta; + } + } + +out: + *pm = m; + *pn = n; + + /* + * The I2S PLL does not have OD bits, so set the *pod to 1 to ensure + * that the ingenic_pll_calc() in cgu.c can run properly. + */ + *pod = 1; +} + +static int x2000_usb_phy_enable(struct clk_hw *hw) +{ + void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; + + writel((readl(reg_opcr) | OPCR_SPENDN) & ~OPCR_GATE_USBPHYCLK, reg_opcr); + + return 0; +} + +static void x2000_usb_phy_disable(struct clk_hw *hw) +{ + void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; + + writel((readl(reg_opcr) & ~OPCR_SPENDN) | OPCR_GATE_USBPHYCLK, reg_opcr); +} + +static int x2000_usb_phy_is_enabled(struct clk_hw *hw) +{ + void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; + + return !!(readl(reg_opcr) & OPCR_SPENDN); +} + +static const struct clk_ops x2000_otg_phy_ops = { + .enable = x2000_usb_phy_enable, + .disable = x2000_usb_phy_disable, + .is_enabled = x2000_usb_phy_is_enabled, +}; + +static const s8 pll_od_encoding[64] = { + -1, 0x1, -1, 0x2, -1, -1, -1, 0x3, + -1, -1, -1, -1, -1, -1, -1, 0x4, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 0x5, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 0x6, +}; + +static const struct ingenic_cgu_clk_info x2000_cgu_clocks[] = { + + /* External clocks */ + + [X2000_CLK_EXCLK] = { "ext", CGU_CLK_EXT }, + [X2000_CLK_RTCLK] = { "rtc", CGU_CLK_EXT }, + + /* PLLs */ + + [X2000_CLK_APLL] = { + "apll", CGU_CLK_PLL, + .parents = { X2000_CLK_EXCLK, -1, -1, -1 }, + .pll = { + .reg = CGU_REG_CPAPCR, + .rate_multiplier = 2, + .m_shift = 20, + .m_bits = 9, + .m_offset = 1, + .n_shift = 14, + .n_bits = 6, + .n_offset = 1, + .od_shift = 11, + .od_bits = 3, + .od_max = 64, + .od_encoding = pll_od_encoding, + .bypass_reg = CGU_REG_CPPCR, + .bypass_bit = 30, + .enable_bit = 0, + .stable_bit = 3, + }, + }, + + [X2000_CLK_MPLL] = { + "mpll", CGU_CLK_PLL, + .parents = { X2000_CLK_EXCLK, -1, -1, -1 }, + .pll = { + .reg = CGU_REG_CPMPCR, + .rate_multiplier = 2, + .m_shift = 20, + .m_bits = 10, + .m_offset = 1, + .n_shift = 14, + .n_bits = 6, + .n_offset = 1, + .od_shift = 11, + .od_bits = 3, + .od_max = 64, + .od_encoding = pll_od_encoding, + .bypass_reg = CGU_REG_CPPCR, + .bypass_bit = 28, + .enable_bit = 0, + .stable_bit = 3, + }, + }, + + [X2000_CLK_EPLL] = { + "epll", CGU_CLK_PLL, + .parents = { X2000_CLK_EXCLK, -1, -1, -1 }, + .pll = { + .reg = CGU_REG_CPEPCR, + .rate_multiplier = 2, + .m_shift = 20, + .m_bits = 10, + .m_offset = 1, + .n_shift = 14, + .n_bits = 6, + .n_offset = 1, + .od_shift = 11, + .od_bits = 3, + .od_max = 64, + .od_encoding = pll_od_encoding, + .bypass_reg = CGU_REG_CPPCR, + .bypass_bit = 26, + .enable_bit = 0, + .stable_bit = 3, + }, + }, + + [X2000_CLK_I2S0] = { + "i2s0", CGU_CLK_PLL, + .parents = { X2000_CLK_SCLKA, X2000_CLK_EPLL, -1, -1 }, + .pll = { + .reg = CGU_REG_I2S0CDR, + .rate_multiplier = 1, + .mux_shift = 30, + .mux_bits = 1, + .m_shift = 20, + .m_bits = 9, + .m_offset = 0, + .n_shift = 0, + .n_bits = 20, + .n_offset = 0, + .bypass_bit = -1, + .enable_bit = 29, + .stable_bit = -1, + .calc_m_n_od = x2000_i2s_calc_m_n, + }, + }, + + [X2000_CLK_I2S1] = { + "i2s1", CGU_CLK_PLL, + .parents = { X2000_CLK_SCLKA, X2000_CLK_EPLL, -1, -1 }, + .pll = { + .reg = CGU_REG_I2S1CDR, + .rate_multiplier = 1, + .mux_shift = 30, + .mux_bits = 1, + .m_shift = 20, + .m_bits = 9, + .m_offset = 0, + .n_shift = 0, + .n_bits = 20, + .n_offset = 0, + .bypass_bit = -1, + .enable_bit = 29, + .stable_bit = -1, + .calc_m_n_od = x2000_i2s_calc_m_n, + }, + }, + + [X2000_CLK_I2S2] = { + "i2s2", CGU_CLK_PLL, + .parents = { X2000_CLK_SCLKA, X2000_CLK_EPLL, -1, -1 }, + .pll = { + .reg = CGU_REG_I2S2CDR, + .rate_multiplier = 1, + .mux_shift = 30, + .mux_bits = 1, + .m_shift = 20, + .m_bits = 9, + .m_offset = 0, + .n_shift = 0, + .n_bits = 20, + .n_offset = 0, + .bypass_bit = -1, + .enable_bit = 29, + .stable_bit = -1, + .calc_m_n_od = x2000_i2s_calc_m_n, + }, + }, + + [X2000_CLK_I2S3] = { + "i2s3", CGU_CLK_PLL, + .parents = { X2000_CLK_SCLKA, X2000_CLK_EPLL, -1, -1 }, + .pll = { + .reg = CGU_REG_I2S3CDR, + .rate_multiplier = 1, + .mux_shift = 30, + .mux_bits = 1, + .m_shift = 20, + .m_bits = 9, + .m_offset = 0, + .n_shift = 0, + .n_bits = 20, + .n_offset = 0, + .bypass_bit = -1, + .enable_bit = 29, + .stable_bit = -1, + .calc_m_n_od = x2000_i2s_calc_m_n, + }, + }, + + /* Custom (SoC-specific) OTG PHY */ + + [X2000_CLK_OTGPHY] = { + "otg_phy", CGU_CLK_CUSTOM, + .parents = { X2000_CLK_EXCLK, -1, -1, -1 }, + .custom = { &x2000_otg_phy_ops }, + }, + + /* Muxes & dividers */ + + [X2000_CLK_SCLKA] = { + "sclk_a", CGU_CLK_MUX, + .parents = { -1, X2000_CLK_EXCLK, X2000_CLK_APLL, -1 }, + .mux = { CGU_REG_CPCCR, 30, 2 }, + }, + + [X2000_CLK_CPUMUX] = { + "cpu_mux", CGU_CLK_MUX, + .parents = { -1, X2000_CLK_SCLKA, X2000_CLK_MPLL, -1 }, + .mux = { CGU_REG_CPCCR, 28, 2 }, + }, + + [X2000_CLK_CPU] = { + "cpu", CGU_CLK_DIV, + .parents = { X2000_CLK_CPUMUX }, + .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 }, + }, + + [X2000_CLK_L2CACHE] = { + "l2cache", CGU_CLK_DIV, + .parents = { X2000_CLK_CPUMUX }, + .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 }, + }, + + [X2000_CLK_AHB0] = { + "ahb0", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { -1, X2000_CLK_SCLKA, X2000_CLK_MPLL, -1 }, + .mux = { CGU_REG_CPCCR, 26, 2 }, + .div = { CGU_REG_CPCCR, 8, 1, 4, 21, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 29 }, + }, + + [X2000_CLK_AHB2PMUX] = { + "ahb2_apb_mux", CGU_CLK_MUX, + .parents = { -1, X2000_CLK_SCLKA, X2000_CLK_MPLL, -1 }, + .mux = { CGU_REG_CPCCR, 24, 2 }, + }, + + [X2000_CLK_AHB2] = { + "ahb2", CGU_CLK_DIV, + .parents = { X2000_CLK_AHB2PMUX }, + .div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 }, + }, + + [X2000_CLK_PCLK] = { + "pclk", CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X2000_CLK_AHB2PMUX }, + .div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 28 }, + }, + + [X2000_CLK_DDR] = { + "ddr", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { -1, X2000_CLK_SCLKA, X2000_CLK_MPLL, -1 }, + .mux = { CGU_REG_DDRCDR, 30, 2 }, + .div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR0, 31 }, + }, + + [X2000_CLK_ISP] = { + "isp", CGU_CLK_MUX | CGU_CLK_DIV, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_EPLL, -1 }, + .mux = { CGU_REG_ISPCDR, 30, 2 }, + .div = { CGU_REG_ISPCDR, 0, 1, 4, 29, 28, 27 }, + }, + + [X2000_CLK_MACPTP] = { + "mac_ptp", CGU_CLK_MUX | CGU_CLK_DIV, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_EPLL, -1 }, + .mux = { CGU_REG_MACPTPCDR, 30, 2 }, + .div = { CGU_REG_MACPTPCDR, 0, 1, 8, 29, 28, 27 }, + }, + + [X2000_CLK_MACPHY] = { + "mac_phy", CGU_CLK_MUX | CGU_CLK_DIV, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_EPLL, -1 }, + .mux = { CGU_REG_MACCDR, 30, 2 }, + .div = { CGU_REG_MACCDR, 0, 1, 8, 29, 28, 27 }, + }, + + [X2000_CLK_MAC0TX] = { + "mac0_tx", CGU_CLK_MUX | CGU_CLK_DIV, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_EPLL, -1 }, + .mux = { CGU_REG_MAC0TXCDR, 30, 2 }, + .div = { CGU_REG_MAC0TXCDR, 0, 1, 8, 29, 28, 27 }, + }, + + [X2000_CLK_MAC1TX] = { + "mac1_tx", CGU_CLK_MUX | CGU_CLK_DIV, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_EPLL, -1 }, + .mux = { CGU_REG_MAC1TXCDR, 30, 2 }, + .div = { CGU_REG_MAC1TXCDR, 0, 1, 8, 29, 28, 27 }, + }, + + [X2000_CLK_RSA] = { + "rsa", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_EXCLK, -1 }, + .mux = { CGU_REG_LPCDR, 30, 2 }, + .div = { CGU_REG_LPCDR, 0, 1, 4, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR0, 25 }, + }, + + [X2000_CLK_SSIPLL] = { + "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_EPLL, -1 }, + .mux = { CGU_REG_SSICDR, 30, 2 }, + .div = { CGU_REG_SSICDR, 0, 1, 8, 29, 28, 27 }, + }, + + [X2000_CLK_LCD] = { + "lcd", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_EXCLK, -1 }, + .mux = { CGU_REG_LPCDR, 30, 2 }, + .div = { CGU_REG_LPCDR, 0, 1, 8, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR0, 23 }, + }, + + [X2000_CLK_MSC_EXCLK] = { + "msc_exclk", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_MSC0CDR, 21, true }, + }, + + [X2000_CLK_MSC0] = { + "msc0", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_MSC_EXCLK, -1 }, + .mux = { CGU_REG_MSC0CDR, 30, 2 }, + .div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR0, 4 }, + }, + + [X2000_CLK_MSC1] = { + "msc1", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_MSC_EXCLK, -1 }, + .mux = { CGU_REG_MSC1CDR, 30, 2 }, + .div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR0, 5 }, + }, + + [X2000_CLK_MSC2] = { + "msc2", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_MSC_EXCLK, -1 }, + .mux = { CGU_REG_MSC2CDR, 30, 2 }, + .div = { CGU_REG_MSC2CDR, 0, 2, 8, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR1, 25 }, + }, + + [X2000_CLK_PWM] = { + "pwm", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_EPLL, -1 }, + .mux = { CGU_REG_PWMCDR, 30, 2 }, + .div = { CGU_REG_PWMCDR, 0, 1, 4, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR1, 5 }, + }, + + [X2000_CLK_SFC] = { + "sfc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_EPLL, -1 }, + .mux = { CGU_REG_SFCCDR, 30, 2 }, + .div = { CGU_REG_SFCCDR, 0, 1, 8, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR0, 2 }, + }, + + [X2000_CLK_CIM] = { + "cim", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X2000_CLK_SCLKA, X2000_CLK_MPLL, X2000_CLK_EPLL, -1 }, + .mux = { CGU_REG_CIMCDR, 30, 2 }, + .div = { CGU_REG_CIMCDR, 0, 1, 8, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR0, 22 }, + }, + + [X2000_CLK_DMIC_EXCLK] = { + "dmic_exclk", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_AUDIOCR, 31 }, + }, + + [X2000_CLK_DMIC] = { + "dmic", CGU_CLK_MUX | CGU_CLK_GATE, + .parents = { X2000_CLK_DMIC_EXCLK, X2000_CLK_I2S3 }, + .mux = { CGU_REG_AUDIOCR, 0, 1}, + .gate = { CGU_REG_CLKGR1, 13 }, + }, + + [X2000_CLK_EXCLK_DIV512] = { + "exclk_div512", CGU_CLK_FIXDIV, + .parents = { X2000_CLK_EXCLK }, + .fixdiv = { 512 }, + }, + + [X2000_CLK_RTC] = { + "rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK_DIV512, X2000_CLK_RTCLK }, + .mux = { CGU_REG_OPCR, 2, 1}, + .gate = { CGU_REG_CLKGR0, 27 }, + }, + + /* Gate-only clocks */ + + [X2000_CLK_EMC] = { + "emc", CGU_CLK_GATE, + .parents = { X2000_CLK_AHB2 }, + .gate = { CGU_REG_CLKGR0, 0 }, + }, + + [X2000_CLK_EFUSE] = { + "efuse", CGU_CLK_GATE, + .parents = { X2000_CLK_AHB2 }, + .gate = { CGU_REG_CLKGR0, 1 }, + }, + + [X2000_CLK_OTG] = { + "otg", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR0, 3 }, + }, + + [X2000_CLK_SCC] = { + "scc", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR0, 6 }, + }, + + [X2000_CLK_I2C0] = { + "i2c0", CGU_CLK_GATE, + .parents = { X2000_CLK_PCLK }, + .gate = { CGU_REG_CLKGR0, 7 }, + }, + + [X2000_CLK_I2C1] = { + "i2c1", CGU_CLK_GATE, + .parents = { X2000_CLK_PCLK }, + .gate = { CGU_REG_CLKGR0, 8 }, + }, + + [X2000_CLK_I2C2] = { + "i2c2", CGU_CLK_GATE, + .parents = { X2000_CLK_PCLK }, + .gate = { CGU_REG_CLKGR0, 9 }, + }, + + [X2000_CLK_I2C3] = { + "i2c3", CGU_CLK_GATE, + .parents = { X2000_CLK_PCLK }, + .gate = { CGU_REG_CLKGR0, 10 }, + }, + + [X2000_CLK_SADC] = { + "sadc", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR0, 13 }, + }, + + [X2000_CLK_UART0] = { + "uart0", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR0, 14 }, + }, + + [X2000_CLK_UART1] = { + "uart1", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR0, 15 }, + }, + + [X2000_CLK_UART2] = { + "uart2", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR0, 16 }, + }, + + [X2000_CLK_DTRNG] = { + "dtrng", CGU_CLK_GATE, + .parents = { X2000_CLK_PCLK }, + .gate = { CGU_REG_CLKGR0, 17 }, + }, + + [X2000_CLK_TCU] = { + "tcu", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR0, 18 }, + }, + + [X2000_CLK_SSI0] = { + "ssi0", CGU_CLK_GATE, + .parents = { X2000_CLK_SSIPLL }, + .gate = { CGU_REG_CLKGR0, 19 }, + }, + + [X2000_CLK_OST] = { + "ost", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR0, 20 }, + }, + + [X2000_CLK_PDMA] = { + "pdma", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR0, 21 }, + }, + + [X2000_CLK_SSI1] = { + "ssi1", CGU_CLK_GATE, + .parents = { X2000_CLK_SSIPLL }, + .gate = { CGU_REG_CLKGR0, 26 }, + }, + + [X2000_CLK_I2C4] = { + "i2c4", CGU_CLK_GATE, + .parents = { X2000_CLK_PCLK }, + .gate = { CGU_REG_CLKGR1, 0 }, + }, + + [X2000_CLK_I2C5] = { + "i2c5", CGU_CLK_GATE, + .parents = { X2000_CLK_PCLK }, + .gate = { CGU_REG_CLKGR1, 1 }, + }, + + [X2000_CLK_ISP0] = { + "isp0", CGU_CLK_GATE, + .parents = { X2000_CLK_ISP }, + .gate = { CGU_REG_CLKGR1, 2 }, + }, + + [X2000_CLK_ISP1] = { + "isp1", CGU_CLK_GATE, + .parents = { X2000_CLK_ISP }, + .gate = { CGU_REG_CLKGR1, 3 }, + }, + + [X2000_CLK_HASH] = { + "hash", CGU_CLK_GATE, + .parents = { X2000_CLK_AHB2 }, + .gate = { CGU_REG_CLKGR1, 6 }, + }, + + [X2000_CLK_UART3] = { + "uart3", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR1, 16 }, + }, + + [X2000_CLK_UART4] = { + "uart4", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR1, 17 }, + }, + + [X2000_CLK_UART5] = { + "uart5", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR1, 18 }, + }, + + [X2000_CLK_UART6] = { + "uart6", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR1, 19 }, + }, + + [X2000_CLK_UART7] = { + "uart7", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR1, 20 }, + }, + + [X2000_CLK_UART8] = { + "uart8", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR1, 21 }, + }, + + [X2000_CLK_UART9] = { + "uart9", CGU_CLK_GATE, + .parents = { X2000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR1, 22 }, + }, + + [X2000_CLK_MAC0] = { + "mac0", CGU_CLK_GATE, + .parents = { X2000_CLK_AHB2 }, + .gate = { CGU_REG_CLKGR1, 23 }, + }, + + [X2000_CLK_MAC1] = { + "mac1", CGU_CLK_GATE, + .parents = { X2000_CLK_AHB2 }, + .gate = { CGU_REG_CLKGR1, 24 }, + }, + + [X2000_CLK_INTC] = { + "intc", CGU_CLK_GATE, + .parents = { X2000_CLK_AHB2 }, + .gate = { CGU_REG_CLKGR1, 26 }, + }, + + [X2000_CLK_CSI] = { + "csi", CGU_CLK_GATE, + .parents = { X2000_CLK_AHB0 }, + .gate = { CGU_REG_CLKGR1, 28 }, + }, + + [X2000_CLK_DSI] = { + "dsi", CGU_CLK_GATE, + .parents = { X2000_CLK_AHB0 }, + .gate = { CGU_REG_CLKGR1, 29 }, + }, +}; + +static void __init x2000_cgu_init(struct device_node *np) +{ + int retval; + + cgu = ingenic_cgu_new(x2000_cgu_clocks, + ARRAY_SIZE(x2000_cgu_clocks), np); + if (!cgu) { + pr_err("%s: failed to initialise CGU\n", __func__); + return; + } + + retval = ingenic_cgu_register_clocks(cgu); + if (retval) { + pr_err("%s: failed to register CGU Clocks\n", __func__); + return; + } + + ingenic_cgu_register_syscore_ops(cgu); +} + +/* + * CGU has some children devices, this is useful for probing children devices + * in the case where the device node is compatible with "simple-mfd". + */ +CLK_OF_DECLARE_DRIVER(x2000_cgu, "ingenic,x2000-cgu", x2000_cgu_init); -- 2.7.4