[Letux-kernel] [RFC 05/28] clock/ingenic/cgu: introduce clock driver for the JZ4730
H. Nikolaus Schaller
hns at goldelico.com
Sat Jan 23 17:28:31 CET 2021
From: Paul Boddie <paul at boddie.org.uk>
Add clock driver for the JZ4730.
Signed-off: Paul Boddie <paul at boddie.org.uk>
Signed-off: H. Nikolaus Schaller <hns at goldelico.com>
---
drivers/clk/ingenic/Kconfig | 10 +
drivers/clk/ingenic/Makefile | 1 +
drivers/clk/ingenic/jz4730-cgu.c | 268 +++++++++++++++++++++++++
include/dt-bindings/clock/jz4730-cgu.h | 48 +++++
4 files changed, 327 insertions(+)
create mode 100644 drivers/clk/ingenic/jz4730-cgu.c
create mode 100644 include/dt-bindings/clock/jz4730-cgu.h
diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig
index 580b0cf69ed51..66cc2be10c1e4 100644
--- a/drivers/clk/ingenic/Kconfig
+++ b/drivers/clk/ingenic/Kconfig
@@ -25,6 +25,16 @@ config INGENIC_CGU_JZ4725B
If building for a JZ4725B SoC, you want to say Y here.
+config INGENIC_CGU_JZ4730
+ bool "Ingenic JZ4730 CGU driver"
+ default MACH_JZ4730
+ select INGENIC_CGU_COMMON
+ help
+ Support the clocks provided by the CGU hardware on Ingenic JZ4730
+ and compatible SoCs.
+
+ If building for a JZ4730 SoC, you want to say Y here.
+
config INGENIC_CGU_JZ4770
bool "Ingenic JZ4770 CGU driver"
default MACH_JZ4770
diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index aaa4bffe03c67..c665bd0abe71d 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_INGENIC_CGU_COMMON) += cgu.o pm.o
obj-$(CONFIG_INGENIC_CGU_JZ4740) += jz4740-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4725B) += jz4725b-cgu.o
+obj-$(CONFIG_INGENIC_CGU_JZ4730) += jz4730-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4770) += jz4770-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4780) += jz4780-cgu.o
obj-$(CONFIG_INGENIC_CGU_X1000) += x1000-cgu.o
diff --git a/drivers/clk/ingenic/jz4730-cgu.c b/drivers/clk/ingenic/jz4730-cgu.c
new file mode 100644
index 0000000000000..c4d85d1699256
--- /dev/null
+++ b/drivers/clk/ingenic/jz4730-cgu.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Ingenic JZ4730 SoC CGU driver
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton at mips.com>
+ *
+ * Copyright (c) 2017, 2019, 2020, 2021 Paul Boddie <paul at boddie.org.uk>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <dt-bindings/clock/jz4730-cgu.h>
+
+#include "cgu.h"
+#include "pm.h"
+
+/* CGU register offsets */
+#define CGU_REG_CFCR 0x00 /* CPCCR in jz4740 */
+#define CGU_REG_LPCR 0x04 /* LCR in jz4740 */
+#define CGU_REG_PLCR1 0x10 /* CPPCR in jz4740 */
+#define CGU_REG_OCR 0x1c
+#define CGU_REG_MSCR 0x20 /* CLKGR in jz4740 */
+#define CGU_REG_CFCR2 0x60 /* LPCDR in jz4740 */
+
+static struct ingenic_cgu *cgu;
+
+static const s8 pll_od_encoding[4] = {
+ 0x0, 0x1, -1, 0x3,
+};
+
+static const s8 jz4730_cgu_cfcr_div_table[] = {
+ 1, 2, 3, 4, 6, 8, 12, 16, 24, 32
+};
+
+static const struct ingenic_cgu_clk_info jz4730_cgu_clocks[] = {
+ /* External clocks */
+
+ [JZ4730_CLK_EXT] = { "ext", CGU_CLK_EXT },
+ [JZ4730_CLK_RTC] = { "rtc", CGU_CLK_EXT },
+ [JZ4730_CLK_MSC16M] = { "msc16m", CGU_CLK_EXT },
+ [JZ4730_CLK_MSC24M] = { "msc24m", CGU_CLK_EXT },
+ [JZ4730_CLK_USB48M] = { "usb48m", CGU_CLK_EXT },
+
+ [JZ4730_CLK_PLL] = {
+ "pll", CGU_CLK_PLL,
+ .parents = { JZ4730_CLK_EXT, -1, -1, -1 },
+ .pll = {
+ .reg = CGU_REG_PLCR1,
+ .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_PLCR1,
+ .bypass_bit = 9,
+ .enable_bit = 8,
+ },
+ },
+
+ /* Muxes & dividers */
+
+ [JZ4730_CLK_PLL_HALF] = {
+ "pll half", CGU_CLK_FIXDIV,
+ .parents = { JZ4730_CLK_PLL, -1, -1, -1 },
+ .div = { 2 },
+ },
+
+ [JZ4730_CLK_CCLK_PLL] = {
+ "cclkdiv", CGU_CLK_DIV,
+ .parents = { JZ4730_CLK_PLL, -1, -1, -1 },
+ .div = {
+ CGU_REG_CFCR, 0, 1, 4, 20, -1, -1,
+ jz4730_cgu_cfcr_div_table,
+ },
+ },
+
+ [JZ4730_CLK_CCLK] = {
+ "cclk", CGU_CLK_MUX,
+ .parents = { JZ4730_CLK_EXT, JZ4730_CLK_CCLK_PLL, -1, -1 },
+ .mux = { CGU_REG_PLCR1, 8, 1 },
+ },
+
+ [JZ4730_CLK_HCLK_PLL] = {
+ "hclkdiv", CGU_CLK_DIV,
+ .parents = { JZ4730_CLK_PLL, -1, -1, -1 },
+ .div = {
+ CGU_REG_CFCR, 4, 1, 4, 20, -1, -1,
+ jz4730_cgu_cfcr_div_table,
+ },
+ },
+
+ [JZ4730_CLK_HCLK] = {
+ "hclk", CGU_CLK_MUX,
+ .parents = { JZ4730_CLK_EXT, JZ4730_CLK_HCLK_PLL, -1, -1 },
+ .mux = { CGU_REG_PLCR1, 8, 1 },
+ },
+
+ [JZ4730_CLK_PCLK_PLL] = {
+ "pclkdiv", CGU_CLK_DIV,
+ .parents = { JZ4730_CLK_PLL, -1, -1, -1 },
+ .div = {
+ CGU_REG_CFCR, 8, 1, 4, 20, -1, -1,
+ jz4730_cgu_cfcr_div_table,
+ },
+ },
+
+ [JZ4730_CLK_PCLK] = {
+ "pclk", CGU_CLK_MUX,
+ .parents = { JZ4730_CLK_EXT, JZ4730_CLK_PCLK_PLL, -1, -1 },
+ .mux = { CGU_REG_PLCR1, 8, 1 },
+ },
+
+ [JZ4730_CLK_MCLK_PLL] = {
+ "mclkdiv", CGU_CLK_DIV,
+ .parents = { JZ4730_CLK_PLL, -1, -1, -1 },
+ .div = {
+ CGU_REG_CFCR, 16, 1, 4, 20, -1, -1,
+ jz4730_cgu_cfcr_div_table,
+ },
+ },
+
+ [JZ4730_CLK_MCLK] = {
+ "mclk", CGU_CLK_MUX,
+ .parents = { JZ4730_CLK_EXT, JZ4730_CLK_MCLK_PLL, -1, -1 },
+ .mux = { CGU_REG_PLCR1, 8, 1 },
+ },
+
+ [JZ4730_CLK_LCD_PLL] = {
+ "lcddiv", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4730_CLK_PLL, -1, -1, -1 },
+ .div = {
+ CGU_REG_CFCR, 12, 1, 4, 20, -1, -1,
+ jz4730_cgu_cfcr_div_table,
+ },
+ .gate = { CGU_REG_MSCR, 7 },
+ },
+
+ [JZ4730_CLK_LCD] = {
+ "lcd", CGU_CLK_MUX,
+ .parents = { JZ4730_CLK_EXT, JZ4730_CLK_LCD_PLL, -1, -1 },
+ .mux = { CGU_REG_PLCR1, 8, 1 },
+ },
+
+ [JZ4730_CLK_LCD_PCLK] = {
+ "lcd_pclk", CGU_CLK_DIV,
+ .parents = { JZ4730_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CFCR2, 0, 1, 9, -1, -1, -1 },
+ },
+
+ [JZ4730_CLK_I2S] = {
+ "i2s", CGU_CLK_MUX,
+ .parents = { JZ4730_CLK_PLL, JZ4730_CLK_PLL_HALF, -1, -1 },
+ .mux = { CGU_REG_CFCR, 29, 1 },
+ },
+
+ [JZ4730_CLK_SPI] = {
+ "spi", CGU_CLK_MUX | CGU_CLK_GATE,
+ .parents = { JZ4730_CLK_PLL, JZ4730_CLK_PLL_HALF, -1, -1 },
+ .mux = { CGU_REG_CFCR, 31, 1 },
+ .gate = { CGU_REG_MSCR, 12 },
+ },
+
+ [JZ4730_CLK_MMC] = {
+ "mmc", CGU_CLK_MUX | CGU_CLK_GATE,
+ .parents = { JZ4730_CLK_MSC16M, JZ4730_CLK_MSC24M, -1, -1 },
+ .mux = { CGU_REG_CFCR, 24, 1 },
+ .gate = { CGU_REG_MSCR, 13 },
+ },
+
+ [JZ4730_CLK_UHC_IN] = {
+ "uhcdiv", CGU_CLK_DIV,
+ .parents = { JZ4730_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CFCR, 25, 1, 3, 20, -1, -1 },
+ },
+
+ [JZ4730_CLK_UHC] = {
+ "uhc", CGU_CLK_MUX,
+ .parents = { JZ4730_CLK_UHC_IN, JZ4730_CLK_USB48M, -1, -1 },
+ .mux = { CGU_REG_CFCR, 28, 1 },
+ },
+
+ [JZ4730_CLK_EXT_128] = {
+ "ext_div128", CGU_CLK_FIXDIV,
+ .parents = { JZ4730_CLK_EXT, -1, -1, -1 },
+ .div = { 128 },
+ },
+
+ [JZ4730_CLK_WDT] = {
+ "wdt", CGU_CLK_MUX,
+ .parents = { JZ4730_CLK_EXT_128, JZ4730_CLK_RTC, -1, -1 },
+ .mux = { CGU_REG_OCR, 8, 1 },
+ },
+
+ /* Gate-only clocks */
+
+ [JZ4730_CLK_UART0] = {
+ "uart0", CGU_CLK_GATE,
+ .parents = { JZ4730_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_MSCR, 0 },
+ },
+
+ [JZ4730_CLK_UART1] = {
+ "uart1", CGU_CLK_GATE,
+ .parents = { JZ4730_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_MSCR, 1 },
+ },
+
+ [JZ4730_CLK_UART2] = {
+ "uart2", CGU_CLK_GATE,
+ .parents = { JZ4730_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_MSCR, 2 },
+ },
+
+ [JZ4730_CLK_UART3] = {
+ "uart3", CGU_CLK_GATE,
+ .parents = { JZ4730_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_MSCR, 20 },
+ },
+
+ [JZ4730_CLK_DMA] = {
+ "dma", CGU_CLK_GATE,
+ .parents = { JZ4730_CLK_HCLK, -1, -1, -1 },
+ .gate = { CGU_REG_MSCR, 5 },
+ },
+
+ [JZ4730_CLK_I2C] = {
+ "i2c", CGU_CLK_GATE,
+ .parents = { JZ4730_CLK_PCLK, -1, -1, -1 },
+ .gate = { CGU_REG_MSCR, 8 },
+ },
+
+ [JZ4730_CLK_TCU] = {
+ "tcu", CGU_CLK_GATE,
+ .parents = { JZ4730_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_MSCR, 3 },
+ },
+};
+
+static void __init jz4730_cgu_init(struct device_node *np)
+{
+ int retval;
+
+ cgu = ingenic_cgu_new(jz4730_cgu_clocks,
+ ARRAY_SIZE(jz4730_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(jz4730_cgu, "ingenic,jz4730-cgu", jz4730_cgu_init);
+MODULE_AUTHOR("Paul Boddie <paul at boddie.org.uk>");
diff --git a/include/dt-bindings/clock/jz4730-cgu.h b/include/dt-bindings/clock/jz4730-cgu.h
new file mode 100644
index 0000000000000..4b7abbc12206a
--- /dev/null
+++ b/include/dt-bindings/clock/jz4730-cgu.h
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * This header provides clock numbers for the ingenic,jz4730-cgu DT binding.
+ *
+ * They are roughly ordered as:
+ * - external clocks
+ * - PLLs
+ * - muxes/dividers
+ * - gates in order of their bit in the MSCR* registers
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_JZ4730_CGU_H__
+#define __DT_BINDINGS_CLOCK_JZ4730_CGU_H__
+
+#define JZ4730_CLK_EXT 0
+#define JZ4730_CLK_RTC 1
+#define JZ4730_CLK_MSC16M 2
+#define JZ4730_CLK_MSC24M 3
+#define JZ4730_CLK_USB48M 4
+#define JZ4730_CLK_PLL 5
+#define JZ4730_CLK_PLL_HALF 6
+#define JZ4730_CLK_CCLK_PLL 7
+#define JZ4730_CLK_CCLK 8
+#define JZ4730_CLK_HCLK_PLL 9
+#define JZ4730_CLK_HCLK 10
+#define JZ4730_CLK_PCLK_PLL 11
+#define JZ4730_CLK_PCLK 12
+#define JZ4730_CLK_MCLK_PLL 13
+#define JZ4730_CLK_MCLK 14
+#define JZ4730_CLK_LCD_PLL 15
+#define JZ4730_CLK_LCD 16
+#define JZ4730_CLK_LCD_PCLK 17
+#define JZ4730_CLK_I2S 18
+#define JZ4730_CLK_SPI 19
+#define JZ4730_CLK_DMA 20
+#define JZ4730_CLK_MMC 21
+#define JZ4730_CLK_UHC_IN 22
+#define JZ4730_CLK_UHC 23
+#define JZ4730_CLK_UART0 24
+#define JZ4730_CLK_UART1 25
+#define JZ4730_CLK_UART2 26
+#define JZ4730_CLK_UART3 27
+#define JZ4730_CLK_I2C 28
+#define JZ4730_CLK_TCU 29
+#define JZ4730_CLK_EXT_128 30
+#define JZ4730_CLK_WDT 31
+
+#endif /* __DT_BINDINGS_CLOCK_JZ4730_CGU_H__ */
--
2.26.2
More information about the Letux-kernel
mailing list