diff mbox series

[v2,4/4] clk: Add Ingenic JZ4755 CGU driver

Message ID 20221016150110.3020451-5-lis8215@gmail.com (mailing list archive)
State Superseded
Headers show
Series Add Ingenic JZ4755 CGU driver | expand

Commit Message

Siarhei Volkau Oct. 16, 2022, 3:01 p.m. UTC
Add support for the clocks provided by the CGU in the Ingenic JZ4755
SoC.

Signed-off-by: Siarhei Volkau <lis8215@gmail.com>
---
 drivers/clk/ingenic/Kconfig      |  10 +
 drivers/clk/ingenic/Makefile     |   1 +
 drivers/clk/ingenic/jz4755-cgu.c | 350 +++++++++++++++++++++++++++++++
 3 files changed, 361 insertions(+)
 create mode 100644 drivers/clk/ingenic/jz4755-cgu.c

Comments

Paul Cercueil Oct. 17, 2022, 9:24 a.m. UTC | #1
Hi Siarhei,

Le dim., oct. 16 2022 at 18:01:09 +0300, Siarhei Volkau 
<lis8215@gmail.com> a écrit :
> Add support for the clocks provided by the CGU in the Ingenic JZ4755
> SoC.
> 
> Signed-off-by: Siarhei Volkau <lis8215@gmail.com>
> ---
>  drivers/clk/ingenic/Kconfig      |  10 +
>  drivers/clk/ingenic/Makefile     |   1 +
>  drivers/clk/ingenic/jz4755-cgu.c | 350 
> +++++++++++++++++++++++++++++++
>  3 files changed, 361 insertions(+)
>  create mode 100644 drivers/clk/ingenic/jz4755-cgu.c
> 
> diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig
> index 898f1bc47..f80ac4f29 100644
> --- a/drivers/clk/ingenic/Kconfig
> +++ b/drivers/clk/ingenic/Kconfig
> @@ -15,6 +15,16 @@ config INGENIC_CGU_JZ4740
> 
>  	  If building for a JZ4740 SoC, you want to say Y here.
> 
> +config INGENIC_CGU_JZ4755
> +	bool "Ingenic JZ4755 CGU driver"
> +	default MACH_JZ4755
> +	select INGENIC_CGU_COMMON
> +	help
> +	  Support the clocks provided by the CGU hardware on Ingenic JZ4755
> +	  and compatible SoCs.
> +
> +	  If building for a JZ4755 SoC, you want to say Y here.
> +
>  config INGENIC_CGU_JZ4725B
>  	bool "Ingenic JZ4725B CGU driver"
>  	default MACH_JZ4725B
> diff --git a/drivers/clk/ingenic/Makefile 
> b/drivers/clk/ingenic/Makefile
> index 9edfaf461..81d8e23c2 100644
> --- a/drivers/clk/ingenic/Makefile
> +++ b/drivers/clk/ingenic/Makefile
> @@ -1,6 +1,7 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  obj-$(CONFIG_INGENIC_CGU_COMMON)	+= cgu.o pm.o
>  obj-$(CONFIG_INGENIC_CGU_JZ4740)	+= jz4740-cgu.o
> +obj-$(CONFIG_INGENIC_CGU_JZ4755)	+= jz4755-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
> diff --git a/drivers/clk/ingenic/jz4755-cgu.c 
> b/drivers/clk/ingenic/jz4755-cgu.c
> new file mode 100644
> index 000000000..16728546a
> --- /dev/null
> +++ b/drivers/clk/ingenic/jz4755-cgu.c
> @@ -0,0 +1,350 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Ingenic JZ4755 SoC CGU driver
> + * Heavily based on JZ4725b CGU driver
> + *
> + * Copyright (C) 2022 Siarhei Volkau
> + * Author: Siarhei Volkau <lis8215@gmail.com>
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/of.h>
> +
> +#include <dt-bindings/clock/ingenic,jz4755-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		0x10
> +#define CGU_REG_CLKGR		0x20
> +#define CGU_REG_OPCR		0x24
> +#define CGU_REG_I2SCDR		0x60
> +#define CGU_REG_LPCDR		0x64
> +#define CGU_REG_MSCCDR		0x68
> +#define CGU_REG_SSICDR		0x74
> +#define CGU_REG_CIMCDR		0x7C
> +
> +/* bits within the LCR register */
> +#define LCR_SLEEP		BIT(0)
> +
> +static struct ingenic_cgu *cgu;
> +
> +static const s8 pll_od_encoding[4] = {
> +	0x0, 0x1, -1, 0x3,
> +};
> +
> +static const u8 jz4755_cgu_cpccr_div_table[] = {
> +	1, 2, 3, 4, 6, 8,
> +};
> +
> +static const u8 jz4755_cgu_pll_half_div_table[] = {
> +	2, 1,
> +};
> +
> +static const struct ingenic_cgu_clk_info jz4755_cgu_clocks[] = {
> +
> +	/* External clocks */
> +
> +	[JZ4755_CLK_EXT] = { "ext", CGU_CLK_EXT },
> +	[JZ4755_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
> +
> +	[JZ4755_CLK_PLL] = {
> +		"pll", CGU_CLK_PLL,
> +		.parents = { JZ4755_CLK_EXT, -1, -1, -1 },
> +		.pll = {
> +			.reg = CGU_REG_CPPCR,
> +			.rate_multiplier = 1,
> +			.m_shift = 23,
> +			.m_bits = 9,
> +			.m_offset = 2,
> +			.n_shift = 18,
> +			.n_bits = 5,
> +			.n_offset = 2,
> +			.od_shift = 16,
> +			.od_bits = 2,
> +			.od_max = 4,
> +			.od_encoding = pll_od_encoding,
> +			.stable_bit = 10,
> +			.bypass_reg = CGU_REG_CPPCR,
> +			.bypass_bit = 9,
> +			.enable_bit = 8,
> +		},
> +	},
> +
> +	/* Muxes & dividers */
> +
> +	[JZ4755_CLK_PLL_HALF] = {
> +		"pll half", CGU_CLK_DIV,
> +		.parents = { JZ4755_CLK_PLL, -1, -1, -1 },
> +		.div = {
> +			CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0,
> +			jz4755_cgu_pll_half_div_table,
> +		},
> +	},
> +
> +	[JZ4755_CLK_EXT_HALF] = {
> +		"ext half", CGU_CLK_DIV,
> +		.parents = { JZ4755_CLK_EXT, -1, -1, -1 },
> +		.div = {
> +			CGU_REG_CPCCR, 30, 1, 1, -1, -1, -1, 0,
> +			NULL,
> +		},
> +	},
> +
> +	[JZ4755_CLK_CCLK] = {
> +		"cclk", CGU_CLK_DIV,
> +		.parents = { JZ4755_CLK_PLL, -1, -1, -1 },
> +		.div = {
> +			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
> +			jz4755_cgu_cpccr_div_table,
> +		},
> +	},
> +
> +	[JZ4755_CLK_H0CLK] = {
> +		"hclk", CGU_CLK_DIV,
> +		.parents = { JZ4755_CLK_PLL, -1, -1, -1 },
> +		.div = {
> +			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
> +			jz4755_cgu_cpccr_div_table,
> +		},
> +	},
> +
> +	[JZ4755_CLK_PCLK] = {
> +		"pclk", CGU_CLK_DIV,
> +		.parents = { JZ4755_CLK_PLL, -1, -1, -1 },
> +		.div = {
> +			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
> +			jz4755_cgu_cpccr_div_table,
> +		},
> +	},
> +
> +	[JZ4755_CLK_MCLK] = {
> +		"mclk", CGU_CLK_DIV,
> +		.parents = { JZ4755_CLK_PLL, -1, -1, -1 },
> +		.div = {
> +			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
> +			jz4755_cgu_cpccr_div_table,
> +		},
> +	},
> +
> +	[JZ4755_CLK_H1CLK] = {
> +		"h1clk", CGU_CLK_DIV,
> +		.parents = { JZ4755_CLK_PLL, -1, -1, -1 },
> +		.div = {
> +			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
> +			jz4755_cgu_cpccr_div_table,
> +		},
> +	},
> +
> +	[JZ4755_CLK_UDC] = {
> +		"udc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_EXT_HALF, JZ4755_CLK_PLL_HALF, -1, -1 },
> +		.mux = { CGU_REG_CPCCR, 29, 1 },
> +		.div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 10 },
> +	},
> +
> +	[JZ4755_CLK_LCD] = {
> +		"lcd", CGU_CLK_DIV | CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_PLL_HALF, -1, -1, -1 },
> +		.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 9 },
> +	},
> +
> +	[JZ4755_CLK_MMC] = {
> +		"mmc", CGU_CLK_DIV,
> +		.parents = { JZ4755_CLK_PLL_HALF, -1, -1, -1 },
> +		.div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 },
> +	},
> +
> +	[JZ4755_CLK_I2S] = {
> +		"i2s", CGU_CLK_MUX | CGU_CLK_DIV,
> +		.parents = { JZ4755_CLK_EXT_HALF, JZ4755_CLK_PLL_HALF, -1, -1 },
> +		.mux = { CGU_REG_CPCCR, 31, 1 },
> +		.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
> +	},
> +
> +	[JZ4755_CLK_SPI] = {
> +		"spi", CGU_CLK_DIV | CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_PLL_HALF, -1, -1, -1 },
> +		.div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 4 },
> +	},
> +
> +	[JZ4755_CLK_TVE] = {
> +		"tve", CGU_CLK_MUX | CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_LCD, JZ4755_CLK_EXT, -1, -1 },
> +		.mux = { CGU_REG_LPCDR, 31, 1 },
> +		.gate = { CGU_REG_CLKGR, 18 },
> +	},
> +
> +	[JZ4755_CLK_RTC] = {
> +		"rtc", CGU_CLK_MUX | CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_EXT512, JZ4755_CLK_OSC32K, -1, -1 },
> +		.mux = { CGU_REG_OPCR, 2, 1},
> +		.gate = { CGU_REG_CLKGR, 2 },
> +	},
> +
> +	[JZ4755_CLK_CIM] = {
> +		"cim", CGU_CLK_DIV | CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_PLL_HALF, -1, -1, -1 },
> +		.div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 8 },
> +	},
> +
> +	/* Gate-only clocks */
> +
> +	[JZ4755_CLK_UART0] = {
> +		"uart0", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_EXT_HALF, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 0 },
> +	},
> +
> +	[JZ4755_CLK_UART1] = {
> +		"uart1", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_EXT_HALF, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 14 },
> +	},
> +
> +	[JZ4755_CLK_UART2] = {
> +		"uart2", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_EXT_HALF, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 15 },
> +	},
> +
> +	[JZ4755_CLK_ADC] = {
> +		"adc", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_EXT_HALF, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 7 },
> +	},
> +
> +	[JZ4755_CLK_AIC] = {
> +		"aic", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_I2S, -1, -1, -1 },

Wrong parent here, should be JZ4755_CLK_EXT_HALF.

> +		.gate = { CGU_REG_CLKGR, 5 },
> +	},
> +
> +	[JZ4755_CLK_I2C] = {
> +		"i2c", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_EXT_HALF, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 3 },
> +	},
> +
> +	[JZ4755_CLK_BCH] = {
> +		"bch", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_MCLK/* not sure */, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 11 },
> +	},
> +
> +	[JZ4755_CLK_TCU] = {
> +		"tcu", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_EXT, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 1 },
> +	},
> +
> +	[JZ4755_CLK_DMA] = {
> +		"dma", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_PCLK, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 12 },
> +	},
> +
> +	[JZ4755_CLK_MMC0] = {
> +		"mmc0", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_MMC, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 6 },
> +	},
> +
> +	[JZ4755_CLK_MMC1] = {
> +		"mmc1", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_MMC, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 16 },
> +	},
> +
> +	[JZ4755_CLK_AUX_CPU] = {
> +		"aux_cpu", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_H1CLK, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 24 },
> +	},
> +
> +	[JZ4755_CLK_AHB1] = {
> +		"ahb1", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_H1CLK, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 23 },
> +	},
> +
> +	[JZ4755_CLK_IDCT] = {
> +		"idct", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_H1CLK, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 22 },
> +	},
> +
> +	[JZ4755_CLK_DB] = {
> +		"db", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_H1CLK, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 21 },
> +	},
> +
> +	[JZ4755_CLK_ME] = {
> +		"me", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_H1CLK, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 20 },
> +	},
> +
> +	[JZ4755_CLK_MC] = {
> +		"mc", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_H1CLK, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 19 },
> +	},
> +
> +	[JZ4755_CLK_TSSI] = {
> +		"tssi", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_EXT_HALF/* not sure */, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 17 },
> +	},
> +
> +	[JZ4755_CLK_IPU] = {
> +		"ipu", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_PLL_HALF/* not sure */, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR, 13 },
> +	},
> +
> +	[JZ4755_CLK_EXT512] = {
> +		"ext/512", CGU_CLK_FIXDIV,
> +		.parents = { JZ4755_CLK_EXT },
> +
> +		/* JZ4725b doc calls it EXT512, but it seems to be /256...
> +		 * Not sure if it applied to JZ4755 too, and which actual
> +		 * source is used EXT or EXT_HALF
> +		 */

Well it would be good to know. It's easy to verify though. Parent the 
watchdog clock to EXT/512, configure it for e.g. 5 seconds, if it shuts 
down in 10 seconds, it's a /256 divider.

Cheers,
-Paul

> +		.fixdiv = { 256 },
> +	},
> +
> +	[JZ4755_CLK_UDC_PHY] = {
> +		"udc_phy", CGU_CLK_GATE,
> +		.parents = { JZ4755_CLK_EXT_HALF, -1, -1, -1 },
> +		.gate = { CGU_REG_OPCR, 6, true },
> +	},
> +};
> +
> +static void __init jz4755_cgu_init(struct device_node *np)
> +{
> +	int retval;
> +
> +	cgu = ingenic_cgu_new(jz4755_cgu_clocks,
> +			      ARRAY_SIZE(jz4755_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__);
> +
> +	ingenic_cgu_register_syscore_ops(cgu);
> +}
> +CLK_OF_DECLARE_DRIVER(jz4755_cgu, "ingenic,jz4755-cgu", 
> jz4755_cgu_init);
> --
> 2.36.1
>
Siarhei Volkau Oct. 17, 2022, 5:10 p.m. UTC | #2
пн, 17 окт. 2022 г. в 12:24, Paul Cercueil <paul@crapouillou.net>:

> > +     [JZ4755_CLK_AIC] = {
> > +             "aic", CGU_CLK_GATE,
> > +             .parents = { JZ4755_CLK_I2S, -1, -1, -1 },
>
> Wrong parent here, should be JZ4755_CLK_EXT_HALF.

I don't  agree, see Figure 20-13 in the JZ4755 PM.

> Well it would be good to know...

Indeed, I will try to figure it out.
Paul Cercueil Oct. 17, 2022, 5:24 p.m. UTC | #3
Le lun., oct. 17 2022 at 20:10:56 +0300, Siarhei Volkau 
<lis8215@gmail.com> a écrit :
> пн, 17 окт. 2022 г. в 12:24, Paul Cercueil 
> <paul@crapouillou.net>:
> 
>>  > +     [JZ4755_CLK_AIC] = {
>>  > +             "aic", CGU_CLK_GATE,
>>  > +             .parents = { JZ4755_CLK_I2S, -1, -1, -1 },
>> 
>>  Wrong parent here, should be JZ4755_CLK_EXT_HALF.
> 
> I don't  agree, see Figure 20-13 in the JZ4755 PM.

20-13 describes the I2S clock, no?

AIC clock's parent is EXT/2 according to the diagram in 8.2.2.

>>  Well it would be good to know...
> 
> Indeed, I will try to figure it out.

Cheers,
-Paul
Siarhei Volkau Oct. 17, 2022, 6:07 p.m. UTC | #4
пн, 17 окт. 2022 г. в 20:24, Paul Cercueil <paul@crapouillou.net>:
>
>
>
> Le lun., oct. 17 2022 at 20:10:56 +0300, Siarhei Volkau
> <lis8215@gmail.com> a écrit :
> > пн, 17 окт. 2022 г. в 12:24, Paul Cercueil
> > <paul@crapouillou.net>:
> >
> >>  > +     [JZ4755_CLK_AIC] = {
> >>  > +             "aic", CGU_CLK_GATE,
> >>  > +             .parents = { JZ4755_CLK_I2S, -1, -1, -1 },
> >>
> >>  Wrong parent here, should be JZ4755_CLK_EXT_HALF.
> >
> > I don't  agree, see Figure 20-13 in the JZ4755 PM.
>
> 20-13 describes the I2S clock, no?

See 20.4.9 Serial Audio Clocks and Sampling Frequencies.
It stated that: "For internal CODEC ... CODEC needs a 12MHz
clock from CPM called SYS_CLK ...", but SYS_CLK is described
only in the I2S Controller section. I assume it is the same clock.

>
> AIC clock's parent is EXT/2 according to the diagram in 8.2.2.
>

It's a bit cryptic manual, who knows how it's done in the HW.
I observed that codec runs on a desired sample rate only when PLL
equals 432 or 216 MHz, but SYS_CLK is definitely configured to be
12MHz - from EXTCLK. On other PLL frequencies it is lower by
2-4% than expected. That isn't observed on JZ4725B.

> >>  Well it would be good to know...
> >
> > Indeed, I will try to figure it out.
>
> Cheers,
> -Paul
>
>
Paul Cercueil Oct. 18, 2022, 1:30 p.m. UTC | #5
Hi Siarhei,

Le lun., oct. 17 2022 at 21:07:47 +0300, Siarhei Volkau 
<lis8215@gmail.com> a écrit :
> пн, 17 окт. 2022 г. в 20:24, Paul Cercueil 
> <paul@crapouillou.net>:
>> 
>> 
>> 
>>  Le lun., oct. 17 2022 at 20:10:56 +0300, Siarhei Volkau
>>  <lis8215@gmail.com> a écrit :
>>  > пн, 17 окт. 2022 г. в 12:24, Paul Cercueil
>>  > <paul@crapouillou.net>:
>>  >
>>  >>  > +     [JZ4755_CLK_AIC] = {
>>  >>  > +             "aic", CGU_CLK_GATE,
>>  >>  > +             .parents = { JZ4755_CLK_I2S, -1, -1, -1 },
>>  >>
>>  >>  Wrong parent here, should be JZ4755_CLK_EXT_HALF.
>>  >
>>  > I don't  agree, see Figure 20-13 in the JZ4755 PM.
>> 
>>  20-13 describes the I2S clock, no?
> 
> See 20.4.9 Serial Audio Clocks and Sampling Frequencies.
> It stated that: "For internal CODEC ... CODEC needs a 12MHz
> clock from CPM called SYS_CLK ...", but SYS_CLK is described
> only in the I2S Controller section. I assume it is the same clock.

Yes, and your SYS_CLK is the I2S clock, not the AIC clock.

>> 
>>  AIC clock's parent is EXT/2 according to the diagram in 8.2.2.
>> 
> 
> It's a bit cryptic manual, who knows how it's done in the HW.
> I observed that codec runs on a desired sample rate only when PLL
> equals 432 or 216 MHz, but SYS_CLK is definitely configured to be
> 12MHz - from EXTCLK. On other PLL frequencies it is lower by
> 2-4% than expected. That isn't observed on JZ4725B.

The audio codec supplies SYS_CLK to the controller, not the other way 
around. Parent the I2S clock to EXT/2 (which is 12 MHz) and it should 
work fine, independently of the PLL.

The AIC clock does not drive anything, it only "powers" the AIC module. 
It should be parented only to EXT/2, similar to what's done in every 
other CGU driver.

Cheers,
-Paul
diff mbox series

Patch

diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig
index 898f1bc47..f80ac4f29 100644
--- a/drivers/clk/ingenic/Kconfig
+++ b/drivers/clk/ingenic/Kconfig
@@ -15,6 +15,16 @@  config INGENIC_CGU_JZ4740
 
 	  If building for a JZ4740 SoC, you want to say Y here.
 
+config INGENIC_CGU_JZ4755
+	bool "Ingenic JZ4755 CGU driver"
+	default MACH_JZ4755
+	select INGENIC_CGU_COMMON
+	help
+	  Support the clocks provided by the CGU hardware on Ingenic JZ4755
+	  and compatible SoCs.
+
+	  If building for a JZ4755 SoC, you want to say Y here.
+
 config INGENIC_CGU_JZ4725B
 	bool "Ingenic JZ4725B CGU driver"
 	default MACH_JZ4725B
diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index 9edfaf461..81d8e23c2 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -1,6 +1,7 @@ 
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_INGENIC_CGU_COMMON)	+= cgu.o pm.o
 obj-$(CONFIG_INGENIC_CGU_JZ4740)	+= jz4740-cgu.o
+obj-$(CONFIG_INGENIC_CGU_JZ4755)	+= jz4755-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
diff --git a/drivers/clk/ingenic/jz4755-cgu.c b/drivers/clk/ingenic/jz4755-cgu.c
new file mode 100644
index 000000000..16728546a
--- /dev/null
+++ b/drivers/clk/ingenic/jz4755-cgu.c
@@ -0,0 +1,350 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ingenic JZ4755 SoC CGU driver
+ * Heavily based on JZ4725b CGU driver
+ *
+ * Copyright (C) 2022 Siarhei Volkau
+ * Author: Siarhei Volkau <lis8215@gmail.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+
+#include <dt-bindings/clock/ingenic,jz4755-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		0x10
+#define CGU_REG_CLKGR		0x20
+#define CGU_REG_OPCR		0x24
+#define CGU_REG_I2SCDR		0x60
+#define CGU_REG_LPCDR		0x64
+#define CGU_REG_MSCCDR		0x68
+#define CGU_REG_SSICDR		0x74
+#define CGU_REG_CIMCDR		0x7C
+
+/* bits within the LCR register */
+#define LCR_SLEEP		BIT(0)
+
+static struct ingenic_cgu *cgu;
+
+static const s8 pll_od_encoding[4] = {
+	0x0, 0x1, -1, 0x3,
+};
+
+static const u8 jz4755_cgu_cpccr_div_table[] = {
+	1, 2, 3, 4, 6, 8,
+};
+
+static const u8 jz4755_cgu_pll_half_div_table[] = {
+	2, 1,
+};
+
+static const struct ingenic_cgu_clk_info jz4755_cgu_clocks[] = {
+
+	/* External clocks */
+
+	[JZ4755_CLK_EXT] = { "ext", CGU_CLK_EXT },
+	[JZ4755_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
+
+	[JZ4755_CLK_PLL] = {
+		"pll", CGU_CLK_PLL,
+		.parents = { JZ4755_CLK_EXT, -1, -1, -1 },
+		.pll = {
+			.reg = CGU_REG_CPPCR,
+			.rate_multiplier = 1,
+			.m_shift = 23,
+			.m_bits = 9,
+			.m_offset = 2,
+			.n_shift = 18,
+			.n_bits = 5,
+			.n_offset = 2,
+			.od_shift = 16,
+			.od_bits = 2,
+			.od_max = 4,
+			.od_encoding = pll_od_encoding,
+			.stable_bit = 10,
+			.bypass_reg = CGU_REG_CPPCR,
+			.bypass_bit = 9,
+			.enable_bit = 8,
+		},
+	},
+
+	/* Muxes & dividers */
+
+	[JZ4755_CLK_PLL_HALF] = {
+		"pll half", CGU_CLK_DIV,
+		.parents = { JZ4755_CLK_PLL, -1, -1, -1 },
+		.div = {
+			CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0,
+			jz4755_cgu_pll_half_div_table,
+		},
+	},
+
+	[JZ4755_CLK_EXT_HALF] = {
+		"ext half", CGU_CLK_DIV,
+		.parents = { JZ4755_CLK_EXT, -1, -1, -1 },
+		.div = {
+			CGU_REG_CPCCR, 30, 1, 1, -1, -1, -1, 0,
+			NULL,
+		},
+	},
+
+	[JZ4755_CLK_CCLK] = {
+		"cclk", CGU_CLK_DIV,
+		.parents = { JZ4755_CLK_PLL, -1, -1, -1 },
+		.div = {
+			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
+			jz4755_cgu_cpccr_div_table,
+		},
+	},
+
+	[JZ4755_CLK_H0CLK] = {
+		"hclk", CGU_CLK_DIV,
+		.parents = { JZ4755_CLK_PLL, -1, -1, -1 },
+		.div = {
+			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
+			jz4755_cgu_cpccr_div_table,
+		},
+	},
+
+	[JZ4755_CLK_PCLK] = {
+		"pclk", CGU_CLK_DIV,
+		.parents = { JZ4755_CLK_PLL, -1, -1, -1 },
+		.div = {
+			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
+			jz4755_cgu_cpccr_div_table,
+		},
+	},
+
+	[JZ4755_CLK_MCLK] = {
+		"mclk", CGU_CLK_DIV,
+		.parents = { JZ4755_CLK_PLL, -1, -1, -1 },
+		.div = {
+			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
+			jz4755_cgu_cpccr_div_table,
+		},
+	},
+
+	[JZ4755_CLK_H1CLK] = {
+		"h1clk", CGU_CLK_DIV,
+		.parents = { JZ4755_CLK_PLL, -1, -1, -1 },
+		.div = {
+			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
+			jz4755_cgu_cpccr_div_table,
+		},
+	},
+
+	[JZ4755_CLK_UDC] = {
+		"udc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_EXT_HALF, JZ4755_CLK_PLL_HALF, -1, -1 },
+		.mux = { CGU_REG_CPCCR, 29, 1 },
+		.div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 10 },
+	},
+
+	[JZ4755_CLK_LCD] = {
+		"lcd", CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_PLL_HALF, -1, -1, -1 },
+		.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 9 },
+	},
+
+	[JZ4755_CLK_MMC] = {
+		"mmc", CGU_CLK_DIV,
+		.parents = { JZ4755_CLK_PLL_HALF, -1, -1, -1 },
+		.div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 },
+	},
+
+	[JZ4755_CLK_I2S] = {
+		"i2s", CGU_CLK_MUX | CGU_CLK_DIV,
+		.parents = { JZ4755_CLK_EXT_HALF, JZ4755_CLK_PLL_HALF, -1, -1 },
+		.mux = { CGU_REG_CPCCR, 31, 1 },
+		.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
+	},
+
+	[JZ4755_CLK_SPI] = {
+		"spi", CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_PLL_HALF, -1, -1, -1 },
+		.div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 4 },
+	},
+
+	[JZ4755_CLK_TVE] = {
+		"tve", CGU_CLK_MUX | CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_LCD, JZ4755_CLK_EXT, -1, -1 },
+		.mux = { CGU_REG_LPCDR, 31, 1 },
+		.gate = { CGU_REG_CLKGR, 18 },
+	},
+
+	[JZ4755_CLK_RTC] = {
+		"rtc", CGU_CLK_MUX | CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_EXT512, JZ4755_CLK_OSC32K, -1, -1 },
+		.mux = { CGU_REG_OPCR, 2, 1},
+		.gate = { CGU_REG_CLKGR, 2 },
+	},
+
+	[JZ4755_CLK_CIM] = {
+		"cim", CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_PLL_HALF, -1, -1, -1 },
+		.div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 8 },
+	},
+
+	/* Gate-only clocks */
+
+	[JZ4755_CLK_UART0] = {
+		"uart0", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_EXT_HALF, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 0 },
+	},
+
+	[JZ4755_CLK_UART1] = {
+		"uart1", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_EXT_HALF, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 14 },
+	},
+
+	[JZ4755_CLK_UART2] = {
+		"uart2", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_EXT_HALF, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 15 },
+	},
+
+	[JZ4755_CLK_ADC] = {
+		"adc", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_EXT_HALF, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 7 },
+	},
+
+	[JZ4755_CLK_AIC] = {
+		"aic", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_I2S, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 5 },
+	},
+
+	[JZ4755_CLK_I2C] = {
+		"i2c", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_EXT_HALF, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 3 },
+	},
+
+	[JZ4755_CLK_BCH] = {
+		"bch", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_MCLK/* not sure */, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 11 },
+	},
+
+	[JZ4755_CLK_TCU] = {
+		"tcu", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_EXT, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 1 },
+	},
+
+	[JZ4755_CLK_DMA] = {
+		"dma", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_PCLK, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 12 },
+	},
+
+	[JZ4755_CLK_MMC0] = {
+		"mmc0", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_MMC, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 6 },
+	},
+
+	[JZ4755_CLK_MMC1] = {
+		"mmc1", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_MMC, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 16 },
+	},
+
+	[JZ4755_CLK_AUX_CPU] = {
+		"aux_cpu", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_H1CLK, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 24 },
+	},
+
+	[JZ4755_CLK_AHB1] = {
+		"ahb1", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_H1CLK, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 23 },
+	},
+
+	[JZ4755_CLK_IDCT] = {
+		"idct", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_H1CLK, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 22 },
+	},
+
+	[JZ4755_CLK_DB] = {
+		"db", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_H1CLK, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 21 },
+	},
+
+	[JZ4755_CLK_ME] = {
+		"me", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_H1CLK, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 20 },
+	},
+
+	[JZ4755_CLK_MC] = {
+		"mc", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_H1CLK, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 19 },
+	},
+
+	[JZ4755_CLK_TSSI] = {
+		"tssi", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_EXT_HALF/* not sure */, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 17 },
+	},
+
+	[JZ4755_CLK_IPU] = {
+		"ipu", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_PLL_HALF/* not sure */, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR, 13 },
+	},
+
+	[JZ4755_CLK_EXT512] = {
+		"ext/512", CGU_CLK_FIXDIV,
+		.parents = { JZ4755_CLK_EXT },
+
+		/* JZ4725b doc calls it EXT512, but it seems to be /256...
+		 * Not sure if it applied to JZ4755 too, and which actual
+		 * source is used EXT or EXT_HALF
+		 */
+		.fixdiv = { 256 },
+	},
+
+	[JZ4755_CLK_UDC_PHY] = {
+		"udc_phy", CGU_CLK_GATE,
+		.parents = { JZ4755_CLK_EXT_HALF, -1, -1, -1 },
+		.gate = { CGU_REG_OPCR, 6, true },
+	},
+};
+
+static void __init jz4755_cgu_init(struct device_node *np)
+{
+	int retval;
+
+	cgu = ingenic_cgu_new(jz4755_cgu_clocks,
+			      ARRAY_SIZE(jz4755_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__);
+
+	ingenic_cgu_register_syscore_ops(cgu);
+}
+CLK_OF_DECLARE_DRIVER(jz4755_cgu, "ingenic,jz4755-cgu", jz4755_cgu_init);