162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * X1000 SoC CGU driver
462306a36Sopenharmony_ci * Copyright (c) 2019 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/clk-provider.h>
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <linux/io.h>
1062306a36Sopenharmony_ci#include <linux/of.h>
1162306a36Sopenharmony_ci#include <linux/rational.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <dt-bindings/clock/ingenic,x1000-cgu.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "cgu.h"
1662306a36Sopenharmony_ci#include "pm.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* CGU register offsets */
1962306a36Sopenharmony_ci#define CGU_REG_CPCCR		0x00
2062306a36Sopenharmony_ci#define CGU_REG_APLL		0x10
2162306a36Sopenharmony_ci#define CGU_REG_MPLL		0x14
2262306a36Sopenharmony_ci#define CGU_REG_CLKGR		0x20
2362306a36Sopenharmony_ci#define CGU_REG_OPCR		0x24
2462306a36Sopenharmony_ci#define CGU_REG_DDRCDR		0x2c
2562306a36Sopenharmony_ci#define CGU_REG_USBPCR		0x3c
2662306a36Sopenharmony_ci#define CGU_REG_USBPCR1		0x48
2762306a36Sopenharmony_ci#define CGU_REG_USBCDR		0x50
2862306a36Sopenharmony_ci#define CGU_REG_MACCDR		0x54
2962306a36Sopenharmony_ci#define CGU_REG_I2SCDR		0x60
3062306a36Sopenharmony_ci#define CGU_REG_LPCDR		0x64
3162306a36Sopenharmony_ci#define CGU_REG_MSC0CDR		0x68
3262306a36Sopenharmony_ci#define CGU_REG_I2SCDR1		0x70
3362306a36Sopenharmony_ci#define CGU_REG_SSICDR		0x74
3462306a36Sopenharmony_ci#define CGU_REG_CIMCDR		0x7c
3562306a36Sopenharmony_ci#define CGU_REG_PCMCDR		0x84
3662306a36Sopenharmony_ci#define CGU_REG_MSC1CDR		0xa4
3762306a36Sopenharmony_ci#define CGU_REG_CMP_INTR	0xb0
3862306a36Sopenharmony_ci#define CGU_REG_CMP_INTRE	0xb4
3962306a36Sopenharmony_ci#define CGU_REG_DRCG		0xd0
4062306a36Sopenharmony_ci#define CGU_REG_CPCSR		0xd4
4162306a36Sopenharmony_ci#define CGU_REG_PCMCDR1		0xe0
4262306a36Sopenharmony_ci#define CGU_REG_MACPHYC		0xe8
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* bits within the OPCR register */
4562306a36Sopenharmony_ci#define OPCR_SPENDN0		BIT(7)
4662306a36Sopenharmony_ci#define OPCR_SPENDN1		BIT(6)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* bits within the USBPCR register */
4962306a36Sopenharmony_ci#define USBPCR_SIDDQ		BIT(21)
5062306a36Sopenharmony_ci#define USBPCR_OTG_DISABLE	BIT(20)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* bits within the USBPCR1 register */
5362306a36Sopenharmony_ci#define USBPCR1_REFCLKSEL_SHIFT	26
5462306a36Sopenharmony_ci#define USBPCR1_REFCLKSEL_MASK	(0x3 << USBPCR1_REFCLKSEL_SHIFT)
5562306a36Sopenharmony_ci#define USBPCR1_REFCLKSEL_CORE	(0x2 << USBPCR1_REFCLKSEL_SHIFT)
5662306a36Sopenharmony_ci#define USBPCR1_REFCLKDIV_SHIFT	24
5762306a36Sopenharmony_ci#define USBPCR1_REFCLKDIV_MASK	(0x3 << USBPCR1_REFCLKDIV_SHIFT)
5862306a36Sopenharmony_ci#define USBPCR1_REFCLKDIV_48	(0x2 << USBPCR1_REFCLKDIV_SHIFT)
5962306a36Sopenharmony_ci#define USBPCR1_REFCLKDIV_24	(0x1 << USBPCR1_REFCLKDIV_SHIFT)
6062306a36Sopenharmony_ci#define USBPCR1_REFCLKDIV_12	(0x0 << USBPCR1_REFCLKDIV_SHIFT)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic struct ingenic_cgu *cgu;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic unsigned long x1000_otg_phy_recalc_rate(struct clk_hw *hw,
6562306a36Sopenharmony_ci						unsigned long parent_rate)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	u32 usbpcr1;
6862306a36Sopenharmony_ci	unsigned refclk_div;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
7162306a36Sopenharmony_ci	refclk_div = usbpcr1 & USBPCR1_REFCLKDIV_MASK;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	switch (refclk_div) {
7462306a36Sopenharmony_ci	case USBPCR1_REFCLKDIV_12:
7562306a36Sopenharmony_ci		return 12000000;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	case USBPCR1_REFCLKDIV_24:
7862306a36Sopenharmony_ci		return 24000000;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	case USBPCR1_REFCLKDIV_48:
8162306a36Sopenharmony_ci		return 48000000;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return parent_rate;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic long x1000_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate,
8862306a36Sopenharmony_ci				      unsigned long *parent_rate)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	if (req_rate < 18000000)
9162306a36Sopenharmony_ci		return 12000000;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (req_rate < 36000000)
9462306a36Sopenharmony_ci		return 24000000;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return 48000000;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic int x1000_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
10062306a36Sopenharmony_ci				   unsigned long parent_rate)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	unsigned long flags;
10362306a36Sopenharmony_ci	u32 usbpcr1, div_bits;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	switch (req_rate) {
10662306a36Sopenharmony_ci	case 12000000:
10762306a36Sopenharmony_ci		div_bits = USBPCR1_REFCLKDIV_12;
10862306a36Sopenharmony_ci		break;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	case 24000000:
11162306a36Sopenharmony_ci		div_bits = USBPCR1_REFCLKDIV_24;
11262306a36Sopenharmony_ci		break;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	case 48000000:
11562306a36Sopenharmony_ci		div_bits = USBPCR1_REFCLKDIV_48;
11662306a36Sopenharmony_ci		break;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	default:
11962306a36Sopenharmony_ci		return -EINVAL;
12062306a36Sopenharmony_ci	}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	spin_lock_irqsave(&cgu->lock, flags);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
12562306a36Sopenharmony_ci	usbpcr1 &= ~USBPCR1_REFCLKDIV_MASK;
12662306a36Sopenharmony_ci	usbpcr1 |= div_bits;
12762306a36Sopenharmony_ci	writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	spin_unlock_irqrestore(&cgu->lock, flags);
13062306a36Sopenharmony_ci	return 0;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic int x1000_usb_phy_enable(struct clk_hw *hw)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;
13662306a36Sopenharmony_ci	void __iomem *reg_usbpcr	= cgu->base + CGU_REG_USBPCR;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	writel(readl(reg_opcr) | OPCR_SPENDN0, reg_opcr);
13962306a36Sopenharmony_ci	writel(readl(reg_usbpcr) & ~USBPCR_OTG_DISABLE & ~USBPCR_SIDDQ, reg_usbpcr);
14062306a36Sopenharmony_ci	return 0;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic void x1000_usb_phy_disable(struct clk_hw *hw)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;
14662306a36Sopenharmony_ci	void __iomem *reg_usbpcr	= cgu->base + CGU_REG_USBPCR;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	writel(readl(reg_opcr) & ~OPCR_SPENDN0, reg_opcr);
14962306a36Sopenharmony_ci	writel(readl(reg_usbpcr) | USBPCR_OTG_DISABLE | USBPCR_SIDDQ, reg_usbpcr);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic int x1000_usb_phy_is_enabled(struct clk_hw *hw)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;
15562306a36Sopenharmony_ci	void __iomem *reg_usbpcr	= cgu->base + CGU_REG_USBPCR;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	return (readl(reg_opcr) & OPCR_SPENDN0) &&
15862306a36Sopenharmony_ci		!(readl(reg_usbpcr) & USBPCR_SIDDQ) &&
15962306a36Sopenharmony_ci		!(readl(reg_usbpcr) & USBPCR_OTG_DISABLE);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic const struct clk_ops x1000_otg_phy_ops = {
16362306a36Sopenharmony_ci	.recalc_rate = x1000_otg_phy_recalc_rate,
16462306a36Sopenharmony_ci	.round_rate = x1000_otg_phy_round_rate,
16562306a36Sopenharmony_ci	.set_rate = x1000_otg_phy_set_rate,
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	.enable		= x1000_usb_phy_enable,
16862306a36Sopenharmony_ci	.disable	= x1000_usb_phy_disable,
16962306a36Sopenharmony_ci	.is_enabled	= x1000_usb_phy_is_enabled,
17062306a36Sopenharmony_ci};
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic void
17362306a36Sopenharmony_cix1000_i2spll_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
17462306a36Sopenharmony_ci			 unsigned long rate, unsigned long parent_rate,
17562306a36Sopenharmony_ci			 unsigned int *pm, unsigned int *pn, unsigned int *pod)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	const unsigned long m_max = GENMASK(pll_info->m_bits - 1, 0);
17862306a36Sopenharmony_ci	const unsigned long n_max = GENMASK(pll_info->n_bits - 1, 0);
17962306a36Sopenharmony_ci	unsigned long m, n;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	rational_best_approximation(rate, parent_rate, m_max, n_max, &m, &n);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* n should not be less than 2*m */
18462306a36Sopenharmony_ci	if (n < 2 * m)
18562306a36Sopenharmony_ci		n = 2 * m;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	*pm = m;
18862306a36Sopenharmony_ci	*pn = n;
18962306a36Sopenharmony_ci	*pod = 1;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic void
19362306a36Sopenharmony_cix1000_i2spll_set_rate_hook(const struct ingenic_cgu_pll_info *pll_info,
19462306a36Sopenharmony_ci			   unsigned long rate, unsigned long parent_rate)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	/*
19762306a36Sopenharmony_ci	 * Writing 0 causes I2SCDR1.I2SDIV_D to be automatically recalculated
19862306a36Sopenharmony_ci	 * based on the current value of I2SCDR.I2SDIV_N, which is needed for
19962306a36Sopenharmony_ci	 * the divider to function correctly.
20062306a36Sopenharmony_ci	 */
20162306a36Sopenharmony_ci	writel(0, cgu->base + CGU_REG_I2SCDR1);
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic const s8 pll_od_encoding[8] = {
20562306a36Sopenharmony_ci	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
20662306a36Sopenharmony_ci};
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	/* External clocks */
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	[X1000_CLK_EXCLK] = { "ext", CGU_CLK_EXT },
21362306a36Sopenharmony_ci	[X1000_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	/* PLLs */
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	[X1000_CLK_APLL] = {
21862306a36Sopenharmony_ci		"apll", CGU_CLK_PLL,
21962306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK },
22062306a36Sopenharmony_ci		.pll = {
22162306a36Sopenharmony_ci			.reg = CGU_REG_APLL,
22262306a36Sopenharmony_ci			.rate_multiplier = 1,
22362306a36Sopenharmony_ci			.m_shift = 24,
22462306a36Sopenharmony_ci			.m_bits = 7,
22562306a36Sopenharmony_ci			.m_offset = 1,
22662306a36Sopenharmony_ci			.n_shift = 18,
22762306a36Sopenharmony_ci			.n_bits = 5,
22862306a36Sopenharmony_ci			.n_offset = 1,
22962306a36Sopenharmony_ci			.od_shift = 16,
23062306a36Sopenharmony_ci			.od_bits = 2,
23162306a36Sopenharmony_ci			.od_max = 8,
23262306a36Sopenharmony_ci			.od_encoding = pll_od_encoding,
23362306a36Sopenharmony_ci			.bypass_reg = CGU_REG_APLL,
23462306a36Sopenharmony_ci			.bypass_bit = 9,
23562306a36Sopenharmony_ci			.enable_bit = 8,
23662306a36Sopenharmony_ci			.stable_bit = 10,
23762306a36Sopenharmony_ci		},
23862306a36Sopenharmony_ci	},
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	[X1000_CLK_MPLL] = {
24162306a36Sopenharmony_ci		"mpll", CGU_CLK_PLL,
24262306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK },
24362306a36Sopenharmony_ci		.pll = {
24462306a36Sopenharmony_ci			.reg = CGU_REG_MPLL,
24562306a36Sopenharmony_ci			.rate_multiplier = 1,
24662306a36Sopenharmony_ci			.m_shift = 24,
24762306a36Sopenharmony_ci			.m_bits = 7,
24862306a36Sopenharmony_ci			.m_offset = 1,
24962306a36Sopenharmony_ci			.n_shift = 18,
25062306a36Sopenharmony_ci			.n_bits = 5,
25162306a36Sopenharmony_ci			.n_offset = 1,
25262306a36Sopenharmony_ci			.od_shift = 16,
25362306a36Sopenharmony_ci			.od_bits = 2,
25462306a36Sopenharmony_ci			.od_max = 8,
25562306a36Sopenharmony_ci			.od_encoding = pll_od_encoding,
25662306a36Sopenharmony_ci			.bypass_reg = CGU_REG_MPLL,
25762306a36Sopenharmony_ci			.bypass_bit = 6,
25862306a36Sopenharmony_ci			.enable_bit = 7,
25962306a36Sopenharmony_ci			.stable_bit = 0,
26062306a36Sopenharmony_ci		},
26162306a36Sopenharmony_ci	},
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* Custom (SoC-specific) OTG PHY */
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	[X1000_CLK_OTGPHY] = {
26662306a36Sopenharmony_ci		"otg_phy", CGU_CLK_CUSTOM,
26762306a36Sopenharmony_ci		.parents = { -1, -1, X1000_CLK_EXCLK, -1 },
26862306a36Sopenharmony_ci		.custom = { &x1000_otg_phy_ops },
26962306a36Sopenharmony_ci	},
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* Muxes & dividers */
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	[X1000_CLK_SCLKA] = {
27462306a36Sopenharmony_ci		"sclk_a", CGU_CLK_MUX,
27562306a36Sopenharmony_ci		.parents = { -1, X1000_CLK_EXCLK, X1000_CLK_APLL, -1 },
27662306a36Sopenharmony_ci		.mux = { CGU_REG_CPCCR, 30, 2 },
27762306a36Sopenharmony_ci	},
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	[X1000_CLK_CPUMUX] = {
28062306a36Sopenharmony_ci		"cpu_mux", CGU_CLK_MUX,
28162306a36Sopenharmony_ci		.parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },
28262306a36Sopenharmony_ci		.mux = { CGU_REG_CPCCR, 28, 2 },
28362306a36Sopenharmony_ci	},
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	[X1000_CLK_CPU] = {
28662306a36Sopenharmony_ci		"cpu", CGU_CLK_DIV | CGU_CLK_GATE,
28762306a36Sopenharmony_ci		/*
28862306a36Sopenharmony_ci		 * Disabling the CPU clock or any parent clocks will hang the
28962306a36Sopenharmony_ci		 * system; mark it critical.
29062306a36Sopenharmony_ci		 */
29162306a36Sopenharmony_ci		.flags = CLK_IS_CRITICAL,
29262306a36Sopenharmony_ci		.parents = { X1000_CLK_CPUMUX },
29362306a36Sopenharmony_ci		.div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
29462306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 30 },
29562306a36Sopenharmony_ci	},
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	[X1000_CLK_L2CACHE] = {
29862306a36Sopenharmony_ci		"l2cache", CGU_CLK_DIV,
29962306a36Sopenharmony_ci		/*
30062306a36Sopenharmony_ci		 * The L2 cache clock is critical if caches are enabled and
30162306a36Sopenharmony_ci		 * disabling it or any parent clocks will hang the system.
30262306a36Sopenharmony_ci		 */
30362306a36Sopenharmony_ci		.flags = CLK_IS_CRITICAL,
30462306a36Sopenharmony_ci		.parents = { X1000_CLK_CPUMUX },
30562306a36Sopenharmony_ci		.div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
30662306a36Sopenharmony_ci	},
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	[X1000_CLK_AHB0] = {
30962306a36Sopenharmony_ci		"ahb0", CGU_CLK_MUX | CGU_CLK_DIV,
31062306a36Sopenharmony_ci		.parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },
31162306a36Sopenharmony_ci		.mux = { CGU_REG_CPCCR, 26, 2 },
31262306a36Sopenharmony_ci		.div = { CGU_REG_CPCCR, 8, 1, 4, 21, -1, -1 },
31362306a36Sopenharmony_ci	},
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	[X1000_CLK_AHB2PMUX] = {
31662306a36Sopenharmony_ci		"ahb2_apb_mux", CGU_CLK_MUX,
31762306a36Sopenharmony_ci		.parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },
31862306a36Sopenharmony_ci		.mux = { CGU_REG_CPCCR, 24, 2 },
31962306a36Sopenharmony_ci	},
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	[X1000_CLK_AHB2] = {
32262306a36Sopenharmony_ci		"ahb2", CGU_CLK_DIV,
32362306a36Sopenharmony_ci		.parents = { X1000_CLK_AHB2PMUX },
32462306a36Sopenharmony_ci		.div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 },
32562306a36Sopenharmony_ci	},
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	[X1000_CLK_PCLK] = {
32862306a36Sopenharmony_ci		"pclk", CGU_CLK_DIV | CGU_CLK_GATE,
32962306a36Sopenharmony_ci		.parents = { X1000_CLK_AHB2PMUX },
33062306a36Sopenharmony_ci		.div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 },
33162306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 28 },
33262306a36Sopenharmony_ci	},
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	[X1000_CLK_DDR] = {
33562306a36Sopenharmony_ci		"ddr", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
33662306a36Sopenharmony_ci		/*
33762306a36Sopenharmony_ci		 * Disabling DDR clock or its parents will render DRAM
33862306a36Sopenharmony_ci		 * inaccessible; mark it critical.
33962306a36Sopenharmony_ci		 */
34062306a36Sopenharmony_ci		.flags = CLK_IS_CRITICAL,
34162306a36Sopenharmony_ci		.parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },
34262306a36Sopenharmony_ci		.mux = { CGU_REG_DDRCDR, 30, 2 },
34362306a36Sopenharmony_ci		.div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 },
34462306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 31 },
34562306a36Sopenharmony_ci	},
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	[X1000_CLK_MAC] = {
34862306a36Sopenharmony_ci		"mac", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
34962306a36Sopenharmony_ci		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },
35062306a36Sopenharmony_ci		.mux = { CGU_REG_MACCDR, 31, 1 },
35162306a36Sopenharmony_ci		.div = { CGU_REG_MACCDR, 0, 1, 8, 29, 28, 27 },
35262306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 25 },
35362306a36Sopenharmony_ci	},
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	[X1000_CLK_I2SPLLMUX] = {
35662306a36Sopenharmony_ci		"i2s_pll_mux", CGU_CLK_MUX,
35762306a36Sopenharmony_ci		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },
35862306a36Sopenharmony_ci		.mux = { CGU_REG_I2SCDR, 31, 1 },
35962306a36Sopenharmony_ci	},
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	[X1000_CLK_I2SPLL] = {
36262306a36Sopenharmony_ci		"i2s_pll", CGU_CLK_PLL,
36362306a36Sopenharmony_ci		.parents = { X1000_CLK_I2SPLLMUX },
36462306a36Sopenharmony_ci		.pll = {
36562306a36Sopenharmony_ci			.reg = CGU_REG_I2SCDR,
36662306a36Sopenharmony_ci			.rate_multiplier = 1,
36762306a36Sopenharmony_ci			.m_shift = 13,
36862306a36Sopenharmony_ci			.m_bits = 9,
36962306a36Sopenharmony_ci			.n_shift = 0,
37062306a36Sopenharmony_ci			.n_bits = 13,
37162306a36Sopenharmony_ci			.calc_m_n_od = x1000_i2spll_calc_m_n_od,
37262306a36Sopenharmony_ci			.set_rate_hook = x1000_i2spll_set_rate_hook,
37362306a36Sopenharmony_ci		},
37462306a36Sopenharmony_ci	},
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	[X1000_CLK_I2S] = {
37762306a36Sopenharmony_ci		"i2s", CGU_CLK_MUX,
37862306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK, -1, -1, X1000_CLK_I2SPLL },
37962306a36Sopenharmony_ci		/*
38062306a36Sopenharmony_ci		 * NOTE: the mux is at bit 30; bit 29 enables the M/N divider.
38162306a36Sopenharmony_ci		 * Therefore, the divider is disabled when EXCLK is selected.
38262306a36Sopenharmony_ci		 */
38362306a36Sopenharmony_ci		.mux = { CGU_REG_I2SCDR, 29, 2 },
38462306a36Sopenharmony_ci	},
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	[X1000_CLK_LCD] = {
38762306a36Sopenharmony_ci		"lcd", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
38862306a36Sopenharmony_ci		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },
38962306a36Sopenharmony_ci		.mux = { CGU_REG_LPCDR, 31, 1 },
39062306a36Sopenharmony_ci		.div = { CGU_REG_LPCDR, 0, 1, 8, 28, 27, 26 },
39162306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 23 },
39262306a36Sopenharmony_ci	},
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	[X1000_CLK_MSCMUX] = {
39562306a36Sopenharmony_ci		"msc_mux", CGU_CLK_MUX,
39662306a36Sopenharmony_ci		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },
39762306a36Sopenharmony_ci		.mux = { CGU_REG_MSC0CDR, 31, 1 },
39862306a36Sopenharmony_ci	},
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	[X1000_CLK_MSC0] = {
40162306a36Sopenharmony_ci		"msc0", CGU_CLK_DIV | CGU_CLK_GATE,
40262306a36Sopenharmony_ci		.parents = { X1000_CLK_MSCMUX },
40362306a36Sopenharmony_ci		.div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 },
40462306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 4 },
40562306a36Sopenharmony_ci	},
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	[X1000_CLK_MSC1] = {
40862306a36Sopenharmony_ci		"msc1", CGU_CLK_DIV | CGU_CLK_GATE,
40962306a36Sopenharmony_ci		.parents = { X1000_CLK_MSCMUX, -1, -1, -1 },
41062306a36Sopenharmony_ci		.div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 },
41162306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 5 },
41262306a36Sopenharmony_ci	},
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	[X1000_CLK_OTG] = {
41562306a36Sopenharmony_ci		"otg", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
41662306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK, -1, X1000_CLK_APLL, X1000_CLK_MPLL },
41762306a36Sopenharmony_ci		.mux = { CGU_REG_USBCDR, 30, 2 },
41862306a36Sopenharmony_ci		.div = { CGU_REG_USBCDR, 0, 1, 8, 29, 28, 27 },
41962306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 3 },
42062306a36Sopenharmony_ci	},
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	[X1000_CLK_SSIPLL] = {
42362306a36Sopenharmony_ci		"ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,
42462306a36Sopenharmony_ci		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },
42562306a36Sopenharmony_ci		.mux = { CGU_REG_SSICDR, 31, 1 },
42662306a36Sopenharmony_ci		.div = { CGU_REG_SSICDR, 0, 1, 8, 29, 28, 27 },
42762306a36Sopenharmony_ci	},
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	[X1000_CLK_SSIPLL_DIV2] = {
43062306a36Sopenharmony_ci		"ssi_pll_div2", CGU_CLK_FIXDIV,
43162306a36Sopenharmony_ci		.parents = { X1000_CLK_SSIPLL },
43262306a36Sopenharmony_ci		.fixdiv = { 2 },
43362306a36Sopenharmony_ci	},
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	[X1000_CLK_SSIMUX] = {
43662306a36Sopenharmony_ci		"ssi_mux", CGU_CLK_MUX,
43762306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK, X1000_CLK_SSIPLL_DIV2 },
43862306a36Sopenharmony_ci		.mux = { CGU_REG_SSICDR, 30, 1 },
43962306a36Sopenharmony_ci	},
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	[X1000_CLK_EXCLK_DIV512] = {
44262306a36Sopenharmony_ci		"exclk_div512", CGU_CLK_FIXDIV,
44362306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK },
44462306a36Sopenharmony_ci		.fixdiv = { 512 },
44562306a36Sopenharmony_ci	},
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	[X1000_CLK_RTC] = {
44862306a36Sopenharmony_ci		"rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE,
44962306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK_DIV512, X1000_CLK_RTCLK },
45062306a36Sopenharmony_ci		.mux = { CGU_REG_OPCR, 2, 1},
45162306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 27 },
45262306a36Sopenharmony_ci	},
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* Gate-only clocks */
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	[X1000_CLK_EMC] = {
45762306a36Sopenharmony_ci		"emc", CGU_CLK_GATE,
45862306a36Sopenharmony_ci		.parents = { X1000_CLK_AHB2 },
45962306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 0 },
46062306a36Sopenharmony_ci	},
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	[X1000_CLK_EFUSE] = {
46362306a36Sopenharmony_ci		"efuse", CGU_CLK_GATE,
46462306a36Sopenharmony_ci		.parents = { X1000_CLK_AHB2 },
46562306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 1 },
46662306a36Sopenharmony_ci	},
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	[X1000_CLK_SFC] = {
46962306a36Sopenharmony_ci		"sfc", CGU_CLK_GATE,
47062306a36Sopenharmony_ci		.parents = { X1000_CLK_SSIPLL },
47162306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 2 },
47262306a36Sopenharmony_ci	},
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	[X1000_CLK_I2C0] = {
47562306a36Sopenharmony_ci		"i2c0", CGU_CLK_GATE,
47662306a36Sopenharmony_ci		.parents = { X1000_CLK_PCLK },
47762306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 7 },
47862306a36Sopenharmony_ci	},
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	[X1000_CLK_I2C1] = {
48162306a36Sopenharmony_ci		"i2c1", CGU_CLK_GATE,
48262306a36Sopenharmony_ci		.parents = { X1000_CLK_PCLK },
48362306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 8 },
48462306a36Sopenharmony_ci	},
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	[X1000_CLK_I2C2] = {
48762306a36Sopenharmony_ci		"i2c2", CGU_CLK_GATE,
48862306a36Sopenharmony_ci		.parents = { X1000_CLK_PCLK },
48962306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 9 },
49062306a36Sopenharmony_ci	},
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	[X1000_CLK_AIC] = {
49362306a36Sopenharmony_ci		"aic", CGU_CLK_GATE,
49462306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK },
49562306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 11 },
49662306a36Sopenharmony_ci	},
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	[X1000_CLK_UART0] = {
49962306a36Sopenharmony_ci		"uart0", CGU_CLK_GATE,
50062306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK },
50162306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 14 },
50262306a36Sopenharmony_ci	},
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	[X1000_CLK_UART1] = {
50562306a36Sopenharmony_ci		"uart1", CGU_CLK_GATE,
50662306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK},
50762306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 15 },
50862306a36Sopenharmony_ci	},
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	[X1000_CLK_UART2] = {
51162306a36Sopenharmony_ci		"uart2", CGU_CLK_GATE,
51262306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK },
51362306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 16 },
51462306a36Sopenharmony_ci	},
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	[X1000_CLK_TCU] = {
51762306a36Sopenharmony_ci		"tcu", CGU_CLK_GATE,
51862306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK },
51962306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 18 },
52062306a36Sopenharmony_ci	},
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	[X1000_CLK_SSI] = {
52362306a36Sopenharmony_ci		"ssi", CGU_CLK_GATE,
52462306a36Sopenharmony_ci		.parents = { X1000_CLK_SSIMUX },
52562306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 19 },
52662306a36Sopenharmony_ci	},
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	[X1000_CLK_OST] = {
52962306a36Sopenharmony_ci		"ost", CGU_CLK_GATE,
53062306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK },
53162306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 20 },
53262306a36Sopenharmony_ci	},
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	[X1000_CLK_PDMA] = {
53562306a36Sopenharmony_ci		"pdma", CGU_CLK_GATE,
53662306a36Sopenharmony_ci		.parents = { X1000_CLK_EXCLK },
53762306a36Sopenharmony_ci		.gate = { CGU_REG_CLKGR, 21 },
53862306a36Sopenharmony_ci	},
53962306a36Sopenharmony_ci};
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic void __init x1000_cgu_init(struct device_node *np)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	int retval;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	cgu = ingenic_cgu_new(x1000_cgu_clocks,
54662306a36Sopenharmony_ci			      ARRAY_SIZE(x1000_cgu_clocks), np);
54762306a36Sopenharmony_ci	if (!cgu) {
54862306a36Sopenharmony_ci		pr_err("%s: failed to initialise CGU\n", __func__);
54962306a36Sopenharmony_ci		return;
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	retval = ingenic_cgu_register_clocks(cgu);
55362306a36Sopenharmony_ci	if (retval) {
55462306a36Sopenharmony_ci		pr_err("%s: failed to register CGU Clocks\n", __func__);
55562306a36Sopenharmony_ci		return;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	ingenic_cgu_register_syscore_ops(cgu);
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci/*
56162306a36Sopenharmony_ci * CGU has some children devices, this is useful for probing children devices
56262306a36Sopenharmony_ci * in the case where the device node is compatible with "simple-mfd".
56362306a36Sopenharmony_ci */
56462306a36Sopenharmony_ciCLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-cgu", x1000_cgu_init);
565