All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yoshinori Sato <ysato@users.sourceforge.jp>
To: linux-sh@vger.kernel.org
Cc: "Yoshinori Sato" <ysato@users.sourceforge.jp>,
	"Damien Le Moal" <dlemoal@kernel.org>,
	"Rob Herring" <robh+dt@kernel.org>,
	"Krzysztof Kozlowski" <krzysztof.kozlowski+dt@linaro.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Geert Uytterhoeven" <geert+renesas@glider.be>,
	"Michael Turquette" <mturquette@baylibre.com>,
	"Stephen Boyd" <sboyd@kernel.org>,
	"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
	"Maxime Ripard" <mripard@kernel.org>,
	"Thomas Zimmermann" <tzimmermann@suse.de>,
	"David Airlie" <airlied@gmail.com>,
	"Daniel Vetter" <daniel@ffwll.ch>,
	"Thomas Gleixner" <tglx@linutronix.de>,
	"Lorenzo Pieralisi" <lpieralisi@kernel.org>,
	"Krzysztof Wilczyński" <kw@linux.com>,
	"Bjorn Helgaas" <bhelgaas@google.com>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Jiri Slaby" <jirislaby@kernel.org>,
	"Magnus Damm" <magnus.damm@gmail.com>,
	"Daniel Lezcano" <daniel.lezcano@linaro.org>,
	"Rich Felker" <dalias@libc.org>,
	"John Paul Adrian Glaubitz" <glaubitz@physik.fu-berlin.de>,
	"Lee Jones" <lee@kernel.org>, "Helge Deller" <deller@gmx.de>,
	"Heiko Stuebner" <heiko@sntech.de>,
	"Jernej Skrabec" <jernej.skrabec@gmail.com>,
	"Chris Morgan" <macromorgan@hotmail.com>,
	"Yang Xiwen" <forbidden405@foxmail.com>,
	"Sebastian Reichel" <sre@kernel.org>,
	"Linus Walleij" <linus.walleij@linaro.org>,
	"Randy Dunlap" <rdunlap@infradead.org>,
	"Arnd Bergmann" <arnd@arndb.de>,
	"Vlastimil Babka" <vbabka@suse.cz>,
	"Hyeonggon Yoo" <42.hyeyoo@gmail.com>,
	"David Rientjes" <rientjes@google.com>,
	"Baoquan He" <bhe@redhat.com>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Guenter Roeck" <linux@roeck-us.net>,
	"Stephen Rothwell" <sfr@canb.auug.org.au>,
	"Azeem Shaikh" <azeemshaikh38@gmail.com>,
	"Javier Martinez Canillas" <javierm@redhat.com>,
	"Max Filippov" <jcmvbkbc@gmail.com>,
	"Palmer Dabbelt" <palmer@rivosinc.com>,
	"Bin Meng" <bmeng@tinylab.org>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"Jacky Huang" <ychuang3@nuvoton.com>,
	"Lukas Bulwahn" <lukas.bulwahn@gmail.com>,
	"Biju Das" <biju.das.jz@bp.renesas.com>,
	"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>,
	"Sam Ravnborg" <sam@ravnborg.org>,
	"Sergey Shtylyov" <s.shtylyov@omp.ru>,
	"Michael Karcher" <kernel@mkarcher.dialup.fu-berlin.de>,
	"Laurent Pinchart" <laurent.pinchart+renesas@ideasonboard.com>,
	linux-ide@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
	linux-clk@vger.kernel.org, dri-devel@lists.freedesktop.org,
	linux-pci@vger.kernel.org, linux-serial@vger.kernel.org,
	linux-fbdev@vger.kernel.org
Subject: [DO NOT MERGE v6 15/37] clk: renesas: Add SH7750/7751 CPG Driver
Date: Tue,  9 Jan 2024 17:23:12 +0900	[thread overview]
Message-ID: <28b339d21fa7b74c75f181d3dc710f667da5f228.1704788539.git.ysato@users.sourceforge.jp> (raw)
In-Reply-To: <cover.1704788539.git.ysato@users.sourceforge.jp>

Renesas SH7750 and SH7751 series CPG driver.
This driver supported frequency control and clock gating.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 drivers/clk/renesas/Kconfig      |  16 +-
 drivers/clk/renesas/Makefile     |   1 +
 drivers/clk/renesas/clk-sh7750.c | 498 +++++++++++++++++++++++++++++++
 3 files changed, 513 insertions(+), 2 deletions(-)
 create mode 100644 drivers/clk/renesas/clk-sh7750.c

diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index 69396e197959..b1350cda7ade 100644
--- a/drivers/clk/renesas/Kconfig
+++ b/drivers/clk/renesas/Kconfig
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 
 config CLK_RENESAS
-	bool "Renesas SoC clock support" if COMPILE_TEST && !ARCH_RENESAS
-	default y if ARCH_RENESAS
+	bool "Renesas SoC clock support" if COMPILE_TEST && !ARCH_RENESAS && !SUPERH
+	default y if ARCH_RENESAS || SUPERH
 	select CLK_EMEV2 if ARCH_EMEV2
 	select CLK_RZA1 if ARCH_R7S72100
 	select CLK_R7S9210 if ARCH_R7S9210
@@ -40,6 +40,9 @@ config CLK_RENESAS
 	select CLK_R9A08G045 if ARCH_R9A08G045
 	select CLK_R9A09G011 if ARCH_R9A09G011
 	select CLK_SH73A0 if ARCH_SH73A0
+	select CLK_SH7750 if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7750S || \
+	                     CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751 || \
+			     CPU_SUBTYPE_SH7751R
 
 if CLK_RENESAS
 
@@ -193,6 +196,10 @@ config CLK_SH73A0
 	select CLK_RENESAS_CPG_MSTP
 	select CLK_RENESAS_DIV6
 
+config CLK_SH7750
+	bool "SH7750/7751 family clock support" if COMPILE_TEST
+	help
+	  This is a driver for SH7750 / SH7751 CPG.
 
 # Family
 config CLK_RCAR_CPG_LIB
@@ -223,6 +230,11 @@ config CLK_RZG2L
 	bool "Renesas RZ/{G2L,G2UL,G3S,V2L} family clock support" if COMPILE_TEST
 	select RESET_CONTROLLER
 
+config CLK_SH7750
+	bool "Renesas SH7750/7751 family clock support" if COMPILE_TEST
+	help
+	  This is a driver for SH7750 / SH7751 CPG.
+
 # Generic
 config CLK_RENESAS_CPG_MSSR
 	bool "CPG/MSSR clock support" if COMPILE_TEST
diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile
index 879a07d445f9..233e029fcd54 100644
--- a/drivers/clk/renesas/Makefile
+++ b/drivers/clk/renesas/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_CLK_R9A07G054)		+= r9a07g044-cpg.o
 obj-$(CONFIG_CLK_R9A08G045)		+= r9a08g045-cpg.o
 obj-$(CONFIG_CLK_R9A09G011)		+= r9a09g011-cpg.o
 obj-$(CONFIG_CLK_SH73A0)		+= clk-sh73a0.o
+obj-$(CONFIG_CLK_SH7750)		+= clk-sh7750.o
 
 # Family
 obj-$(CONFIG_CLK_RCAR_CPG_LIB)		+= rcar-cpg-lib.o
diff --git a/drivers/clk/renesas/clk-sh7750.c b/drivers/clk/renesas/clk-sh7750.c
new file mode 100644
index 000000000000..bd971e9a8869
--- /dev/null
+++ b/drivers/clk/renesas/clk-sh7750.c
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas SH7750/51 CPG driver
+ *
+ * Copyright 2023 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+/* PCLK divide rate selector */
+static const struct clk_div_table pdiv_table[] = {
+	{ .val = 0, .div = 2, },
+	{ .val = 1, .div = 3, },
+	{ .val = 2, .div = 4, },
+	{ .val = 3, .div = 6, },
+	{ .val = 4, .div = 8, },
+	{ }
+};
+
+/* ICLK and BCLK divide rate selector */
+static const struct clk_div_table div_table[] = {
+	{ .val = 0, .div = 1, },
+	{ .val = 1, .div = 2, },
+	{ .val = 2, .div = 3, },
+	{ .val = 3, .div = 4, },
+	{ .val = 4, .div = 6, },
+	{ .val = 5, .div = 8, },
+	{ }
+};
+
+struct cpg_priv {
+	struct clk_hw hw;
+	spinlock_t clklock;
+	void __iomem *frqcr;
+	void __iomem *clkstp00;
+	u32 mode;
+	u32 feat;
+};
+
+/* CPG feature flag */
+#define CPG_DIV1	BIT(0)	/* 7750, 7750S, 7751 */
+#define MSTP_CR2	BIT(1)	/* 7750S, 7750R, 7751, 7751R */
+#define MSTP_CLKSTP	BIT(2)	/* 7750R, 7751, 7751R */
+#define MSTP_CSTP2	BIT(3)	/* 7751, 7751R */
+
+enum {
+	CPG_SH7750,
+	CPG_SH7750S,
+	CPG_SH7750R,
+	CPG_SH7751,
+	CPG_SH7751R,
+};
+
+static const u32 cpg_feature[] = {
+	[CPG_SH7750]  = CPG_DIV1,
+	[CPG_SH7750S] = CPG_DIV1 | MSTP_CR2,
+	[CPG_SH7750R] = MSTP_CR2 | MSTP_CLKSTP,
+	[CPG_SH7751]  = CPG_DIV1 | MSTP_CR2 | MSTP_CLKSTP | MSTP_CSTP2,
+	[CPG_SH7751R] = MSTP_CR2 | MSTP_CLKSTP | MSTP_CSTP2,
+};
+
+enum clk_type {CLK_DIV, CLK_STBCR, CLK_STBCR2, CLK_CLKSTP00};
+
+enum {
+	FRQCR = 0,
+	STBCR = 4,
+	WTCNT = 8,
+	WTCSR = 12,
+	STBCR2 = 16,
+	CLKSTP00 = 0,
+	CLKSTPCLR00 = 8,
+};
+
+static struct cpg_priv *cpg_data;
+
+#define to_priv(_hw) container_of(_hw, struct cpg_priv, hw)
+
+#define FRQCR_PLL1EN BIT(10)
+static const unsigned int pll1mult[] = { 12, 12, 6, 12, 6, 12, 1};
+
+static unsigned long pll_recalc_rate(struct clk_hw *hw,
+				      unsigned long parent_rate)
+{
+	struct cpg_priv *cpg = to_priv(hw);
+	unsigned long rate = parent_rate;
+	u16 frqcr;
+
+	frqcr = ioread16(cpg->frqcr);
+	if (frqcr & FRQCR_PLL1EN) {
+		rate *= pll1mult[cpg->mode];
+		if (cpg->mode < 6 && (cpg->feat & CPG_DIV1))
+			rate /= 2;
+	}
+	return rate;
+}
+
+static void get_round_rate(struct cpg_priv *cpg,
+			   unsigned long *out, bool *pllen,
+			   unsigned long rate, unsigned long prate)
+{
+	long pllout, res;
+	bool pll;
+
+	if (cpg->mode < 6 && (cpg->feat & CPG_DIV1))
+		prate /= 2;
+
+	pllout = prate * pll1mult[cpg->mode];
+	if (abs(pllout - rate) > abs(prate - rate)) {
+		res = prate;
+		pll = false;
+	} else {
+		res = pllout;
+		pll = true;
+	}
+	if (out)
+		*out = res;
+	if (pllen)
+		*pllen = pll;
+}
+
+static int pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+	struct cpg_priv *cpg = to_priv(hw);
+
+	get_round_rate(cpg, &req->rate, NULL, req->rate, req->best_parent_rate);
+	return 0;
+}
+
+static int pll_set_rate(struct clk_hw *hw,
+			unsigned long rate, unsigned long prate)
+{
+	struct cpg_priv *cpg = to_priv(hw);
+	bool oldpll, newpll;
+	u16 frqcr;
+
+	frqcr = ioread16(cpg->frqcr);
+	get_round_rate(cpg, NULL, &newpll, rate, prate);
+	oldpll = frqcr & FRQCR_PLL1EN;
+	frqcr &= ~FRQCR_PLL1EN;
+
+	if (newpll) {
+		frqcr |= FRQCR_PLL1EN;
+		if (!oldpll) {
+			/* set PLL wakeup delay time */
+			iowrite16(0xa500, cpg->frqcr + WTCNT);
+			iowrite16(0xa507, cpg->frqcr + WTCNT);
+			iowrite16(0x5a00, cpg->frqcr + WTCSR);
+		}
+	}
+	iowrite16(frqcr, cpg->frqcr);
+
+	/* Test for new PLL state */
+	frqcr = ioread16(cpg->frqcr);
+	oldpll = frqcr & FRQCR_PLL1EN;
+	return !(oldpll == newpll);
+}
+
+static const struct clk_ops pll_ops = {
+	.recalc_rate = pll_recalc_rate,
+	.determine_rate = pll_determine_rate,
+	.set_rate = pll_set_rate,
+};
+
+#define PLLOUT "pllout"
+
+static int register_pll(struct device_node *node, struct cpg_priv *cpg)
+{
+	const char *clk_name = node->name;
+	const char *parent_name;
+	struct clk_init_data init = {
+		.name = PLLOUT,
+		.ops = &pll_ops,
+		.flags = 0,
+		.num_parents = 1,
+	};
+	int ret;
+
+	parent_name = of_clk_get_parent_name(node, 0);
+	init.parent_names = &parent_name;
+	cpg->hw.init = &init;
+
+	ret = of_clk_hw_register(node, &cpg->hw);
+	if (ret < 0) {
+		pr_err("%s: failed to register %s pll clock (%d)\n",
+		       __func__, clk_name, ret);
+		return ret;
+	}
+	if (ret < 0)
+		pr_err("%s: failed to add provider %s (%d)\n",
+		       __func__, clk_name, ret);
+	return ret;
+}
+
+static void clkstp00_sw(struct clk_hw *hw, bool on)
+{
+	u32 val;
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	val = BIT(gate->bit_idx);
+	if (on)
+		writel(val, gate->reg + CLKSTPCLR00);
+	else
+		writel(val, gate->reg);
+}
+
+static int clkstp00_enable(struct clk_hw *hw)
+{
+	clkstp00_sw(hw, true);
+	return 0;
+}
+
+static void clkstp00_disable(struct clk_hw *hw)
+{
+	clkstp00_sw(hw, false);
+}
+
+static int clkstp00_is_enabled(struct clk_hw *hw)
+{
+	u8 val;
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	val = readb(gate->reg);
+	val &= 1 << gate->bit_idx;
+	return val == 0;
+}
+
+static const struct clk_ops gate_clkstp00_ops = {
+	.enable = clkstp00_enable,
+	.disable = clkstp00_disable,
+	.is_enabled = clkstp00_is_enabled,
+};
+
+static struct clk_hw *clk_hw_register_clkstp(struct device_node *node,
+					     const char *name,
+					     const char *parent,
+					     void __iomem *reg, int bit,
+					     spinlock_t *lock)
+{
+	struct clk_gate *gate;
+	struct clk_init_data init = {
+		.name = name,
+		.ops = &gate_clkstp00_ops,
+		.flags = 0,
+		.parent_names = &parent,
+		.num_parents = 1,
+	};
+	struct clk_hw *hw;
+	int ret;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (gate == NULL)
+		goto error;
+	gate->reg = reg;
+	gate->bit_idx = bit;
+	gate->flags = 0;
+	gate->lock = lock;
+	gate->hw.init = &init;
+	hw = &gate->hw;
+	ret = of_clk_hw_register(node, hw);
+	if (ret < 0)
+		goto error;
+	return hw;
+error:
+	kfree(gate);
+	return ERR_PTR(ret);
+}
+
+static int register_div(struct device_node *node, struct cpg_priv *cpg)
+{
+	static const char * const divout[] = {
+		"fck", "bck", "ick",
+	};
+	static const char * const stbcrout[] = {
+		"sci_clk", "rtc_clk", "tmu012_clk",	/* STBCR */
+		"scif_clk", "dmac_clk",			/* STBCR */
+		"ubc_clk", "sq_clk",			/* STBCR2 */
+	};
+	static const char * const clkstpout[] = {
+		"intc_clk", "tmu34_clk", "pcic_clk",	/* CLKSTP00 */
+	};
+
+	unsigned int i;
+	int ret;
+	struct clk_hw_onecell_data *data;
+	struct clk_hw *reg_hw;
+	int num_clk = ARRAY_SIZE(divout) + ARRAY_SIZE(stbcrout) + ARRAY_SIZE(clkstpout);
+
+	data = kzalloc(struct_size(data, hws, num_clk + 1), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	num_clk = 0;
+	for (i = 0; i < ARRAY_SIZE(divout); i++) {
+		reg_hw = __clk_hw_register_divider(NULL, node, divout[i],
+						   PLLOUT, NULL, NULL,
+						   0, cpg->frqcr, i * 3, 3,
+						   CLK_DIVIDER_REG_16BIT,
+						   (i == 0) ? pdiv_table : div_table,
+						   &cpg->clklock);
+		if (IS_ERR(reg_hw)) {
+			ret = PTR_ERR(reg_hw);
+			goto error;
+		}
+		data->hws[num_clk++] = reg_hw;
+	}
+	for (i = 0; i < ARRAY_SIZE(stbcrout); i++) {
+		u32 off =  (i < 5) ? STBCR : STBCR2;
+
+		if (i >= 5 && !(cpg->feat & MSTP_CR2))
+			break;
+		reg_hw = __clk_hw_register_gate(NULL, node, stbcrout[i],
+						divout[0], NULL, NULL,
+						0, cpg->frqcr + off, i % 5,
+						CLK_GATE_REG_8BIT | CLK_GATE_SET_TO_DISABLE,
+						&cpg->clklock);
+		if (IS_ERR(reg_hw)) {
+			ret = PTR_ERR(reg_hw);
+			goto error;
+		}
+		data->hws[num_clk++] = reg_hw;
+	}
+	if (cpg->feat & MSTP_CLKSTP) {
+		for (i = 0; i < ARRAY_SIZE(clkstpout); i++) {
+			if (i == 2 && !(cpg->feat & MSTP_CSTP2))
+				continue;
+			reg_hw = clk_hw_register_clkstp(node, clkstpout[i],
+							divout[0], cpg->clkstp00,
+							i, &cpg->clklock);
+			if (IS_ERR(reg_hw)) {
+				ret = PTR_ERR(reg_hw);
+				goto error;
+			}
+			data->hws[num_clk++] = reg_hw;
+		}
+	}
+	data->num = num_clk;
+	ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data);
+	if (ret < 0)
+		goto error;
+	return 0;
+
+error:
+	pr_err("%pOF: failed to register clock (%d)\n",
+		       node, ret);
+	for (num_clk--; num_clk >= 0; num_clk--)
+		kfree(data->hws[num_clk]);
+	kfree(data);
+	return ret;
+}
+
+static struct cpg_priv *sh7750_cpg_setup(struct device_node *node, u32 feat)
+{
+	unsigned int num_parents;
+	u32 mode;
+	struct cpg_priv *cpg;
+	int ret = 0;
+
+	num_parents = of_clk_get_parent_count(node);
+	if (num_parents < 1) {
+		pr_err("%s: no parent found", node->name);
+		return ERR_PTR(-ENODEV);
+	}
+
+	of_property_read_u32_index(node, "renesas,mode", 0, &mode);
+	if (mode >= 7) {
+		pr_err("%s: Invalid clock mode setting (%u)\n",
+		       node->name, mode);
+		return ERR_PTR(-EINVAL);
+	}
+
+	cpg = kzalloc(sizeof(struct cpg_priv), GFP_KERNEL);
+	if (!cpg)
+		return ERR_PTR(-ENOMEM);
+
+	cpg->frqcr = of_iomap(node, 0);
+	if (cpg->frqcr == NULL) {
+		pr_err("%pOF: failed to map divide register", node);
+		ret = -ENODEV;
+		goto cpg_free;
+	}
+
+	if (feat & MSTP_CLKSTP) {
+		cpg->clkstp00 = of_iomap(node, 1);
+		if (cpg->clkstp00 == NULL) {
+			pr_err("%pOF: failed to map clkstp00 register", node);
+			ret = -ENODEV;
+			goto unmap_frqcr;
+		}
+	}
+	cpg->feat = feat;
+	cpg->mode = mode;
+
+	ret = register_pll(node, cpg);
+	if (ret < 0)
+		goto unmap_clkstp00;
+
+	ret = register_div(node, cpg);
+	if (ret < 0)
+		goto unmap_clkstp00;
+
+	return cpg;
+
+unmap_clkstp00:
+	iounmap(cpg->clkstp00);
+unmap_frqcr:
+	iounmap(cpg->frqcr);
+cpg_free:
+	kfree(cpg);
+	return ERR_PTR(ret);
+}
+
+static void __init sh7750_cpg_init(struct device_node *node)
+{
+	cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7750]);
+	if (IS_ERR(cpg_data))
+		cpg_data = NULL;
+}
+
+static void __init sh7750s_cpg_init(struct device_node *node)
+{
+	cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7750S]);
+	if (IS_ERR(cpg_data))
+		cpg_data = NULL;
+}
+
+static void __init sh7750r_cpg_init(struct device_node *node)
+{
+	cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7750R]);
+	if (IS_ERR(cpg_data))
+		cpg_data = NULL;
+}
+
+static void __init sh7751_cpg_init(struct device_node *node)
+{
+	cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7751]);
+	if (IS_ERR(cpg_data))
+		cpg_data = NULL;
+}
+
+static void __init sh7751r_cpg_init(struct device_node *node)
+{
+	cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7751R]);
+	if (IS_ERR(cpg_data))
+		cpg_data = NULL;
+}
+
+CLK_OF_DECLARE_DRIVER(sh7750_cpg, "renesas,sh7750-cpg",
+		      sh7750_cpg_init);
+CLK_OF_DECLARE_DRIVER(sh7750s_cpg, "renesas,sh7750s-cpg",
+		      sh7750s_cpg_init);
+CLK_OF_DECLARE_DRIVER(sh7750r_cpg, "renesas,sh7750r-cpg",
+		      sh7750r_cpg_init);
+CLK_OF_DECLARE_DRIVER(sh7751_cpg, "renesas,sh7751-cpg",
+		      sh7751_cpg_init);
+CLK_OF_DECLARE_DRIVER(sh7751r_cpg, "renesas,sh7751r-cpg",
+		      sh7751r_cpg_init);
+
+static int sh7750_cpg_probe(struct platform_device *pdev)
+{
+	u32 feature;
+
+	if (cpg_data)
+		return 0;
+	feature = *(u32 *)of_device_get_match_data(&pdev->dev);
+	cpg_data = sh7750_cpg_setup(pdev->dev.of_node, feature);
+	if (IS_ERR(cpg_data))
+		return PTR_ERR(cpg_data);
+	return 0;
+}
+
+static const struct of_device_id sh7750_cpg_of_match[] = {
+	{ .compatible = "renesas,sh7750-cpg",
+	  .data = &cpg_feature[CPG_SH7750] },
+	{ .compatible = "renesas,sh7750s-cpg",
+	  .data = &cpg_feature[CPG_SH7750S] },
+	{ .compatible = "renesas,sh7750r-cpg",
+	  .data = &cpg_feature[CPG_SH7750R] },
+	{ .compatible = "renesas,sh7751-cpg",
+	  .data = &cpg_feature[CPG_SH7751] },
+	{ .compatible = "renesas,sh7751r-cpg",
+	  .data = &cpg_feature[CPG_SH7751R] },
+	{ }
+};
+
+static struct platform_driver sh7750_cpg_driver = {
+	.probe  = sh7750_cpg_probe,
+	.driver = {
+		.name = "sh7750-cpg",
+		.of_match_table = sh7750_cpg_of_match,
+	},
+};
+builtin_platform_driver(sh7750_cpg_driver);
-- 
2.39.2


WARNING: multiple messages have this Message-ID (diff)
From: Yoshinori Sato <ysato@users.sourceforge.jp>
To: linux-sh@vger.kernel.org
Cc: "Krzysztof Wilczyński" <kw@linux.com>,
	linux-fbdev@vger.kernel.org, "Rich Felker" <dalias@libc.org>,
	"Geert Uytterhoeven" <geert+renesas@glider.be>,
	"Bin Meng" <bmeng@tinylab.org>,
	"Michael Turquette" <mturquette@baylibre.com>,
	linux-pci@vger.kernel.org, "Jacky Huang" <ychuang3@nuvoton.com>,
	"Palmer Dabbelt" <palmer@rivosinc.com>,
	linux-kernel@vger.kernel.org, "Max Filippov" <jcmvbkbc@gmail.com>,
	"Lee Jones" <lee@kernel.org>,
	"Krzysztof Kozlowski" <krzysztof.kozlowski+dt@linaro.org>,
	"Hyeonggon Yoo" <42.hyeyoo@gmail.com>,
	"Jiri Slaby" <jirislaby@kernel.org>,
	linux-clk@vger.kernel.org,
	"Stephen Rothwell" <sfr@canb.auug.org.au>,
	"Laurent Pinchart" <laurent.pinchart+renesas@ideasonboard.com>,
	"Yoshinori Sato" <ysato@users.sourceforge.jp>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"Helge Deller" <deller@gmx.de>,
	"Daniel Lezcano" <daniel.lezcano@linaro.org>,
	"Magnus Damm" <magnus.damm@gmail.com>,
	"Javier Martinez Canillas" <javierm@redhat.com>,
	"Jernej Skrabec" <jernej.skrabec@gmail.com>,
	linux-serial@vger.kernel.org,
	"David Rientjes" <rientjes@google.com>,
	"Lukas Bulwahn" <lukas.bulwahn@gmail.com>,
	"Lorenzo Pieralisi" <lpieralisi@kernel.org>,
	"Guenter Roeck" <linux@roeck-us.net>,
	devicetree@vger.kernel.org, "Conor Dooley" <conor+dt@kernel.org>,
	"Arnd Bergmann" <arnd@arndb.de>,
	"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>,
	"Maxime Ripard" <mripard@kernel.org>,
	"Sam Ravnborg" <sam@ravnborg.org>,
	"Rob Herring" <robh+dt@kernel.org>,
	dri-devel@lists.freedesktop.org,
	"Chris Morgan" <macromorgan@hotmail.com>,
	"John Paul Adrian Glaubitz" <glaubitz@physik.fu-berlin.de>,
	"Bjorn Helgaas" <bhelgaas@google.com>,
	"Thomas Gleixner" <tglx@linutronix.de>,
	"Vlastimil Babka" <vbabka@suse.cz>,
	"Yang Xiwen" <forbidden405@foxmail.com>,
	"Sergey Shtylyov" <s.shtylyov@omp.ru>,
	"Baoquan He" <bhe@redhat.com>,
	linux-ide@vger.kernel.org, "Stephen Boyd" <sboyd@kernel.org>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Randy Dunlap" <rdunlap@infradead.org>,
	"Biju Das" <biju.das.jz@bp.renesas.com>,
	"Sebastian Reichel" <sre@kernel.org>,
	"Azeem Shaikh" <azeemshaikh38@gmail.com>,
	linux-renesas-soc@vger.kernel.org,
	"Damien Le Moal" <dlemoal@kernel.org>,
	"Thomas Zimmermann" <tzimmermann@suse.de>,
	"Michael Karcher" <kernel@mkarcher.dialup.fu-berlin.de>,
	"Andrew Morton" <akpm@linux-foundation.org>
Subject: [DO NOT MERGE v6 15/37] clk: renesas: Add SH7750/7751 CPG Driver
Date: Tue,  9 Jan 2024 17:23:12 +0900	[thread overview]
Message-ID: <28b339d21fa7b74c75f181d3dc710f667da5f228.1704788539.git.ysato@users.sourceforge.jp> (raw)
In-Reply-To: <cover.1704788539.git.ysato@users.sourceforge.jp>

Renesas SH7750 and SH7751 series CPG driver.
This driver supported frequency control and clock gating.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 drivers/clk/renesas/Kconfig      |  16 +-
 drivers/clk/renesas/Makefile     |   1 +
 drivers/clk/renesas/clk-sh7750.c | 498 +++++++++++++++++++++++++++++++
 3 files changed, 513 insertions(+), 2 deletions(-)
 create mode 100644 drivers/clk/renesas/clk-sh7750.c

diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index 69396e197959..b1350cda7ade 100644
--- a/drivers/clk/renesas/Kconfig
+++ b/drivers/clk/renesas/Kconfig
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 
 config CLK_RENESAS
-	bool "Renesas SoC clock support" if COMPILE_TEST && !ARCH_RENESAS
-	default y if ARCH_RENESAS
+	bool "Renesas SoC clock support" if COMPILE_TEST && !ARCH_RENESAS && !SUPERH
+	default y if ARCH_RENESAS || SUPERH
 	select CLK_EMEV2 if ARCH_EMEV2
 	select CLK_RZA1 if ARCH_R7S72100
 	select CLK_R7S9210 if ARCH_R7S9210
@@ -40,6 +40,9 @@ config CLK_RENESAS
 	select CLK_R9A08G045 if ARCH_R9A08G045
 	select CLK_R9A09G011 if ARCH_R9A09G011
 	select CLK_SH73A0 if ARCH_SH73A0
+	select CLK_SH7750 if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7750S || \
+	                     CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751 || \
+			     CPU_SUBTYPE_SH7751R
 
 if CLK_RENESAS
 
@@ -193,6 +196,10 @@ config CLK_SH73A0
 	select CLK_RENESAS_CPG_MSTP
 	select CLK_RENESAS_DIV6
 
+config CLK_SH7750
+	bool "SH7750/7751 family clock support" if COMPILE_TEST
+	help
+	  This is a driver for SH7750 / SH7751 CPG.
 
 # Family
 config CLK_RCAR_CPG_LIB
@@ -223,6 +230,11 @@ config CLK_RZG2L
 	bool "Renesas RZ/{G2L,G2UL,G3S,V2L} family clock support" if COMPILE_TEST
 	select RESET_CONTROLLER
 
+config CLK_SH7750
+	bool "Renesas SH7750/7751 family clock support" if COMPILE_TEST
+	help
+	  This is a driver for SH7750 / SH7751 CPG.
+
 # Generic
 config CLK_RENESAS_CPG_MSSR
 	bool "CPG/MSSR clock support" if COMPILE_TEST
diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile
index 879a07d445f9..233e029fcd54 100644
--- a/drivers/clk/renesas/Makefile
+++ b/drivers/clk/renesas/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_CLK_R9A07G054)		+= r9a07g044-cpg.o
 obj-$(CONFIG_CLK_R9A08G045)		+= r9a08g045-cpg.o
 obj-$(CONFIG_CLK_R9A09G011)		+= r9a09g011-cpg.o
 obj-$(CONFIG_CLK_SH73A0)		+= clk-sh73a0.o
+obj-$(CONFIG_CLK_SH7750)		+= clk-sh7750.o
 
 # Family
 obj-$(CONFIG_CLK_RCAR_CPG_LIB)		+= rcar-cpg-lib.o
diff --git a/drivers/clk/renesas/clk-sh7750.c b/drivers/clk/renesas/clk-sh7750.c
new file mode 100644
index 000000000000..bd971e9a8869
--- /dev/null
+++ b/drivers/clk/renesas/clk-sh7750.c
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas SH7750/51 CPG driver
+ *
+ * Copyright 2023 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+/* PCLK divide rate selector */
+static const struct clk_div_table pdiv_table[] = {
+	{ .val = 0, .div = 2, },
+	{ .val = 1, .div = 3, },
+	{ .val = 2, .div = 4, },
+	{ .val = 3, .div = 6, },
+	{ .val = 4, .div = 8, },
+	{ }
+};
+
+/* ICLK and BCLK divide rate selector */
+static const struct clk_div_table div_table[] = {
+	{ .val = 0, .div = 1, },
+	{ .val = 1, .div = 2, },
+	{ .val = 2, .div = 3, },
+	{ .val = 3, .div = 4, },
+	{ .val = 4, .div = 6, },
+	{ .val = 5, .div = 8, },
+	{ }
+};
+
+struct cpg_priv {
+	struct clk_hw hw;
+	spinlock_t clklock;
+	void __iomem *frqcr;
+	void __iomem *clkstp00;
+	u32 mode;
+	u32 feat;
+};
+
+/* CPG feature flag */
+#define CPG_DIV1	BIT(0)	/* 7750, 7750S, 7751 */
+#define MSTP_CR2	BIT(1)	/* 7750S, 7750R, 7751, 7751R */
+#define MSTP_CLKSTP	BIT(2)	/* 7750R, 7751, 7751R */
+#define MSTP_CSTP2	BIT(3)	/* 7751, 7751R */
+
+enum {
+	CPG_SH7750,
+	CPG_SH7750S,
+	CPG_SH7750R,
+	CPG_SH7751,
+	CPG_SH7751R,
+};
+
+static const u32 cpg_feature[] = {
+	[CPG_SH7750]  = CPG_DIV1,
+	[CPG_SH7750S] = CPG_DIV1 | MSTP_CR2,
+	[CPG_SH7750R] = MSTP_CR2 | MSTP_CLKSTP,
+	[CPG_SH7751]  = CPG_DIV1 | MSTP_CR2 | MSTP_CLKSTP | MSTP_CSTP2,
+	[CPG_SH7751R] = MSTP_CR2 | MSTP_CLKSTP | MSTP_CSTP2,
+};
+
+enum clk_type {CLK_DIV, CLK_STBCR, CLK_STBCR2, CLK_CLKSTP00};
+
+enum {
+	FRQCR = 0,
+	STBCR = 4,
+	WTCNT = 8,
+	WTCSR = 12,
+	STBCR2 = 16,
+	CLKSTP00 = 0,
+	CLKSTPCLR00 = 8,
+};
+
+static struct cpg_priv *cpg_data;
+
+#define to_priv(_hw) container_of(_hw, struct cpg_priv, hw)
+
+#define FRQCR_PLL1EN BIT(10)
+static const unsigned int pll1mult[] = { 12, 12, 6, 12, 6, 12, 1};
+
+static unsigned long pll_recalc_rate(struct clk_hw *hw,
+				      unsigned long parent_rate)
+{
+	struct cpg_priv *cpg = to_priv(hw);
+	unsigned long rate = parent_rate;
+	u16 frqcr;
+
+	frqcr = ioread16(cpg->frqcr);
+	if (frqcr & FRQCR_PLL1EN) {
+		rate *= pll1mult[cpg->mode];
+		if (cpg->mode < 6 && (cpg->feat & CPG_DIV1))
+			rate /= 2;
+	}
+	return rate;
+}
+
+static void get_round_rate(struct cpg_priv *cpg,
+			   unsigned long *out, bool *pllen,
+			   unsigned long rate, unsigned long prate)
+{
+	long pllout, res;
+	bool pll;
+
+	if (cpg->mode < 6 && (cpg->feat & CPG_DIV1))
+		prate /= 2;
+
+	pllout = prate * pll1mult[cpg->mode];
+	if (abs(pllout - rate) > abs(prate - rate)) {
+		res = prate;
+		pll = false;
+	} else {
+		res = pllout;
+		pll = true;
+	}
+	if (out)
+		*out = res;
+	if (pllen)
+		*pllen = pll;
+}
+
+static int pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+	struct cpg_priv *cpg = to_priv(hw);
+
+	get_round_rate(cpg, &req->rate, NULL, req->rate, req->best_parent_rate);
+	return 0;
+}
+
+static int pll_set_rate(struct clk_hw *hw,
+			unsigned long rate, unsigned long prate)
+{
+	struct cpg_priv *cpg = to_priv(hw);
+	bool oldpll, newpll;
+	u16 frqcr;
+
+	frqcr = ioread16(cpg->frqcr);
+	get_round_rate(cpg, NULL, &newpll, rate, prate);
+	oldpll = frqcr & FRQCR_PLL1EN;
+	frqcr &= ~FRQCR_PLL1EN;
+
+	if (newpll) {
+		frqcr |= FRQCR_PLL1EN;
+		if (!oldpll) {
+			/* set PLL wakeup delay time */
+			iowrite16(0xa500, cpg->frqcr + WTCNT);
+			iowrite16(0xa507, cpg->frqcr + WTCNT);
+			iowrite16(0x5a00, cpg->frqcr + WTCSR);
+		}
+	}
+	iowrite16(frqcr, cpg->frqcr);
+
+	/* Test for new PLL state */
+	frqcr = ioread16(cpg->frqcr);
+	oldpll = frqcr & FRQCR_PLL1EN;
+	return !(oldpll == newpll);
+}
+
+static const struct clk_ops pll_ops = {
+	.recalc_rate = pll_recalc_rate,
+	.determine_rate = pll_determine_rate,
+	.set_rate = pll_set_rate,
+};
+
+#define PLLOUT "pllout"
+
+static int register_pll(struct device_node *node, struct cpg_priv *cpg)
+{
+	const char *clk_name = node->name;
+	const char *parent_name;
+	struct clk_init_data init = {
+		.name = PLLOUT,
+		.ops = &pll_ops,
+		.flags = 0,
+		.num_parents = 1,
+	};
+	int ret;
+
+	parent_name = of_clk_get_parent_name(node, 0);
+	init.parent_names = &parent_name;
+	cpg->hw.init = &init;
+
+	ret = of_clk_hw_register(node, &cpg->hw);
+	if (ret < 0) {
+		pr_err("%s: failed to register %s pll clock (%d)\n",
+		       __func__, clk_name, ret);
+		return ret;
+	}
+	if (ret < 0)
+		pr_err("%s: failed to add provider %s (%d)\n",
+		       __func__, clk_name, ret);
+	return ret;
+}
+
+static void clkstp00_sw(struct clk_hw *hw, bool on)
+{
+	u32 val;
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	val = BIT(gate->bit_idx);
+	if (on)
+		writel(val, gate->reg + CLKSTPCLR00);
+	else
+		writel(val, gate->reg);
+}
+
+static int clkstp00_enable(struct clk_hw *hw)
+{
+	clkstp00_sw(hw, true);
+	return 0;
+}
+
+static void clkstp00_disable(struct clk_hw *hw)
+{
+	clkstp00_sw(hw, false);
+}
+
+static int clkstp00_is_enabled(struct clk_hw *hw)
+{
+	u8 val;
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	val = readb(gate->reg);
+	val &= 1 << gate->bit_idx;
+	return val == 0;
+}
+
+static const struct clk_ops gate_clkstp00_ops = {
+	.enable = clkstp00_enable,
+	.disable = clkstp00_disable,
+	.is_enabled = clkstp00_is_enabled,
+};
+
+static struct clk_hw *clk_hw_register_clkstp(struct device_node *node,
+					     const char *name,
+					     const char *parent,
+					     void __iomem *reg, int bit,
+					     spinlock_t *lock)
+{
+	struct clk_gate *gate;
+	struct clk_init_data init = {
+		.name = name,
+		.ops = &gate_clkstp00_ops,
+		.flags = 0,
+		.parent_names = &parent,
+		.num_parents = 1,
+	};
+	struct clk_hw *hw;
+	int ret;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (gate == NULL)
+		goto error;
+	gate->reg = reg;
+	gate->bit_idx = bit;
+	gate->flags = 0;
+	gate->lock = lock;
+	gate->hw.init = &init;
+	hw = &gate->hw;
+	ret = of_clk_hw_register(node, hw);
+	if (ret < 0)
+		goto error;
+	return hw;
+error:
+	kfree(gate);
+	return ERR_PTR(ret);
+}
+
+static int register_div(struct device_node *node, struct cpg_priv *cpg)
+{
+	static const char * const divout[] = {
+		"fck", "bck", "ick",
+	};
+	static const char * const stbcrout[] = {
+		"sci_clk", "rtc_clk", "tmu012_clk",	/* STBCR */
+		"scif_clk", "dmac_clk",			/* STBCR */
+		"ubc_clk", "sq_clk",			/* STBCR2 */
+	};
+	static const char * const clkstpout[] = {
+		"intc_clk", "tmu34_clk", "pcic_clk",	/* CLKSTP00 */
+	};
+
+	unsigned int i;
+	int ret;
+	struct clk_hw_onecell_data *data;
+	struct clk_hw *reg_hw;
+	int num_clk = ARRAY_SIZE(divout) + ARRAY_SIZE(stbcrout) + ARRAY_SIZE(clkstpout);
+
+	data = kzalloc(struct_size(data, hws, num_clk + 1), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	num_clk = 0;
+	for (i = 0; i < ARRAY_SIZE(divout); i++) {
+		reg_hw = __clk_hw_register_divider(NULL, node, divout[i],
+						   PLLOUT, NULL, NULL,
+						   0, cpg->frqcr, i * 3, 3,
+						   CLK_DIVIDER_REG_16BIT,
+						   (i == 0) ? pdiv_table : div_table,
+						   &cpg->clklock);
+		if (IS_ERR(reg_hw)) {
+			ret = PTR_ERR(reg_hw);
+			goto error;
+		}
+		data->hws[num_clk++] = reg_hw;
+	}
+	for (i = 0; i < ARRAY_SIZE(stbcrout); i++) {
+		u32 off =  (i < 5) ? STBCR : STBCR2;
+
+		if (i >= 5 && !(cpg->feat & MSTP_CR2))
+			break;
+		reg_hw = __clk_hw_register_gate(NULL, node, stbcrout[i],
+						divout[0], NULL, NULL,
+						0, cpg->frqcr + off, i % 5,
+						CLK_GATE_REG_8BIT | CLK_GATE_SET_TO_DISABLE,
+						&cpg->clklock);
+		if (IS_ERR(reg_hw)) {
+			ret = PTR_ERR(reg_hw);
+			goto error;
+		}
+		data->hws[num_clk++] = reg_hw;
+	}
+	if (cpg->feat & MSTP_CLKSTP) {
+		for (i = 0; i < ARRAY_SIZE(clkstpout); i++) {
+			if (i == 2 && !(cpg->feat & MSTP_CSTP2))
+				continue;
+			reg_hw = clk_hw_register_clkstp(node, clkstpout[i],
+							divout[0], cpg->clkstp00,
+							i, &cpg->clklock);
+			if (IS_ERR(reg_hw)) {
+				ret = PTR_ERR(reg_hw);
+				goto error;
+			}
+			data->hws[num_clk++] = reg_hw;
+		}
+	}
+	data->num = num_clk;
+	ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data);
+	if (ret < 0)
+		goto error;
+	return 0;
+
+error:
+	pr_err("%pOF: failed to register clock (%d)\n",
+		       node, ret);
+	for (num_clk--; num_clk >= 0; num_clk--)
+		kfree(data->hws[num_clk]);
+	kfree(data);
+	return ret;
+}
+
+static struct cpg_priv *sh7750_cpg_setup(struct device_node *node, u32 feat)
+{
+	unsigned int num_parents;
+	u32 mode;
+	struct cpg_priv *cpg;
+	int ret = 0;
+
+	num_parents = of_clk_get_parent_count(node);
+	if (num_parents < 1) {
+		pr_err("%s: no parent found", node->name);
+		return ERR_PTR(-ENODEV);
+	}
+
+	of_property_read_u32_index(node, "renesas,mode", 0, &mode);
+	if (mode >= 7) {
+		pr_err("%s: Invalid clock mode setting (%u)\n",
+		       node->name, mode);
+		return ERR_PTR(-EINVAL);
+	}
+
+	cpg = kzalloc(sizeof(struct cpg_priv), GFP_KERNEL);
+	if (!cpg)
+		return ERR_PTR(-ENOMEM);
+
+	cpg->frqcr = of_iomap(node, 0);
+	if (cpg->frqcr == NULL) {
+		pr_err("%pOF: failed to map divide register", node);
+		ret = -ENODEV;
+		goto cpg_free;
+	}
+
+	if (feat & MSTP_CLKSTP) {
+		cpg->clkstp00 = of_iomap(node, 1);
+		if (cpg->clkstp00 == NULL) {
+			pr_err("%pOF: failed to map clkstp00 register", node);
+			ret = -ENODEV;
+			goto unmap_frqcr;
+		}
+	}
+	cpg->feat = feat;
+	cpg->mode = mode;
+
+	ret = register_pll(node, cpg);
+	if (ret < 0)
+		goto unmap_clkstp00;
+
+	ret = register_div(node, cpg);
+	if (ret < 0)
+		goto unmap_clkstp00;
+
+	return cpg;
+
+unmap_clkstp00:
+	iounmap(cpg->clkstp00);
+unmap_frqcr:
+	iounmap(cpg->frqcr);
+cpg_free:
+	kfree(cpg);
+	return ERR_PTR(ret);
+}
+
+static void __init sh7750_cpg_init(struct device_node *node)
+{
+	cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7750]);
+	if (IS_ERR(cpg_data))
+		cpg_data = NULL;
+}
+
+static void __init sh7750s_cpg_init(struct device_node *node)
+{
+	cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7750S]);
+	if (IS_ERR(cpg_data))
+		cpg_data = NULL;
+}
+
+static void __init sh7750r_cpg_init(struct device_node *node)
+{
+	cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7750R]);
+	if (IS_ERR(cpg_data))
+		cpg_data = NULL;
+}
+
+static void __init sh7751_cpg_init(struct device_node *node)
+{
+	cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7751]);
+	if (IS_ERR(cpg_data))
+		cpg_data = NULL;
+}
+
+static void __init sh7751r_cpg_init(struct device_node *node)
+{
+	cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7751R]);
+	if (IS_ERR(cpg_data))
+		cpg_data = NULL;
+}
+
+CLK_OF_DECLARE_DRIVER(sh7750_cpg, "renesas,sh7750-cpg",
+		      sh7750_cpg_init);
+CLK_OF_DECLARE_DRIVER(sh7750s_cpg, "renesas,sh7750s-cpg",
+		      sh7750s_cpg_init);
+CLK_OF_DECLARE_DRIVER(sh7750r_cpg, "renesas,sh7750r-cpg",
+		      sh7750r_cpg_init);
+CLK_OF_DECLARE_DRIVER(sh7751_cpg, "renesas,sh7751-cpg",
+		      sh7751_cpg_init);
+CLK_OF_DECLARE_DRIVER(sh7751r_cpg, "renesas,sh7751r-cpg",
+		      sh7751r_cpg_init);
+
+static int sh7750_cpg_probe(struct platform_device *pdev)
+{
+	u32 feature;
+
+	if (cpg_data)
+		return 0;
+	feature = *(u32 *)of_device_get_match_data(&pdev->dev);
+	cpg_data = sh7750_cpg_setup(pdev->dev.of_node, feature);
+	if (IS_ERR(cpg_data))
+		return PTR_ERR(cpg_data);
+	return 0;
+}
+
+static const struct of_device_id sh7750_cpg_of_match[] = {
+	{ .compatible = "renesas,sh7750-cpg",
+	  .data = &cpg_feature[CPG_SH7750] },
+	{ .compatible = "renesas,sh7750s-cpg",
+	  .data = &cpg_feature[CPG_SH7750S] },
+	{ .compatible = "renesas,sh7750r-cpg",
+	  .data = &cpg_feature[CPG_SH7750R] },
+	{ .compatible = "renesas,sh7751-cpg",
+	  .data = &cpg_feature[CPG_SH7751] },
+	{ .compatible = "renesas,sh7751r-cpg",
+	  .data = &cpg_feature[CPG_SH7751R] },
+	{ }
+};
+
+static struct platform_driver sh7750_cpg_driver = {
+	.probe  = sh7750_cpg_probe,
+	.driver = {
+		.name = "sh7750-cpg",
+		.of_match_table = sh7750_cpg_of_match,
+	},
+};
+builtin_platform_driver(sh7750_cpg_driver);
-- 
2.39.2


  parent reply	other threads:[~2024-01-09  8:24 UTC|newest]

Thread overview: 138+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-09  8:22 [DO NOT MERGE v6 00/37] Device Tree support for SH7751 based board Yoshinori Sato
2024-01-09  8:22 ` Yoshinori Sato
2024-01-09  8:22 ` [DO NOT MERGE v6 01/37] sh: passing FDT address to kernel startup Yoshinori Sato
2024-01-09  8:22   ` Yoshinori Sato
2024-01-15 14:03   ` Geert Uytterhoeven
2024-01-15 14:03     ` Geert Uytterhoeven
2024-01-09  8:22 ` [DO NOT MERGE v6 02/37] sh: Kconfig unified OF supported targets Yoshinori Sato
2024-01-09  8:22   ` Yoshinori Sato
2024-02-26 16:21   ` Geert Uytterhoeven
2024-01-09  8:23 ` [DO NOT MERGE v6 03/37] sh: Enable OF support for build and configuration Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 04/37] dt-bindings: interrupt-controller: Add header for Renesas SH3/4 INTC Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09 18:41   ` Krzysztof Kozlowski
2024-01-09 18:41     ` Krzysztof Kozlowski
2024-01-09  8:23 ` [DO NOT MERGE v6 05/37] sh: GENERIC_IRQ_CHIP support for CONFIG_OF=y Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 06/37] sh: kernel/setup Update DT support Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 07/37] sh: Fix COMMON_CLK support in CONFIG_OF=y Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 08/37] clocksource: sh_tmu: CLOCKSOURCE support Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-02-26 16:54   ` Geert Uytterhoeven
2024-01-09  8:23 ` [DO NOT MERGE v6 09/37] dt-bindings: timer: renesas,tmu: add renesas,tmu-sh7750 Yoshinori Sato
2024-01-09  8:23   ` [DO NOT MERGE v6 09/37] dt-bindings: timer: renesas, tmu: add renesas, tmu-sh7750 Yoshinori Sato
2024-01-15 13:59   ` [DO NOT MERGE v6 09/37] dt-bindings: timer: renesas,tmu: add renesas,tmu-sh7750 Geert Uytterhoeven
2024-01-15 13:59     ` [DO NOT MERGE v6 09/37] dt-bindings: timer: renesas, tmu: add renesas, tmu-sh7750 Geert Uytterhoeven
2024-01-09  8:23 ` [DO NOT MERGE v6 10/37] sh: Common PCI Framework driver support Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 11/37] pci: pci-sh7751: Add SH7751 PCI driver Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 12/37] dt-bindings: pci: pci-sh7751: Add SH7751 PCI Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09 12:42   ` Linus Walleij
2024-01-09 12:42     ` Linus Walleij
2024-01-09 17:31     ` Rob Herring
2024-01-09 17:31       ` Rob Herring
2024-01-09  8:23 ` [DO NOT MERGE v6 13/37] dt-bindings: clock: sh7750-cpg: Add renesas,sh7750-cpg header Yoshinori Sato
2024-01-09  8:23   ` [DO NOT MERGE v6 13/37] dt-bindings: clock: sh7750-cpg: Add renesas, sh7750-cpg header Yoshinori Sato
2024-02-27 16:47   ` [DO NOT MERGE v6 13/37] dt-bindings: clock: sh7750-cpg: Add renesas,sh7750-cpg header Geert Uytterhoeven
2024-01-09  8:23 ` [DO NOT MERGE v6 14/37] clk: Compatible with narrow registers Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-02-27 15:41   ` Geert Uytterhoeven
2024-01-09  8:23 ` Yoshinori Sato [this message]
2024-01-09  8:23   ` [DO NOT MERGE v6 15/37] clk: renesas: Add SH7750/7751 CPG Driver Yoshinori Sato
2024-02-27 16:34   ` Geert Uytterhoeven
2024-01-09  8:23 ` [DO NOT MERGE v6 16/37] irqchip: Add SH7751 INTC driver Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 17/37] dt-bindings: interrupt-controller: renesas,sh7751-intc: Add json-schema Yoshinori Sato
2024-01-09  8:23   ` [DO NOT MERGE v6 17/37] dt-bindings: interrupt-controller: renesas, sh7751-intc: " Yoshinori Sato
2024-01-09 12:30   ` [DO NOT MERGE v6 17/37] dt-bindings: interrupt-controller: renesas,sh7751-intc: " Linus Walleij
2024-01-09 12:30     ` Linus Walleij
2024-01-17  9:46     ` [DO NOT MERGE v6 17/37] dt-bindings: interrupt-controller: renesas, sh7751-intc: " Yoshinori Sato
2024-01-17  9:46       ` [DO NOT MERGE v6 17/37] dt-bindings: interrupt-controller: renesas,sh7751-intc: " Yoshinori Sato
2024-01-17 10:06       ` Geert Uytterhoeven
2024-01-17 10:06         ` Geert Uytterhoeven
2024-01-09  8:23 ` [DO NOT MERGE v6 18/37] irqchip: SH7751 external interrupt encoder with enable gate Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 19/37] dt-bindings: interrupt-controller: renesas,sh7751-irl-ext: Add json-schema Yoshinori Sato
2024-01-09  8:23   ` [DO NOT MERGE v6 19/37] dt-bindings: interrupt-controller: renesas, sh7751-irl-ext: " Yoshinori Sato
2024-01-09 16:29   ` [DO NOT MERGE v6 19/37] dt-bindings: interrupt-controller: renesas,sh7751-irl-ext: " Rob Herring
2024-01-09 16:29     ` Rob Herring
2024-01-09 17:18   ` Rob Herring
2024-01-09 17:18     ` Rob Herring
2024-01-09  8:23 ` [DO NOT MERGE v6 20/37] serial: sh-sci: fix SH4 OF support Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 21/37] dt-bindings: serial: renesas,scif: Add scif-sh7751 Yoshinori Sato
2024-01-09  8:23   ` [DO NOT MERGE v6 21/37] dt-bindings: serial: renesas, scif: " Yoshinori Sato
2024-01-15  9:29   ` [DO NOT MERGE v6 21/37] dt-bindings: serial: renesas,scif: " Geert Uytterhoeven
2024-01-15  9:29     ` [DO NOT MERGE v6 21/37] dt-bindings: serial: renesas, scif: " Geert Uytterhoeven
2024-01-09  8:23 ` [DO NOT MERGE v6 22/37] dt-bindings: display: smi,sm501: SMI SM501 binding json-schema Yoshinori Sato
2024-01-09  8:23   ` [DO NOT MERGE v6 22/37] dt-bindings: display: smi, sm501: " Yoshinori Sato
2024-01-15  9:52   ` [DO NOT MERGE v6 22/37] dt-bindings: display: smi,sm501: " Geert Uytterhoeven
2024-01-15  9:52     ` Geert Uytterhoeven
2024-01-09  8:23 ` [DO NOT MERGE v6 23/37] mfd: sm501: Convert platform_data to OF property Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-11 11:35   ` Lee Jones
2024-01-11 11:35     ` Lee Jones
2024-01-09  8:23 ` [DO NOT MERGE v6 24/37] dt-binding: sh: cpus: Add SH CPUs json-schema Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09 18:00   ` Conor Dooley
2024-01-09 18:00     ` Conor Dooley
2024-01-09  8:23 ` [DO NOT MERGE v6 25/37] dt-bindings: vendor-prefixes: Add iodata Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09 18:03   ` Conor Dooley
2024-01-09 18:03     ` Conor Dooley
2024-01-15 14:02   ` Geert Uytterhoeven
2024-01-15 14:02     ` Geert Uytterhoeven
2024-01-09  8:23 ` [DO NOT MERGE v6 26/37] dt-bindings: vendor-prefixes: Add smi Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09 18:05   ` Conor Dooley
2024-01-09 18:05     ` Conor Dooley
2024-01-10 11:23     ` Geert Uytterhoeven
2024-01-10 11:23       ` Geert Uytterhoeven
2024-01-10 14:28       ` Guenter Roeck
2024-01-10 14:28         ` Guenter Roeck
2024-01-10 16:11       ` Conor Dooley
2024-01-10 16:11         ` Conor Dooley
2024-01-11 14:59         ` Rob Herring
2024-01-11 14:59           ` Rob Herring
2024-01-09 21:40   ` Uwe Kleine-König
2024-01-09 21:40     ` Uwe Kleine-König
2024-01-09  8:23 ` [DO NOT MERGE v6 27/37] dt-bindings: ata: ata-generic: Add new targets Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09 18:07   ` Conor Dooley
2024-01-09 18:07     ` Conor Dooley
2024-01-09 18:09     ` Conor Dooley
2024-01-09 18:09       ` Conor Dooley
2024-01-10  2:06   ` Damien Le Moal
2024-01-10  2:06     ` Damien Le Moal
2024-01-10  7:19     ` Krzysztof Kozlowski
2024-01-10  7:19       ` Krzysztof Kozlowski
2024-01-10  7:25       ` Damien Le Moal
2024-01-10  7:25         ` Damien Le Moal
2024-01-09  8:23 ` [DO NOT MERGE v6 28/37] dt-bindings: soc: renesas: sh: Add SH7751 based target Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-02-27 15:58   ` Geert Uytterhoeven
2024-01-09  8:23 ` [DO NOT MERGE v6 29/37] sh: SH7751R SoC Internal peripheral definition dtsi Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 30/37] sh: add RTS7751R2D Plus DTS Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 31/37] sh: Add IO DATA LANDISK dts Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 32/37] sh: Add IO DATA USL-5P dts Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 33/37] sh: j2_mimas_v2.dts update Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-02-27 16:07   ` Geert Uytterhoeven
2024-01-09  8:23 ` [DO NOT MERGE v6 34/37] sh: Add dtbs target support Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-02-27 18:48   ` Geert Uytterhoeven
2024-01-09  8:23 ` [DO NOT MERGE v6 35/37] sh: RTS7751R2D Plus OF defconfig Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 36/37] sh: LANDISK " Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato
2024-01-09  8:23 ` [DO NOT MERGE v6 37/37] sh: j2_defconfig: update Yoshinori Sato
2024-01-09  8:23   ` Yoshinori Sato

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=28b339d21fa7b74c75f181d3dc710f667da5f228.1704788539.git.ysato@users.sourceforge.jp \
    --to=ysato@users.sourceforge.jp \
    --cc=42.hyeyoo@gmail.com \
    --cc=airlied@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=arnd@arndb.de \
    --cc=azeemshaikh38@gmail.com \
    --cc=bhe@redhat.com \
    --cc=bhelgaas@google.com \
    --cc=biju.das.jz@bp.renesas.com \
    --cc=bmeng@tinylab.org \
    --cc=conor+dt@kernel.org \
    --cc=corbet@lwn.net \
    --cc=dalias@libc.org \
    --cc=daniel.lezcano@linaro.org \
    --cc=daniel@ffwll.ch \
    --cc=deller@gmx.de \
    --cc=devicetree@vger.kernel.org \
    --cc=dlemoal@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=forbidden405@foxmail.com \
    --cc=geert+renesas@glider.be \
    --cc=glaubitz@physik.fu-berlin.de \
    --cc=gregkh@linuxfoundation.org \
    --cc=heiko@sntech.de \
    --cc=javierm@redhat.com \
    --cc=jcmvbkbc@gmail.com \
    --cc=jernej.skrabec@gmail.com \
    --cc=jirislaby@kernel.org \
    --cc=kernel@mkarcher.dialup.fu-berlin.de \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=kw@linux.com \
    --cc=laurent.pinchart+renesas@ideasonboard.com \
    --cc=lee@kernel.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=linux-ide@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-renesas-soc@vger.kernel.org \
    --cc=linux-serial@vger.kernel.org \
    --cc=linux-sh@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=lpieralisi@kernel.org \
    --cc=lukas.bulwahn@gmail.com \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=macromorgan@hotmail.com \
    --cc=magnus.damm@gmail.com \
    --cc=mripard@kernel.org \
    --cc=mturquette@baylibre.com \
    --cc=palmer@rivosinc.com \
    --cc=rdunlap@infradead.org \
    --cc=rientjes@google.com \
    --cc=robh+dt@kernel.org \
    --cc=s.shtylyov@omp.ru \
    --cc=sam@ravnborg.org \
    --cc=sboyd@kernel.org \
    --cc=sfr@canb.auug.org.au \
    --cc=sre@kernel.org \
    --cc=tglx@linutronix.de \
    --cc=tzimmermann@suse.de \
    --cc=u.kleine-koenig@pengutronix.de \
    --cc=vbabka@suse.cz \
    --cc=ychuang3@nuvoton.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.