diff mbox series

[v7,10/11] clk: Ingenic: Add CGU driver for JZ4775.

Message ID 1627119286-125821-11-git-send-email-zhouyanjie@wanyeetech.com (mailing list archive)
State Superseded, archived
Headers show
Series Add new clocks and fix bugs for Ingenic SoCs. | expand

Commit Message

Zhou Yanjie July 24, 2021, 9:34 a.m. UTC
Add support for the clocks provided by the CGU in the Ingenic JZ4775
SoC, making use of the cgu code to do the heavy lifting.

Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
---

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/jz4775-cgu.c | 572 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 583 insertions(+)
 create mode 100644 drivers/clk/ingenic/jz4775-cgu.c
diff mbox series

Patch

diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig
index 898f1bc..7fda7bb 100644
--- a/drivers/clk/ingenic/Kconfig
+++ b/drivers/clk/ingenic/Kconfig
@@ -45,6 +45,16 @@  config INGENIC_CGU_JZ4770
 
 	  If building for a JZ4770 SoC, you want to say Y here.
 
+config INGENIC_CGU_JZ4775
+	bool "Ingenic JZ4775 CGU driver"
+	default MACH_JZ4775
+	select INGENIC_CGU_COMMON
+	help
+	  Support the clocks provided by the CGU hardware on Ingenic JZ4775
+	  and compatible SoCs.
+
+	  If building for a JZ4775 SoC, you want to say Y here.
+
 config INGENIC_CGU_JZ4780
 	bool "Ingenic JZ4780 CGU driver"
 	default MACH_JZ4780
diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index 9edfaf4..aed8da4 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -4,6 +4,7 @@  obj-$(CONFIG_INGENIC_CGU_JZ4740)	+= jz4740-cgu.o
 obj-$(CONFIG_INGENIC_CGU_JZ4725B)	+= jz4725b-cgu.o
 obj-$(CONFIG_INGENIC_CGU_JZ4760)	+= jz4760-cgu.o
 obj-$(CONFIG_INGENIC_CGU_JZ4770)	+= jz4770-cgu.o
+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
diff --git a/drivers/clk/ingenic/jz4775-cgu.c b/drivers/clk/ingenic/jz4775-cgu.c
new file mode 100644
index 00000000..5c8a227
--- /dev/null
+++ b/drivers/clk/ingenic/jz4775-cgu.c
@@ -0,0 +1,572 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * JZ4775 SoC CGU driver
+ * Copyright (c) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <dt-bindings/clock/jz4775-cgu.h>
+
+#include "cgu.h"
+#include "pm.h"
+
+/* CGU register offsets */
+#define CGU_REG_CPCCR			0x00
+#define CGU_REG_APLL			0x10
+#define CGU_REG_MPLL			0x14
+#define CGU_REG_CLKGR			0x20
+#define CGU_REG_OPCR			0x24
+#define CGU_REG_DDRCDR			0x2c
+#define CGU_REG_VPUCDR			0x30
+#define CGU_REG_USBPCR			0x3c
+#define CGU_REG_USBPCR1			0x48
+#define CGU_REG_USBCDR			0x50
+#define CGU_REG_I2SCDR			0x60
+#define CGU_REG_LPCDR			0x64
+#define CGU_REG_MSC0CDR			0x68
+#define CGU_REG_UHCCDR			0x6c
+#define CGU_REG_SSICDR			0x74
+#define CGU_REG_CIM0CDR			0x7c
+#define CGU_REG_CIM1CDR			0x80
+#define CGU_REG_PCMCDR			0x84
+#define CGU_REG_MSC1CDR			0xa4
+#define CGU_REG_MSC2CDR			0xa8
+#define CGU_REG_BCHCDR			0xac
+#define CGU_REG_CMP_INTR		0xb0
+#define CGU_REG_CMP_INTRE		0xb4
+#define CGU_REG_SRBC			0xc4
+#define CGU_REG_DRCG			0xd0
+#define CGU_REG_CPCSR			0xd4
+#define CGU_REG_MACPHYC			0xe0
+
+/* bits within the OPCR register */
+#define OPCR_SPENDN0			BIT(7)
+
+/* bits within the USBPCR register */
+#define USBPCR_SIDDQ			BIT(21)
+#define USBPCR_OTG_DISABLE		BIT(20)
+
+/* bits within the USBPCR1 register */
+#define USBPCR1_REFCLKDIV_SHIFT	24
+#define USBPCR1_REFCLKDIV_MASK	(0x3 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_19_2	(0x3 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_48	(0x2 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_24	(0x1 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_12	(0x0 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_PDBAR			BIT(17)
+#define USBPCR1_XP_SHIFT		12
+#define USBPCR1_XP_MASK			(0x3 << USBPCR1_XP_SHIFT)
+#define USBPCR1_XP_DFT			(0x1 << USBPCR1_XP_SHIFT)
+#define USBPCR1_SM_SHIFT		6
+#define USBPCR1_SM_MASK			(0x7 << USBPCR1_XP_SHIFT)
+#define USBPCR1_SM_RPD			(0x1 << USBPCR1_XP_SHIFT)
+
+static struct ingenic_cgu *cgu;
+
+static int jz4775_uhc_phy_enable(struct clk_hw *hw)
+{
+	void __iomem *reg_usbpcr1	= cgu->base + CGU_REG_USBPCR1;
+	u32	usbpcr1;
+
+	usbpcr1 = readl(reg_usbpcr1);
+	usbpcr1 &= ~(USBPCR1_XP_MASK | USBPCR1_SM_MASK);
+	usbpcr1 |= USBPCR1_XP_DFT | USBPCR1_SM_RPD;
+	writel(usbpcr1, reg_usbpcr1);
+
+	return 0;
+}
+
+static void jz4775_uhc_phy_disable(struct clk_hw *hw)
+{
+	void __iomem *reg_usbpcr1	= cgu->base + CGU_REG_USBPCR1;
+
+	writel(readl(reg_usbpcr1) & ~USBPCR1_PDBAR, reg_usbpcr1);
+}
+
+static int jz4775_uhc_phy_is_enabled(struct clk_hw *hw)
+{
+	void __iomem *reg_usbpcr1	= cgu->base + CGU_REG_USBPCR1;
+
+	return !!(readl(reg_usbpcr1) & USBPCR1_PDBAR);
+}
+
+static const struct clk_ops jz4775_uhc_phy_ops = {
+	.enable = jz4775_uhc_phy_enable,
+	.disable = jz4775_uhc_phy_disable,
+	.is_enabled = jz4775_uhc_phy_is_enabled,
+};
+
+static unsigned long jz4775_otg_phy_recalc_rate(struct clk_hw *hw,
+						unsigned long parent_rate)
+{
+	u32 usbpcr1;
+	unsigned refclk_div;
+
+	usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
+	refclk_div = usbpcr1 & USBPCR1_REFCLKDIV_MASK;
+
+	switch (refclk_div) {
+	case USBPCR1_REFCLKDIV_12:
+		return 12000000;
+
+	case USBPCR1_REFCLKDIV_24:
+		return 24000000;
+
+	case USBPCR1_REFCLKDIV_48:
+		return 48000000;
+
+	case USBPCR1_REFCLKDIV_19_2:
+		return 19200000;
+	}
+
+	return parent_rate;
+}
+
+static long jz4775_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate,
+				      unsigned long *parent_rate)
+{
+	if (req_rate < 15600000)
+		return 12000000;
+
+	if (req_rate < 21600000)
+		return 19200000;
+
+	if (req_rate < 36000000)
+		return 24000000;
+
+	return 48000000;
+}
+
+static int jz4775_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
+				   unsigned long parent_rate)
+{
+	unsigned long flags;
+	u32 usbpcr1, div_bits;
+
+	switch (req_rate) {
+	case 12000000:
+		div_bits = USBPCR1_REFCLKDIV_12;
+		break;
+
+	case 19200000:
+		div_bits = USBPCR1_REFCLKDIV_19_2;
+		break;
+
+	case 24000000:
+		div_bits = USBPCR1_REFCLKDIV_24;
+		break;
+
+	case 48000000:
+		div_bits = USBPCR1_REFCLKDIV_48;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&cgu->lock, flags);
+
+	usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
+	usbpcr1 &= ~USBPCR1_REFCLKDIV_MASK;
+	usbpcr1 |= div_bits;
+	writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
+
+	spin_unlock_irqrestore(&cgu->lock, flags);
+
+	return 0;
+}
+
+static int jz4775_otg_phy_enable(struct clk_hw *hw)
+{
+	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;
+	void __iomem *reg_usbpcr	= cgu->base + CGU_REG_USBPCR;
+
+	writel(readl(reg_opcr) | OPCR_SPENDN0, reg_opcr);
+	writel(readl(reg_usbpcr) & ~USBPCR_OTG_DISABLE & ~USBPCR_SIDDQ, reg_usbpcr);
+
+	return 0;
+}
+
+static void jz4775_otg_phy_disable(struct clk_hw *hw)
+{
+	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;
+	void __iomem *reg_usbpcr	= cgu->base + CGU_REG_USBPCR;
+
+	writel(readl(reg_opcr) & ~OPCR_SPENDN0, reg_opcr);
+	writel(readl(reg_usbpcr) | USBPCR_OTG_DISABLE | USBPCR_SIDDQ, reg_usbpcr);
+}
+
+static int jz4775_otg_phy_is_enabled(struct clk_hw *hw)
+{
+	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;
+	void __iomem *reg_usbpcr	= cgu->base + CGU_REG_USBPCR;
+
+	return (readl(reg_opcr) & OPCR_SPENDN0) &&
+		!(readl(reg_usbpcr) & USBPCR_SIDDQ) &&
+		!(readl(reg_usbpcr) & USBPCR_OTG_DISABLE);
+}
+
+static const struct clk_ops jz4775_otg_phy_ops = {
+	.recalc_rate = jz4775_otg_phy_recalc_rate,
+	.round_rate = jz4775_otg_phy_round_rate,
+	.set_rate = jz4775_otg_phy_set_rate,
+
+	.enable = jz4775_otg_phy_enable,
+	.disable = jz4775_otg_phy_disable,
+	.is_enabled = jz4775_otg_phy_is_enabled,
+};
+
+static const s8 pll_od_encoding[8] = {
+	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
+};
+
+static const struct ingenic_cgu_clk_info jz4775_cgu_clocks[] = {
+
+	/* External clocks */
+
+	[JZ4775_CLK_EXCLK] = { "ext", CGU_CLK_EXT },
+	[JZ4775_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },
+
+	/* PLLs */
+
+	[JZ4775_CLK_APLL] = {
+		"apll", CGU_CLK_PLL,
+		.parents = { JZ4775_CLK_EXCLK, -1, -1, -1 },
+		.pll = {
+			.reg = CGU_REG_APLL,
+			.rate_multiplier = 1,
+			.m_shift = 24,
+			.m_bits = 7,
+			.m_offset = 1,
+			.n_shift = 18,
+			.n_bits = 5,
+			.n_offset = 1,
+			.od_shift = 16,
+			.od_bits = 2,
+			.od_max = 8,
+			.od_encoding = pll_od_encoding,
+			.bypass_reg = CGU_REG_APLL,
+			.bypass_bit = 9,
+			.enable_bit = 8,
+			.stable_bit = 10,
+		},
+	},
+
+	[JZ4775_CLK_MPLL] = {
+		"mpll", CGU_CLK_PLL,
+		.parents = { JZ4775_CLK_EXCLK, -1, -1, -1 },
+		.pll = {
+			.reg = CGU_REG_MPLL,
+			.rate_multiplier = 1,
+			.m_shift = 24,
+			.m_bits = 7,
+			.m_offset = 1,
+			.n_shift = 18,
+			.n_bits = 5,
+			.n_offset = 1,
+			.od_shift = 16,
+			.od_bits = 2,
+			.od_max = 8,
+			.od_encoding = pll_od_encoding,
+			.bypass_reg = CGU_REG_MPLL,
+			.bypass_bit = 6,
+			.enable_bit = 7,
+			.stable_bit = 0,
+		},
+	},
+
+	/* Custom (SoC-specific) */
+
+	[JZ4775_CLK_UHCPHY] = {
+		"uhc_phy", CGU_CLK_CUSTOM,
+		.parents = { JZ4775_CLK_UHC, -1, -1, -1 },
+		.custom = { &jz4775_uhc_phy_ops },
+	},
+
+	[JZ4775_CLK_OTGPHY] = {
+		"otg_phy", CGU_CLK_CUSTOM,
+		.parents = { JZ4775_CLK_EXCLK, -1, -1, -1 },
+		.custom = { &jz4775_otg_phy_ops },
+	},
+
+	/* Muxes & dividers */
+
+	[JZ4775_CLK_SCLKA] = {
+		"sclk_a", CGU_CLK_MUX,
+		.parents = { -1, JZ4775_CLK_APLL, JZ4775_CLK_EXCLK, JZ4775_CLK_RTCLK },
+		.mux = { CGU_REG_CPCCR, 30, 2 },
+	},
+
+	[JZ4775_CLK_CPUMUX] = {
+		"cpu_mux", CGU_CLK_MUX,
+		.parents = { -1, JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL, -1 },
+		.mux = { CGU_REG_CPCCR, 28, 2 },
+	},
+
+	[JZ4775_CLK_CPU] = {
+		"cpu", CGU_CLK_DIV,
+		.parents = { JZ4775_CLK_CPUMUX },
+		.div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+	},
+
+	[JZ4775_CLK_L2CACHE] = {
+		"l2cache", CGU_CLK_DIV,
+		.parents = { JZ4775_CLK_CPUMUX },
+		.div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+	},
+
+	[JZ4775_CLK_AHB0] = {
+		"ahb0", CGU_CLK_MUX | CGU_CLK_DIV,
+		.parents = { -1, JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL, -1 },
+		.mux = { CGU_REG_CPCCR, 26, 2 },
+		.div = { CGU_REG_CPCCR, 8, 1, 4, 21, -1, -1 },
+	},
+
+	[JZ4775_CLK_AHB2PMUX] = {
+		"ahb2_apb_mux", CGU_CLK_MUX,
+		.parents = { -1, JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL, JZ4775_CLK_RTCLK },
+		.mux = { CGU_REG_CPCCR, 24, 2 },
+	},
+
+	[JZ4775_CLK_AHB2] = {
+		"ahb2", CGU_CLK_DIV,
+		.parents = { JZ4775_CLK_AHB2PMUX },
+		.div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 },
+	},
+
+	[JZ4775_CLK_PCLK] = {
+		"pclk", CGU_CLK_DIV,
+		.parents = { JZ4775_CLK_AHB2PMUX },
+		.div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 },
+	},
+
+	[JZ4775_CLK_DDR] = {
+		"ddr", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { -1, JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL, -1 },
+		.mux = { CGU_REG_DDRCDR, 30, 2 },
+		.div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 },
+		.gate = { CGU_REG_CLKGR, 31 },
+	},
+
+	[JZ4775_CLK_VPU] = {
+		"vpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL },
+		.mux = { CGU_REG_VPUCDR, 31, 1 },
+		.div = { CGU_REG_VPUCDR, 0, 1, 4, 29, 28, 27 },
+		.gate = { CGU_REG_CLKGR, 19 },
+	},
+
+	[JZ4775_CLK_OTG] = {
+		"otg", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+		.parents = { JZ4775_CLK_EXCLK, -1, JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL },
+		.mux = { CGU_REG_USBCDR, 30, 2 },
+		.div = { CGU_REG_USBCDR, 0, 1, 8, 29, 28, 27 },
+		.gate = { CGU_REG_CLKGR, 2 },
+	},
+
+	[JZ4775_CLK_EXCLK_DIV2] = {
+		"exclk_div2", CGU_CLK_FIXDIV,
+		.parents = { JZ4775_CLK_EXCLK },
+		.fixdiv = { 2 },
+	},
+
+	[JZ4775_CLK_I2S] = {
+		"i2s", CGU_CLK_MUX | CGU_CLK_DIV,
+		.parents = { JZ4775_CLK_EXCLK_DIV2, -1, JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL },
+		.mux = { CGU_REG_I2SCDR, 30, 2 },
+		.div = { CGU_REG_I2SCDR, 0, 1, 8, 29, 28, 27 },
+	},
+
+	[JZ4775_CLK_LCD] = {
+		"lcd", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL },
+		.mux = { CGU_REG_LPCDR, 31, 1 },
+		.div = { CGU_REG_LPCDR, 0, 1, 8, 28, 27, 26 },
+		.gate = { CGU_REG_CLKGR, 25 },
+	},
+
+	[JZ4775_CLK_MSCMUX] = {
+		"msc_mux", CGU_CLK_MUX,
+		.parents = { -1, JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL, -1 },
+		.mux = { CGU_REG_MSC0CDR, 30, 2 },
+	},
+
+	[JZ4775_CLK_MSC0] = {
+		"msc0", CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_MSCMUX },
+		.div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 },
+		.gate = { CGU_REG_CLKGR, 3 },
+	},
+
+	[JZ4775_CLK_MSC1] = {
+		"msc1", CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_MSCMUX },
+		.div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 },
+		.gate = { CGU_REG_CLKGR, 11 },
+	},
+
+	[JZ4775_CLK_MSC2] = {
+		"msc2", CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_MSCMUX },
+		.div = { CGU_REG_MSC2CDR, 0, 2, 8, 29, 28, 27 },
+		.gate = { CGU_REG_CLKGR, 12 },
+	},
+
+	[JZ4775_CLK_UHC] = {
+		"uhc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL, JZ4775_CLK_OTGPHY, -1 },
+		.mux = { CGU_REG_UHCCDR, 30, 2 },
+		.div = { CGU_REG_UHCCDR, 0, 1, 8, 29, 28, 27 },
+		.gate = { CGU_REG_CLKGR, 22 },
+	},
+
+	[JZ4775_CLK_SSI] = {
+		"ssi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_EXCLK, -1, JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL },
+		.mux = { CGU_REG_SSICDR, 30, 2 },
+		.div = { CGU_REG_SSICDR, 0, 1, 8, 29, 28, 27 },
+		.gate = { CGU_REG_CLKGR, 4 },
+	},
+
+	[JZ4775_CLK_CIM0] = {
+		"cim0", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL },
+		.mux = { CGU_REG_CIM0CDR, 31, 1 },
+		.div = { CGU_REG_CIM0CDR, 0, 1, 8, 30, 29, 28 },
+		.gate = { CGU_REG_CLKGR, 23 },
+	},
+
+	[JZ4775_CLK_CIM1] = {
+		"cim1", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL },
+		.mux = { CGU_REG_CIM1CDR, 31, 1 },
+		.div = { CGU_REG_CIM1CDR, 0, 1, 8, 30, 29, 28 },
+		.gate = { CGU_REG_CLKGR, 24 },
+	},
+
+	[JZ4775_CLK_PCM] = {
+		"pcm", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_EXCLK_DIV2, -1, JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL },
+		.mux = { CGU_REG_PCMCDR, 30, 2 },
+		.div = { CGU_REG_PCMCDR, 0, 1, 8, 28, 27, 26 },
+		.gate = { CGU_REG_CLKGR, 13 },
+	},
+
+	[JZ4775_CLK_BCH] = {
+		"bch", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { -1, JZ4775_CLK_SCLKA, JZ4775_CLK_MPLL, -1 },
+		.mux = { CGU_REG_BCHCDR, 30, 2 },
+		.div = { CGU_REG_BCHCDR, 0, 1, 4, 29, 28, 27 },
+		.gate = { CGU_REG_CLKGR, 1 },
+	},
+
+	[JZ4775_CLK_EXCLK_DIV512] = {
+		"exclk_div512", CGU_CLK_FIXDIV,
+		.parents = { JZ4775_CLK_EXCLK },
+		.fixdiv = { 512 },
+	},
+
+	[JZ4775_CLK_RTC] = {
+		"rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_EXCLK_DIV512, JZ4775_CLK_RTCLK },
+		.mux = { CGU_REG_OPCR, 2, 1},
+	},
+
+	/* Gate-only clocks */
+
+	[JZ4775_CLK_NEMC] = {
+		"nemc", CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_AHB2 },
+		.gate = { CGU_REG_CLKGR, 0 },
+	},
+
+	[JZ4775_CLK_I2C0] = {
+		"i2c0", CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_PCLK },
+		.gate = { CGU_REG_CLKGR, 5 },
+	},
+
+	[JZ4775_CLK_I2C1] = {
+		"i2c1", CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_PCLK },
+		.gate = { CGU_REG_CLKGR, 6 },
+	},
+
+	[JZ4775_CLK_I2C2] = {
+		"i2c2", CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_PCLK },
+		.gate = { CGU_REG_CLKGR, 7 },
+	},
+
+	[JZ4775_CLK_SADC] = {
+		"sadc", CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_EXCLK },
+		.gate = { CGU_REG_CLKGR, 14 },
+	},
+
+	[JZ4775_CLK_UART0] = {
+		"uart0", CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_EXCLK },
+		.gate = { CGU_REG_CLKGR, 15 },
+	},
+
+	[JZ4775_CLK_UART1] = {
+		"uart1", CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_EXCLK },
+		.gate = { CGU_REG_CLKGR, 16 },
+	},
+
+	[JZ4775_CLK_UART2] = {
+		"uart2", CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_EXCLK },
+		.gate = { CGU_REG_CLKGR, 17 },
+	},
+
+	[JZ4775_CLK_UART3] = {
+		"uart3", CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_EXCLK },
+		.gate = { CGU_REG_CLKGR, 18 },
+	},
+
+	[JZ4775_CLK_PDMA] = {
+		"pdma", CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_EXCLK },
+		.gate = { CGU_REG_CLKGR, 20 },
+	},
+
+	[JZ4775_CLK_MAC] = {
+		"mac", CGU_CLK_GATE,
+		.parents = { JZ4775_CLK_AHB2 },
+		.gate = { CGU_REG_CLKGR, 21 },
+	},
+};
+
+static void __init jz4775_cgu_init(struct device_node *np)
+{
+	int retval;
+
+	cgu = ingenic_cgu_new(jz4775_cgu_clocks,
+			      ARRAY_SIZE(jz4775_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(jz4775_cgu, "ingenic,jz4775-cgu", jz4775_cgu_init);