linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 0/5] clk: shmobile: Add new CPG/MSSR driver
@ 2015-10-29 11:20 Geert Uytterhoeven
  2015-10-29 11:21 ` [PATCH v5 1/5] clk: shmobile: Rework CONFIG_ARCH_SHMOBILE_MULTI Geert Uytterhoeven
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Geert Uytterhoeven @ 2015-10-29 11:20 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Magnus Damm, Simon Horman,
	Laurent Pinchart
  Cc: linux-clk, linux-sh, linux-kernel, Geert Uytterhoeven

	Hi Mike, Stephen, et al.,

This series adds a new driver for the Renesas CPG (Clock Pulse
Generator) and MSSR (Module Standby and Software Reset) blocks for R-Car
H3 (r8a7795).  This is supposed to be more in-line with current CCF best
practices, and allows expansion to cover the module reset functionality
in the future. This drivers follows the DT bindings in
Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt, which have
been accepted in clk/clk-next.
Support for other SoCs may be added later.

  - Patch 1 reworks configuration after the removal of shmobile-legacy,
    and prepares for the advent of arm64 support, where
    CONFIG_ARCH_SHMOBILE_MULTI is not defined.
  - Patch 2 makes clock-output-names optional in the DIV6 driver.
    This is a bit unrelated, but I had sent this patch before, and
    there's a contextual dependency,
  - Patch 3 prepares the existing DIV6 driver for reuse,
  - Patch 4 introduces the new CPG/MSSR driver core, to be used by
    several SoC-specific drivers,
  - Patch 5 introduces the new r8a7795-specific driver.

Compared to v4, major changes are:
  - Convert from CLK_OF_DECLARE() to a real platform_driver, initialized
    using platform_driver_probe() from subsys_initcall().
    Note that arch_initcall() would be OK for arm32, but not for arm64:
      - arm32 calls of_platform_populate() from arch_initcall(),
      - arm64 calls of_platform_populate() from arch_initcall_sync().
  - Move conversion from Module Clock numbers to IDs from run time (C
    code) to compile time (CPP macros for filling in tables),
  - Implement handling of core clocks that are suitable for power
    management (not needed for R-Car, but useful for SH-Mobile AG5 and
    R-Mobile APE6),
More detailed changelog information is available in the individual
patches.

For your convenience, I pushed these patches and its dependencies to the
topic/cpg-mssr-v5 branch of my
renesas-drivers repository at
https://git.kernel.org/cgit/linux/kernel/git/geert/renesas-drivers.git/log/?h=topic/cpg-mssr-v5.

A full integration for R-Car Gen3 is available from the
topic/gen3-latest branch.

Thanks for your comments!

References:
  - v4 = "[PATCH/RFC v4 0/5] clk: shmobile: Add new Renesas CPG/MSSR DT
    bindings" (http://www.spinics.net/lists/devicetree/msg98342.html)
  - v3 = "[PATCH/RFC v3 0/3] clk: shmobile: Add new Renesas CPG/MSSR DT
    bindings" (http://www.spinics.net/lists/linux-sh/msg45870.html)
  - v2+ ≈ "[PATCH v8 00/05] Renesas R-Car Gen3 CPG support V8"
    (http://www.spinics.net/lists/linux-clk/msg03288.html)
  - v2 = "[PATCH/RFC v2 0/4] Renesas CPG/MSTP DT Binding Proposal"
    (http://www.spinics.net/lists/linux-clk/msg03132.html)
  - v1 = "Renesas CPG/MSTP DT Binding Proposal"
    (http://www.spinics.net/lists/linux-clk/msg01189.html)

Geert Uytterhoeven (4):
  clk: shmobile: div6: Make clock-output-names optional
  clk: shmobile: div6: Extract cpg_div6_register()
  clk: shmobile: Add new CPG/MSSR driver core
  clk: shmobile: r8a7795: Add new CPG/MSSR driver

Magnus Damm (1):
  clk: shmobile: Rework CONFIG_ARCH_SHMOBILE_MULTI

 .../bindings/clock/renesas,cpg-div6-clocks.txt     |   4 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/shmobile/Makefile                      |  24 +-
 drivers/clk/shmobile/clk-div6.c                    | 137 +++--
 drivers/clk/shmobile/clk-div6.h                    |   7 +
 drivers/clk/shmobile/r8a7795-cpg-mssr.c            | 373 +++++++++++++
 drivers/clk/shmobile/renesas-cpg-mssr.c            | 593 +++++++++++++++++++++
 drivers/clk/shmobile/renesas-cpg-mssr.h            | 132 +++++
 8 files changed, 1208 insertions(+), 63 deletions(-)
 create mode 100644 drivers/clk/shmobile/clk-div6.h
 create mode 100644 drivers/clk/shmobile/r8a7795-cpg-mssr.c
 create mode 100644 drivers/clk/shmobile/renesas-cpg-mssr.c
 create mode 100644 drivers/clk/shmobile/renesas-cpg-mssr.h

-- 
1.9.1

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v5 1/5] clk: shmobile: Rework CONFIG_ARCH_SHMOBILE_MULTI
  2015-10-29 11:20 [PATCH v5 0/5] clk: shmobile: Add new CPG/MSSR driver Geert Uytterhoeven
@ 2015-10-29 11:21 ` Geert Uytterhoeven
  2015-10-29 11:21 ` [PATCH v5 2/5] clk: shmobile: div6: Make clock-output-names optional Geert Uytterhoeven
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Geert Uytterhoeven @ 2015-10-29 11:21 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Magnus Damm, Simon Horman,
	Laurent Pinchart
  Cc: linux-clk, linux-sh, linux-kernel, Geert Uytterhoeven

From: Magnus Damm <damm+renesas@opensource.se>

Shmobile is all multiplatform these days, so get rid of the reference to
CONFIG_ARCH_SHMOBILE_MULTI in drivers/clk/shmobile/.

Also instead of always enabling DIV6 and MSTP adjust the Makefile
to enable DIV6 and MSTP depending on if they are included in the
SoC or not.

Signed-off-by: Magnus Damm <damm+renesas@opensource.se>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v5:
  - Integrated in this series as a dependency.
---
 drivers/clk/shmobile/Makefile | 22 ++++++++++------------
 1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index 97c71c885e4f38c5..1eb947db6f5926a0 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -1,13 +1,11 @@
 obj-$(CONFIG_ARCH_EMEV2)		+= clk-emev2.o
-obj-$(CONFIG_ARCH_R7S72100)		+= clk-rz.o
-obj-$(CONFIG_ARCH_R8A73A4)		+= clk-r8a73a4.o
-obj-$(CONFIG_ARCH_R8A7740)		+= clk-r8a7740.o
-obj-$(CONFIG_ARCH_R8A7778)		+= clk-r8a7778.o
-obj-$(CONFIG_ARCH_R8A7779)		+= clk-r8a7779.o
-obj-$(CONFIG_ARCH_R8A7790)		+= clk-rcar-gen2.o
-obj-$(CONFIG_ARCH_R8A7791)		+= clk-rcar-gen2.o
-obj-$(CONFIG_ARCH_R8A7793)		+= clk-rcar-gen2.o
-obj-$(CONFIG_ARCH_R8A7794)		+= clk-rcar-gen2.o
-obj-$(CONFIG_ARCH_SH73A0)		+= clk-sh73a0.o
-obj-$(CONFIG_ARCH_SHMOBILE_MULTI)	+= clk-div6.o
-obj-$(CONFIG_ARCH_SHMOBILE_MULTI)	+= clk-mstp.o
+obj-$(CONFIG_ARCH_R7S72100)		+= clk-rz.o clk-mstp.o
+obj-$(CONFIG_ARCH_R8A73A4)		+= clk-r8a73a4.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7740)		+= clk-r8a7740.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7778)		+= clk-r8a7778.o clk-mstp.o
+obj-$(CONFIG_ARCH_R8A7779)		+= clk-r8a7779.o clk-mstp.o
+obj-$(CONFIG_ARCH_R8A7790)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7791)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7793)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7794)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_SH73A0)		+= clk-sh73a0.o clk-mstp.o clk-div6.o
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v5 2/5] clk: shmobile: div6: Make clock-output-names optional
  2015-10-29 11:20 [PATCH v5 0/5] clk: shmobile: Add new CPG/MSSR driver Geert Uytterhoeven
  2015-10-29 11:21 ` [PATCH v5 1/5] clk: shmobile: Rework CONFIG_ARCH_SHMOBILE_MULTI Geert Uytterhoeven
@ 2015-10-29 11:21 ` Geert Uytterhoeven
  2015-10-30 13:47   ` Laurent Pinchart
  2015-10-29 11:21 ` [PATCH v5 3/5] clk: shmobile: div6: Extract cpg_div6_register() Geert Uytterhoeven
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Geert Uytterhoeven @ 2015-10-29 11:21 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Magnus Damm, Simon Horman,
	Laurent Pinchart
  Cc: linux-clk, linux-sh, linux-kernel, Geert Uytterhoeven

Renesas DIV6 clocks provide a single clock output.  Hence make the
"clock-output-names" DT property optional instead of mandatory. In case
the DT property is omitted the DT node name will be used.

Rename the variable "name" to "clk_name" to make the code more similar
with fixed-factor-clock.c, and to avoid a conflict with a nested local
variable while we're at it.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v5:
  - Integrated in this series as a dependency.
---
 .../devicetree/bindings/clock/renesas,cpg-div6-clocks.txt   |  4 ++++
 drivers/clk/shmobile/clk-div6.c                             | 13 +++----------
 2 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
index 5ddb68418655d569..86008ad354cf4bbd 100644
--- a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
@@ -20,6 +20,10 @@ Required Properties:
     clocks must be specified.  For clocks with multiple parents, invalid
     settings must be specified as "<0>".
   - #clock-cells: Must be 0
+
+
+Optional Properties:
+
   - clock-output-names: The name of the clock as a free-form string
 
 
diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c
index 036a692c72195db9..c89566a918290246 100644
--- a/drivers/clk/shmobile/clk-div6.c
+++ b/drivers/clk/shmobile/clk-div6.c
@@ -178,10 +178,9 @@ static void __init cpg_div6_clock_init(struct device_node *np)
 	const char **parent_names;
 	struct clk_init_data init;
 	struct div6_clock *clock;
-	const char *name;
+	const char *clk_name = np->name;
 	struct clk *clk;
 	unsigned int i;
-	int ret;
 
 	clock = kzalloc(sizeof(*clock), GFP_KERNEL);
 	if (!clock)
@@ -215,13 +214,7 @@ static void __init cpg_div6_clock_init(struct device_node *np)
 	clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1;
 
 	/* Parse the DT properties. */
-	ret = of_property_read_string(np, "clock-output-names", &name);
-	if (ret < 0) {
-		pr_err("%s: failed to get %s DIV6 clock output name\n",
-		       __func__, np->name);
-		goto error;
-	}
-
+	of_property_read_string(np, "clock-output-names", &clk_name);
 
 	for (i = 0, valid_parents = 0; i < num_parents; i++) {
 		const char *name = of_clk_get_parent_name(np, i);
@@ -255,7 +248,7 @@ static void __init cpg_div6_clock_init(struct device_node *np)
 	}
 
 	/* Register the clock. */
-	init.name = name;
+	init.name = clk_name;
 	init.ops = &cpg_div6_clock_ops;
 	init.flags = CLK_IS_BASIC;
 	init.parent_names = parent_names;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v5 3/5] clk: shmobile: div6: Extract cpg_div6_register()
  2015-10-29 11:20 [PATCH v5 0/5] clk: shmobile: Add new CPG/MSSR driver Geert Uytterhoeven
  2015-10-29 11:21 ` [PATCH v5 1/5] clk: shmobile: Rework CONFIG_ARCH_SHMOBILE_MULTI Geert Uytterhoeven
  2015-10-29 11:21 ` [PATCH v5 2/5] clk: shmobile: div6: Make clock-output-names optional Geert Uytterhoeven
@ 2015-10-29 11:21 ` Geert Uytterhoeven
  2015-10-30 13:54   ` Laurent Pinchart
  2015-10-29 11:21 ` [PATCH v5 4/5] clk: shmobile: Add new CPG/MSSR driver core Geert Uytterhoeven
  2015-10-29 11:21 ` [PATCH v5 5/5] clk: shmobile: r8a7795: Add new CPG/MSSR driver Geert Uytterhoeven
  4 siblings, 1 reply; 10+ messages in thread
From: Geert Uytterhoeven @ 2015-10-29 11:21 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Magnus Damm, Simon Horman,
	Laurent Pinchart
  Cc: linux-clk, linux-sh, linux-kernel, Geert Uytterhoeven

Extract cpg_div6_register(), to allow registering div6 clocks from
another clock driver.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v5:
  - Document cpg_div6_register(),
  - Free clock on clock->parents allocation failure,
  - Add include guards to clk-div6.h,
  - Drop RFC state,

v4:
  - New.
---
 drivers/clk/shmobile/clk-div6.c | 132 ++++++++++++++++++++++++++--------------
 drivers/clk/shmobile/clk-div6.h |   7 +++
 2 files changed, 94 insertions(+), 45 deletions(-)
 create mode 100644 drivers/clk/shmobile/clk-div6.h

diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c
index c89566a918290246..5970d6a1506a9075 100644
--- a/drivers/clk/shmobile/clk-div6.c
+++ b/drivers/clk/shmobile/clk-div6.c
@@ -18,6 +18,8 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 
+#include "clk-div6.h"
+
 #define CPG_DIV6_CKSTP		BIT(8)
 #define CPG_DIV6_DIV(d)		((d) & 0x3f)
 #define CPG_DIV6_DIV_MASK	0x3f
@@ -172,60 +174,44 @@ static const struct clk_ops cpg_div6_clock_ops = {
 	.set_rate = cpg_div6_clock_set_rate,
 };
 
-static void __init cpg_div6_clock_init(struct device_node *np)
+
+/**
+ * cpg_div6_register - Register a DIV6 clock
+ * @name: Name of the DIV6 clock
+ * @num_parents: Number of parent clocks of the DIV6 clock (1, 4, or 8)
+ * @parent_names: Array containing the names of the parent clocks
+ * @reg: Mapped register used to control the DIV6 clock
+ */
+struct clk * __init cpg_div6_register(const char *name,
+				      unsigned int num_parents,
+				      const char **parent_names,
+				      void __iomem *reg)
 {
-	unsigned int num_parents, valid_parents;
-	const char **parent_names;
+	unsigned int valid_parents;
 	struct clk_init_data init;
 	struct div6_clock *clock;
-	const char *clk_name = np->name;
 	struct clk *clk;
 	unsigned int i;
 
 	clock = kzalloc(sizeof(*clock), GFP_KERNEL);
 	if (!clock)
-		return;
+		return ERR_PTR(-ENOMEM);
 
-	num_parents = of_clk_get_parent_count(np);
-	if (num_parents < 1) {
-		pr_err("%s: no parent found for %s DIV6 clock\n",
-		       __func__, np->name);
-		return;
+	clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
+				       GFP_KERNEL);
+	if (!clock->parents) {
+		clk = ERR_PTR(-ENOMEM);
+		goto free_clock;
 	}
 
-	clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
-		GFP_KERNEL);
-	parent_names = kmalloc_array(num_parents, sizeof(*parent_names),
-				GFP_KERNEL);
-	if (!parent_names)
-		return;
+	clock->reg = reg;
 
-	/* Remap the clock register and read the divisor. Disabling the
-	 * clock overwrites the divisor, so we need to cache its value for the
-	 * enable operation.
+	/*
+	 * Read the divisor. Disabling the clock overwrites the divisor, so we
+	 * need to cache its value for the enable operation.
 	 */
-	clock->reg = of_iomap(np, 0);
-	if (clock->reg == NULL) {
-		pr_err("%s: failed to map %s DIV6 clock register\n",
-		       __func__, np->name);
-		goto error;
-	}
-
 	clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1;
 
-	/* Parse the DT properties. */
-	of_property_read_string(np, "clock-output-names", &clk_name);
-
-	for (i = 0, valid_parents = 0; i < num_parents; i++) {
-		const char *name = of_clk_get_parent_name(np, i);
-
-		if (name) {
-			parent_names[valid_parents] = name;
-			clock->parents[valid_parents] = i;
-			valid_parents++;
-		}
-	}
-
 	switch (num_parents) {
 	case 1:
 		/* fixed parent clock */
@@ -243,12 +229,22 @@ static void __init cpg_div6_clock_init(struct device_node *np)
 		break;
 	default:
 		pr_err("%s: invalid number of parents for DIV6 clock %s\n",
-		       __func__, np->name);
-		goto error;
+		       __func__, name);
+		clk = ERR_PTR(-EINVAL);
+		goto free_parents;
+	}
+
+	/* Filter out invalid parents */
+	for (i = 0, valid_parents = 0; i < num_parents; i++) {
+		if (parent_names[i]) {
+			parent_names[valid_parents] = parent_names[i];
+			clock->parents[valid_parents] = i;
+			valid_parents++;
+		}
 	}
 
 	/* Register the clock. */
-	init.name = clk_name;
+	init.name = name;
 	init.ops = &cpg_div6_clock_ops;
 	init.flags = CLK_IS_BASIC;
 	init.parent_names = parent_names;
@@ -257,6 +253,53 @@ static void __init cpg_div6_clock_init(struct device_node *np)
 	clock->hw.init = &init;
 
 	clk = clk_register(NULL, &clock->hw);
+	if (IS_ERR(clk))
+		goto free_parents;
+
+	return clk;
+
+free_parents:
+	kfree(clock->parents);
+free_clock:
+	kfree(clock);
+	return clk;
+}
+
+static void __init cpg_div6_clock_init(struct device_node *np)
+{
+	unsigned int num_parents;
+	const char **parent_names;
+	const char *clk_name = np->name;
+	void __iomem *reg;
+	struct clk *clk;
+	unsigned int i;
+
+	num_parents = of_clk_get_parent_count(np);
+	if (num_parents < 1) {
+		pr_err("%s: no parent found for %s DIV6 clock\n",
+		       __func__, np->name);
+		return;
+	}
+
+	parent_names = kmalloc_array(num_parents, sizeof(*parent_names),
+				GFP_KERNEL);
+	if (!parent_names)
+		return;
+
+	reg = of_iomap(np, 0);
+	if (reg == NULL) {
+		pr_err("%s: failed to map %s DIV6 clock register\n",
+		       __func__, np->name);
+		goto error;
+	}
+
+	/* Parse the DT properties. */
+	of_property_read_string(np, "clock-output-names", &clk_name);
+
+	for (i = 0; i < num_parents; i++)
+		parent_names[i] = of_clk_get_parent_name(np, i);
+
+	clk = cpg_div6_register(clk_name, num_parents, parent_names, reg);
 	if (IS_ERR(clk)) {
 		pr_err("%s: failed to register %s DIV6 clock (%ld)\n",
 		       __func__, np->name, PTR_ERR(clk));
@@ -269,9 +312,8 @@ static void __init cpg_div6_clock_init(struct device_node *np)
 	return;
 
 error:
-	if (clock->reg)
-		iounmap(clock->reg);
+	if (reg)
+		iounmap(reg);
 	kfree(parent_names);
-	kfree(clock);
 }
 CLK_OF_DECLARE(cpg_div6_clk, "renesas,cpg-div6-clock", cpg_div6_clock_init);
diff --git a/drivers/clk/shmobile/clk-div6.h b/drivers/clk/shmobile/clk-div6.h
new file mode 100644
index 0000000000000000..9a85a95188daa813
--- /dev/null
+++ b/drivers/clk/shmobile/clk-div6.h
@@ -0,0 +1,7 @@
+#ifndef __SHMOBILE_CLK_DIV6_H__
+#define __SHMOBILE_CLK_DIV6_H__
+
+struct clk *cpg_div6_register(const char *name, unsigned int num_parents,
+			      const char **parent_names, void __iomem *reg);
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v5 4/5] clk: shmobile: Add new CPG/MSSR driver core
  2015-10-29 11:20 [PATCH v5 0/5] clk: shmobile: Add new CPG/MSSR driver Geert Uytterhoeven
                   ` (2 preceding siblings ...)
  2015-10-29 11:21 ` [PATCH v5 3/5] clk: shmobile: div6: Extract cpg_div6_register() Geert Uytterhoeven
@ 2015-10-29 11:21 ` Geert Uytterhoeven
  2015-10-29 11:21 ` [PATCH v5 5/5] clk: shmobile: r8a7795: Add new CPG/MSSR driver Geert Uytterhoeven
  4 siblings, 0 replies; 10+ messages in thread
From: Geert Uytterhoeven @ 2015-10-29 11:21 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Magnus Damm, Simon Horman,
	Laurent Pinchart
  Cc: linux-clk, linux-sh, linux-kernel, Geert Uytterhoeven

Add the common core for the new Renesas Clock Pulse Generator / Module
Standby and Software Reset driver.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v5:
  - Convert from CLK_OF_DECLARE() to a real platform_driver, initialized
    using platform_driver_probe() from subsys_initcall().
    Note that arch_initcall() would be OK for arm32, but not for arm64:
      - arm32 calls of_platform_populate() from arch_initcall(),
      - arm64 calls of_platform_populate() from arch_initcall_sync().
  - Implement handling of core clocks that are suitable for power
    management (not needed for R-Car, but useful for SH-Mobile AG5 and
    R-Mobile APE6),
  - Add cpg_mssr_info.init(), as initialization is now done from the
    core driver,
  - Move conversion from Module Clock numbers to IDs from run time (C
    code) to compile time (CPP macros for filling in tables),
  - Unify some code to handle CLK_TYPE_IN and CLK_TYPE_FF,
  - Rename from clk-cpg-mssr to renesas-cpg-mssr,
  - Add include guards to clk-cpg-mssr.h,
  - Improve struct documentation,
  - Clean up debugging code,
  - Drop RFC state,

v4:
  - New.
---
 drivers/clk/shmobile/renesas-cpg-mssr.c | 587 ++++++++++++++++++++++++++++++++
 drivers/clk/shmobile/renesas-cpg-mssr.h | 131 +++++++
 2 files changed, 718 insertions(+)
 create mode 100644 drivers/clk/shmobile/renesas-cpg-mssr.c
 create mode 100644 drivers/clk/shmobile/renesas-cpg-mssr.h

diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.c b/drivers/clk/shmobile/renesas-cpg-mssr.c
new file mode 100644
index 0000000000000000..e4382ba4e1e31aca
--- /dev/null
+++ b/drivers/clk/shmobile/renesas-cpg-mssr.c
@@ -0,0 +1,587 @@
+/*
+ * Renesas Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * Based on clk-mstp.c, clk-rcar-gen2.c, and clk-rcar-gen3.c
+ *
+ * Copyright (C) 2013 Ideas On Board SPRL
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+#include "clk-div6.h"
+
+#ifdef DEBUG
+#define WARN_DEBUG(x)	do { } while (0)
+#else
+#define WARN_DEBUG(x)	WARN_ON(x)
+#endif
+
+
+/*
+ * Module Standby and Software Reset register offets.
+ *
+ * If the registers exist, these are valid for SH-Mobile, R-Mobile,
+ * R-Car Gen 2, and R-Car Gen 3.
+ * These are NOT valid for R-Car Gen1 and RZ/A1!
+ */
+
+/*
+ * Module Stop Status Register offsets
+ */
+
+static const u16 mstpsr[] = {
+	0x030, 0x038, 0x040, 0x048, 0x04C, 0x03C, 0x1C0, 0x1C4,
+	0x9A0, 0x9A4, 0x9A8, 0x9AC,
+};
+
+#define	MSTPSR(i)	mstpsr[i]
+
+
+/*
+ * System Module Stop Control Register offsets
+ */
+
+static const u16 smstpcr[] = {
+	0x130, 0x134, 0x138, 0x13C, 0x140, 0x144, 0x148, 0x14C,
+	0x990, 0x994, 0x998, 0x99C,
+};
+
+#define	SMSTPCR(i)	smstpcr[i]
+
+
+/*
+ * Software Reset Register offsets
+ */
+
+static const u16 srcr[] = {
+	0x0A0, 0x0A8, 0x0B0, 0x0B8, 0x0BC, 0x0C4, 0x1C8, 0x1CC,
+	0x920, 0x924, 0x928, 0x92C,
+};
+
+#define	SRCR(i)		srcr[i]
+
+
+/* Realtime Module Stop Control Register offsets */
+#define RMSTPCR(i)	(smstpcr[i] - 0x20)
+
+/* Modem Module Stop Control Register offsets (r8a73a4) */
+#define MMSTPCR(i)	(smstpcr[i] + 0x20)
+
+/* Software Reset Clearing Register offsets */
+#define	SRSTCLR(i)	(0x940 + (i) * 4)
+
+
+/**
+ * Clock Pulse Generator / Module Standby and Software Reset Private Data
+ *
+ * @dev: CPG/MSSR device
+ * @base: CPG/MSSR register block base address
+ * @mstp_lock: protects writes to SMSTPCR
+ * @clks: Array containing all Core and Module Clocks
+ * @num_core_clks: Number of Core Clocks in clks[]
+ * @num_mod_clks: Number of Module Clocks in clks[]
+ * @last_dt_core_clk: ID of the last Core Clock exported to DT
+ */
+struct cpg_mssr_priv {
+	struct device *dev;
+	void __iomem *base;
+	spinlock_t mstp_lock;
+
+	struct clk **clks;
+	unsigned int num_core_clks;
+	unsigned int num_mod_clks;
+	unsigned int last_dt_core_clk;
+};
+
+
+/**
+ * struct mstp_clock - MSTP gating clock
+ * @hw: handle between common and hardware-specific interfaces
+ * @index: MSTP clock number
+ * @priv: CPG/MSSR private data
+ */
+struct mstp_clock {
+	struct clk_hw hw;
+	u32 index;
+	struct cpg_mssr_priv *priv;
+};
+
+#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw)
+
+static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
+{
+	struct mstp_clock *clock = to_mstp_clock(hw);
+	struct cpg_mssr_priv *priv = clock->priv;
+	unsigned int reg = clock->index / 32;
+	unsigned int bit = clock->index % 32;
+	struct device *dev = priv->dev;
+	u32 bitmask = BIT(bit);
+	unsigned long flags;
+	unsigned int i;
+	u32 value;
+
+	dev_dbg(dev, "MSTP %u%02u/%pC %s\n", reg, bit, hw->clk,
+		enable ? "ON" : "OFF");
+	spin_lock_irqsave(&priv->mstp_lock, flags);
+
+	value = clk_readl(priv->base + SMSTPCR(reg));
+	if (enable)
+		value &= ~bitmask;
+	else
+		value |= bitmask;
+	clk_writel(value, priv->base + SMSTPCR(reg));
+
+	spin_unlock_irqrestore(&priv->mstp_lock, flags);
+
+	if (!enable)
+		return 0;
+
+	for (i = 1000; i > 0; --i) {
+		if (!(clk_readl(priv->base + MSTPSR(reg)) &
+		      bitmask))
+			break;
+		cpu_relax();
+	}
+
+	if (!i) {
+		dev_err(dev, "Failed to enable SMSTP %p[%d]\n",
+			priv->base + SMSTPCR(reg), bit);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int cpg_mstp_clock_enable(struct clk_hw *hw)
+{
+	return cpg_mstp_clock_endisable(hw, true);
+}
+
+static void cpg_mstp_clock_disable(struct clk_hw *hw)
+{
+	cpg_mstp_clock_endisable(hw, false);
+}
+
+static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
+{
+	struct mstp_clock *clock = to_mstp_clock(hw);
+	struct cpg_mssr_priv *priv = clock->priv;
+	u32 value;
+
+	value = clk_readl(priv->base + MSTPSR(clock->index / 32));
+
+	return !(value & BIT(clock->index % 32));
+}
+
+static const struct clk_ops cpg_mstp_clock_ops = {
+	.enable = cpg_mstp_clock_enable,
+	.disable = cpg_mstp_clock_disable,
+	.is_enabled = cpg_mstp_clock_is_enabled,
+};
+
+static
+struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
+					 void *data)
+{
+	unsigned int clkidx = clkspec->args[1];
+	struct cpg_mssr_priv *priv = data;
+	struct device *dev = priv->dev;
+	unsigned int idx;
+	const char *type;
+	struct clk *clk;
+
+	switch (clkspec->args[0]) {
+	case CPG_CORE:
+		type = "core";
+		if (clkidx > priv->last_dt_core_clk) {
+			dev_err(dev, "Invalid %s clock index %u\n", type,
+			       clkidx);
+			return ERR_PTR(-EINVAL);
+		}
+		clk = priv->clks[clkidx];
+		break;
+
+	case CPG_MOD:
+		type = "module";
+		idx = MOD_CLK_PACK(clkidx);
+		if (clkidx % 100 > 31 || idx >= priv->num_mod_clks) {
+			dev_err(dev, "Invalid %s clock index %u\n", type,
+				clkidx);
+			return ERR_PTR(-EINVAL);
+		}
+		clk = priv->clks[priv->num_core_clks + idx];
+		break;
+
+	default:
+		dev_err(dev, "Invalid CPG clock type %u\n", clkspec->args[0]);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (IS_ERR(clk))
+		dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx,
+		       PTR_ERR(clk));
+	else
+		dev_dbg(dev, "clock (%u, %u) is %pC at %pCr Hz\n",
+			clkspec->args[0], clkspec->args[1], clk, clk);
+	return clk;
+}
+
+static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
+					      const struct cpg_mssr_info *info,
+					      struct cpg_mssr_priv *priv)
+{
+	struct clk *clk = NULL, *parent;
+	struct device *dev = priv->dev;
+	unsigned int id = core->id;
+	const char *parent_name;
+
+	WARN_DEBUG(id >= priv->num_core_clks);
+	WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
+
+	switch (core->type) {
+	case CLK_TYPE_IN:
+		clk = of_clk_get_by_name(priv->dev->of_node, core->name);
+		break;
+
+	case CLK_TYPE_FF:
+	case CLK_TYPE_DIV6P1:
+		WARN_DEBUG(core->parent >= priv->num_core_clks);
+		parent = priv->clks[core->parent];
+		if (IS_ERR(parent)) {
+			clk = parent;
+			goto fail;
+		}
+
+		parent_name = __clk_get_name(parent);
+		if (core->type == CLK_TYPE_FF) {
+			clk = clk_register_fixed_factor(NULL, core->name,
+							parent_name, 0,
+							core->mult, core->div);
+		} else {
+			clk = cpg_div6_register(core->name, 1, &parent_name,
+						priv->base + core->offset);
+		}
+		break;
+
+	default:
+		if (info->cpg_clk_register)
+			clk = info->cpg_clk_register(dev, core, info,
+						     priv->clks, priv->base);
+		else
+			dev_err(dev, "%s has unsupported core clock type %u\n",
+				core->name, core->type);
+		break;
+	}
+
+	if (IS_ERR_OR_NULL(clk))
+		goto fail;
+
+	dev_dbg(dev, "Core clock %pC at %pCr Hz\n", clk, clk);
+	priv->clks[id] = clk;
+	return;
+
+fail:
+	dev_err(dev, "Failed to register %s clock %s: %ld\n", "core,",
+		core->name, PTR_ERR(clk));
+}
+
+static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod,
+					     const struct cpg_mssr_info *info,
+					     struct cpg_mssr_priv *priv)
+{
+	struct mstp_clock *clock = NULL;
+	struct device *dev = priv->dev;
+	unsigned int id = mod->id;
+	struct clk_init_data init;
+	struct clk *parent, *clk;
+	const char *parent_name;
+	unsigned int i;
+
+	WARN_DEBUG(id < priv->num_core_clks);
+	WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks);
+	WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks);
+	WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
+
+	parent = priv->clks[mod->parent];
+	if (IS_ERR(parent)) {
+		clk = parent;
+		goto fail;
+	}
+
+	clock = kzalloc(sizeof(*clock), GFP_KERNEL);
+	if (!clock) {
+		clk = ERR_PTR(-ENOMEM);
+		goto fail;
+	}
+
+	init.name = mod->name;
+	init.ops = &cpg_mstp_clock_ops;
+	init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
+	for (i = 0; i < info->num_crit_mod_clks; i++)
+		if (id == info->crit_mod_clks[i]) {
+#ifdef CLK_ENABLE_HAND_OFF
+			dev_dbg(dev, "MSTP %s setting CLK_ENABLE_HAND_OFF\n",
+				mod->name);
+			init.flags |= CLK_ENABLE_HAND_OFF;
+			break;
+#else
+			dev_dbg(dev, "Ignoring MSTP %s to prevent disabling\n",
+				mod->name);
+			return;
+#endif
+		}
+
+	parent_name = __clk_get_name(parent);
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	clock->index = id - priv->num_core_clks;
+	clock->priv = priv;
+	clock->hw.init = &init;
+
+	clk = clk_register(NULL, &clock->hw);
+	if (IS_ERR(clk))
+		goto fail;
+
+	dev_dbg(dev, "Module clock %pC at %pCr Hz\n", clk, clk);
+	priv->clks[id] = clk;
+	return;
+
+fail:
+	dev_err(dev, "Failed to register %s clock %s: %ld\n", "module,",
+		mod->name, PTR_ERR(clk));
+	kfree(clock);
+}
+
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
+struct cpg_mssr_clk_domain {
+	struct generic_pm_domain genpd;
+	struct device_node *np;
+	unsigned int num_core_pm_clks;
+	unsigned int core_pm_clks[0];
+};
+
+static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec,
+			       struct cpg_mssr_clk_domain *pd)
+{
+	unsigned int i;
+
+	if (clkspec->np != pd->np || clkspec->args_count != 2)
+		return false;
+
+	switch (clkspec->args[0]) {
+	case CPG_CORE:
+		for (i = 0; i < pd->num_core_pm_clks; i++)
+			if (clkspec->args[1] == pd->core_pm_clks[i])
+				return true;
+		return false;
+
+	case CPG_MOD:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+static int cpg_mssr_attach_dev(struct generic_pm_domain *genpd,
+			       struct device *dev)
+{
+	struct cpg_mssr_clk_domain *pd =
+		container_of(genpd, struct cpg_mssr_clk_domain, genpd);
+	struct device_node *np = dev->of_node;
+	struct of_phandle_args clkspec;
+	struct clk *clk;
+	int i = 0;
+	int error;
+
+	while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
+					   &clkspec)) {
+		if (cpg_mssr_is_pm_clk(&clkspec, pd))
+			goto found;
+
+		of_node_put(clkspec.np);
+		i++;
+	}
+
+	return 0;
+
+found:
+	clk = of_clk_get_from_provider(&clkspec);
+	of_node_put(clkspec.np);
+
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	error = pm_clk_create(dev);
+	if (error) {
+		dev_err(dev, "pm_clk_create failed %d\n", error);
+		goto fail_put;
+	}
+
+	error = pm_clk_add_clk(dev, clk);
+	if (error) {
+		dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
+		goto fail_destroy;
+	}
+
+	return 0;
+
+fail_destroy:
+	pm_clk_destroy(dev);
+fail_put:
+	clk_put(clk);
+	return error;
+}
+
+static void cpg_mssr_detach_dev(struct generic_pm_domain *genpd,
+				struct device *dev)
+{
+	if (!list_empty(&dev->power.subsys_data->clock_list))
+		pm_clk_destroy(dev);
+}
+
+static int __init cpg_mssr_add_clk_domain(struct device *dev,
+					  const unsigned int *core_pm_clks,
+					  unsigned int num_core_pm_clks)
+{
+	struct device_node *np = dev->of_node;
+	struct generic_pm_domain *genpd;
+	struct cpg_mssr_clk_domain *pd;
+	size_t pm_size = num_core_pm_clks * sizeof(core_pm_clks[0]);
+
+	pd = devm_kzalloc(dev, sizeof(*pd) + pm_size, GFP_KERNEL);
+	if (!pd)
+		return -ENOMEM;
+
+	pd->np = np;
+	pd->num_core_pm_clks = num_core_pm_clks;
+	memcpy(pd->core_pm_clks, core_pm_clks, pm_size);
+
+	genpd = &pd->genpd;
+	genpd->name = np->name;
+	genpd->flags = GENPD_FLAG_PM_CLK;
+	pm_genpd_init(genpd, &simple_qos_governor, false);
+	genpd->attach_dev = cpg_mssr_attach_dev;
+	genpd->detach_dev = cpg_mssr_detach_dev;
+
+	of_genpd_add_provider_simple(np, genpd);
+	return 0;
+}
+#else
+static inline int cpg_mssr_add_clk_domain(struct device *dev,
+					  const unsigned int *core_pm_clks,
+					  unsigned int num_core_pm_clks) {}
+#endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */
+
+
+static const struct of_device_id cpg_mssr_match[] = {
+	{ /* sentinel */ }
+};
+
+static void cpg_mssr_del_clk_provider(void *data)
+{
+	of_clk_del_provider(data);
+}
+
+static int __init cpg_mssr_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	const struct cpg_mssr_info *info;
+	struct cpg_mssr_priv *priv;
+	unsigned int nclks, i;
+	struct resource *res;
+	struct clk **clks;
+	int error;
+
+	info = of_match_node(cpg_mssr_match, np)->data;
+	if (info->init) {
+		error = info->init(dev);
+		if (error)
+			return error;
+	}
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+	spin_lock_init(&priv->mstp_lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	nclks = info->num_total_core_clks + info->num_hw_mod_clks;
+	clks = devm_kmalloc_array(dev, nclks, sizeof(*clks), GFP_KERNEL);
+	if (!clks)
+		return -ENOMEM;
+
+	priv->clks = clks;
+	priv->num_core_clks = info->num_total_core_clks;
+	priv->num_mod_clks = info->num_hw_mod_clks;
+	priv->last_dt_core_clk = info->last_dt_core_clk;
+
+	for (i = 0; i < nclks; i++)
+		clks[i] = ERR_PTR(-ENOENT);
+
+	for (i = 0; i < info->num_core_clks; i++)
+		cpg_mssr_register_core_clk(&info->core_clks[i], info, priv);
+
+	for (i = 0; i < info->num_mod_clks; i++)
+		cpg_mssr_register_mod_clk(&info->mod_clks[i], info, priv);
+
+	error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
+	if (error)
+		return error;
+
+	devm_add_action(dev, cpg_mssr_del_clk_provider, np);
+
+	error = cpg_mssr_add_clk_domain(dev, info->core_pm_clks,
+					info->num_core_pm_clks);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static struct platform_driver cpg_mssr_driver = {
+	.driver		= {
+		.name	= "renesas-cpg-mssr",
+		.of_match_table = cpg_mssr_match,
+	},
+};
+
+static int __init cpg_mssr_init(void)
+{
+	return platform_driver_probe(&cpg_mssr_driver, cpg_mssr_probe);
+}
+
+subsys_initcall(cpg_mssr_init);
+
+MODULE_DESCRIPTION("Renesas CPG/MSSR Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.h b/drivers/clk/shmobile/renesas-cpg-mssr.h
new file mode 100644
index 0000000000000000..e6d24875b56f7755
--- /dev/null
+++ b/drivers/clk/shmobile/renesas-cpg-mssr.h
@@ -0,0 +1,131 @@
+/*
+ * Renesas Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#ifndef __CLK_RENESAS_CPG_MSSR_H__
+#define __CLK_RENESAS_CPG_MSSR_H__
+
+    /*
+     * Definitions of CPG Core Clocks
+     *
+     * These include:
+     *   - Clock outputs exported to DT
+     *   - External input clocks
+     *   - Internal CPG clocks
+     */
+
+struct cpg_core_clk {
+	/* Common */
+	const char *name;
+	unsigned int id;
+	unsigned int type;
+	/* Depending on type */
+	unsigned int parent;	/* Core Clocks only */
+	unsigned int div;
+	unsigned int mult;
+	unsigned int offset;
+};
+
+enum clk_types {
+	/* Generic */
+	CLK_TYPE_IN,		/* External Clock Input */
+	CLK_TYPE_FF,		/* Fixed Factor Clock */
+	CLK_TYPE_DIV6P1,	/* DIV6 Clock with 1 parent clock */
+
+	/* Custom definitions start here */
+	CLK_TYPE_CUSTOM,
+};
+
+#define DEF_TYPE(_name, _id, _type...)	\
+	{ .name = _name, .id = _id, .type = _type }
+#define DEF_BASE(_name, _id, _type, _parent...)	\
+	DEF_TYPE(_name, _id, _type, .parent = _parent)
+
+#define DEF_INPUT(_name, _id) \
+	DEF_TYPE(_name, _id, CLK_TYPE_IN)
+#define DEF_FIXED(_name, _id, _parent, _div, _mult)	\
+	DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult)
+#define DEF_DIV6P1(_name, _id, _parent, _offset)	\
+	DEF_BASE(_name, _id, CLK_TYPE_DIV6P1, _parent, .offset = _offset)
+
+
+    /*
+     * Definitions of Module Clocks
+     */
+
+struct mssr_mod_clk {
+	const char *name;
+	unsigned int id;
+	unsigned int parent;	/* Add MOD_CLK_BASE for Module Clocks */
+};
+
+/* Convert from sparse base-100 to packed index space */
+#define MOD_CLK_PACK(x)	((x) - ((x) / 100) * (100 - 32))
+
+#define MOD_CLK_ID(x)	(MOD_CLK_BASE + MOD_CLK_PACK(x))
+
+#define DEF_MOD(_name, _mod, _parent...)	\
+	{ .name = _name, .id = MOD_CLK_ID(_mod), .parent = _parent }
+
+
+struct device_node;
+
+    /**
+     * SoC-specific CPG/MSSR Description
+     *
+     * @core_clks: Array of Core Clock definitions
+     * @num_core_clks: Number of entries in core_clks[]
+     * @last_dt_core_clk: ID of the last Core Clock exported to DT
+     * @num_total_core_clks: Total number of Core Clocks (exported + internal)
+     *
+     * @mod_clks: Array of Module Clock definitions
+     * @num_mod_clks: Number of entries in mod_clks[]
+     * @num_hw_mod_clks: Number of Module Clocks supported by the hardware
+     *
+     * @crit_mod_clks: Array with Module Clock IDs of critical clocks that
+     *                 should not be disabled without a knowledgeable driver
+     * @num_crit_mod_clks: Number of entries in crit_mod_clks[]
+     *
+     * @core_pm_clks: Array with IDs of Core Clocks that are suitable for Power
+     *                Management, in addition to Module Clocks
+     * @num_core_pm_clks: Number of entries in core_pm_clks[]
+     *
+     * @init: Optional callback to perform SoC-specific initialization
+     * @cpg_clk_register: Optional callback to handle special Core Clock types
+     */
+
+struct cpg_mssr_info {
+	/* Core Clocks */
+	const struct cpg_core_clk *core_clks;
+	unsigned int num_core_clks;
+	unsigned int last_dt_core_clk;
+	unsigned int num_total_core_clks;
+
+	/* Module Clocks */
+	const struct mssr_mod_clk *mod_clks;
+	unsigned int num_mod_clks;
+	unsigned int num_hw_mod_clks;
+
+	/* Critical Module Clocks that should not be disabled */
+	const unsigned int *crit_mod_clks;
+	unsigned int num_crit_mod_clks;
+
+	/* Core Clocks suitable for PM, in addition to the Module Clocks */
+	const unsigned int *core_pm_clks;
+	unsigned int num_core_pm_clks;
+
+	/* Callbacks */
+	int (*init)(struct device *dev);
+	struct clk *(*cpg_clk_register)(struct device *dev,
+					const struct cpg_core_clk *core,
+					const struct cpg_mssr_info *info,
+					struct clk **clks, void __iomem *base);
+};
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v5 5/5] clk: shmobile: r8a7795: Add new CPG/MSSR driver
  2015-10-29 11:20 [PATCH v5 0/5] clk: shmobile: Add new CPG/MSSR driver Geert Uytterhoeven
                   ` (3 preceding siblings ...)
  2015-10-29 11:21 ` [PATCH v5 4/5] clk: shmobile: Add new CPG/MSSR driver core Geert Uytterhoeven
@ 2015-10-29 11:21 ` Geert Uytterhoeven
  2015-10-30  8:27   ` Geert Uytterhoeven
  4 siblings, 1 reply; 10+ messages in thread
From: Geert Uytterhoeven @ 2015-10-29 11:21 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Magnus Damm, Simon Horman,
	Laurent Pinchart
  Cc: linux-clk, linux-sh, linux-kernel, Geert Uytterhoeven

Add a new R-Car H3 Clock Pulse Generator / Module Standby and Software
Reset driver, using the new CPG/MSSR driver core.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v5:
  - Convert to real platform_driver,
  - Drop dependency on undocumented "renesas,modemr" property,
  - Move conversion from Module Clock numbers to IDs from run time (C
    code) to compile time (CPP macros for filling in tables),
  - Rename driver from clk-r8a7795-cpg-mssr to r8a7795-cpg-mssr,
  - Enter shmobile subdir if CONFIG_ARCH_RENESAS=y,
  - Clean up debugging code,
  - Drop RFC state,

v4:
  - New.
---
 drivers/clk/Makefile                    |   1 +
 drivers/clk/shmobile/Makefile           |   2 +
 drivers/clk/shmobile/r8a7795-cpg-mssr.c | 373 ++++++++++++++++++++++++++++++++
 drivers/clk/shmobile/renesas-cpg-mssr.c |   6 +
 drivers/clk/shmobile/renesas-cpg-mssr.h |   1 +
 5 files changed, 383 insertions(+)
 create mode 100644 drivers/clk/shmobile/r8a7795-cpg-mssr.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index c4cf075a2320f7ae..4ef2475aebd64d81 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_COMMON_CLK_QCOM)		+= qcom/
 obj-$(CONFIG_ARCH_ROCKCHIP)		+= rockchip/
 obj-$(CONFIG_COMMON_CLK_SAMSUNG)	+= samsung/
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)	+= shmobile/
+obj-$(CONFIG_ARCH_RENESAS)		+= shmobile/
 obj-$(CONFIG_ARCH_SIRF)			+= sirf/
 obj-$(CONFIG_ARCH_SOCFPGA)		+= socfpga/
 obj-$(CONFIG_PLAT_SPEAR)		+= spear/
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index 1eb947db6f5926a0..7e2579b303267d8b 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -8,4 +8,6 @@ obj-$(CONFIG_ARCH_R8A7790)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
 obj-$(CONFIG_ARCH_R8A7791)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
 obj-$(CONFIG_ARCH_R8A7793)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
 obj-$(CONFIG_ARCH_R8A7794)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7795)		+= renesas-cpg-mssr.o \
+					   r8a7795-cpg-mssr.o clk-div6.o
 obj-$(CONFIG_ARCH_SH73A0)		+= clk-sh73a0.o clk-mstp.o clk-div6.o
diff --git a/drivers/clk/shmobile/r8a7795-cpg-mssr.c b/drivers/clk/shmobile/r8a7795-cpg-mssr.c
new file mode 100644
index 0000000000000000..38760c9fa18cdf22
--- /dev/null
+++ b/drivers/clk/shmobile/r8a7795-cpg-mssr.c
@@ -0,0 +1,373 @@
+/*
+ * r8a7795 Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * Based on clk-rcar-gen3.c
+ *
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/bug.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+
+
+enum clk_ids {
+	/* Core Clock Outputs exported to DT */
+	LAST_DT_CORE_CLK = R8A7795_CLK_OSC,
+
+	/* External Input Clocks */
+	CLK_EXTAL,
+	CLK_EXTALR,
+
+	/* Internal Core Clocks */
+	CLK_MAIN,
+	CLK_PLL0,
+	CLK_PLL1,
+	CLK_PLL2,
+	CLK_PLL3,
+	CLK_PLL4,
+	CLK_PLL1_DIV2,
+	CLK_PLL1_DIV4,
+	CLK_S0,
+	CLK_S1,
+	CLK_S2,
+	CLK_S3,
+	CLK_SDSRC,
+	CLK_SSPSRC,
+
+	/* Module Clocks */
+	MOD_CLK_BASE
+};
+
+enum r8a7795_clk_types {
+	CLK_TYPE_GEN3_MAIN = CLK_TYPE_CUSTOM,
+	CLK_TYPE_GEN3_PLL0,
+	CLK_TYPE_GEN3_PLL1,
+	CLK_TYPE_GEN3_PLL2,
+	CLK_TYPE_GEN3_PLL3,
+	CLK_TYPE_GEN3_PLL4,
+};
+
+static const struct cpg_core_clk r8a7795_core_clks[] __initconst = {
+	/* External Clock Inputs */
+	DEF_INPUT("extal",  CLK_EXTAL),
+	DEF_INPUT("extalr", CLK_EXTALR),
+
+	/* Internal Core Clocks */
+	DEF_BASE(".main",       CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL),
+	DEF_BASE(".pll0",       CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN),
+	DEF_BASE(".pll1",       CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN),
+	DEF_BASE(".pll2",       CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN),
+	DEF_BASE(".pll3",       CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN),
+	DEF_BASE(".pll4",       CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN),
+
+	DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2,     CLK_PLL1,       2, 1),
+	DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4,     CLK_PLL1_DIV2,  2, 1),
+	DEF_FIXED(".s0",        CLK_S0,            CLK_PLL1_DIV2,  2, 1),
+	DEF_FIXED(".s1",        CLK_S1,            CLK_PLL1_DIV2,  3, 1),
+	DEF_FIXED(".s2",        CLK_S2,            CLK_PLL1_DIV2,  4, 1),
+	DEF_FIXED(".s3",        CLK_S3,            CLK_PLL1_DIV2,  6, 1),
+
+	/* Core Clock Outputs */
+	DEF_FIXED("ztr",        R8A7795_CLK_ZTR,   CLK_PLL1_DIV2,  6, 1),
+	DEF_FIXED("ztrd2",      R8A7795_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1),
+	DEF_FIXED("zt",         R8A7795_CLK_ZT,    CLK_PLL1_DIV2,  4, 1),
+	DEF_FIXED("zx",         R8A7795_CLK_ZX,    CLK_PLL1_DIV2,  2, 1),
+	DEF_FIXED("s0d1",       R8A7795_CLK_S0D1,  CLK_S0,         1, 1),
+	DEF_FIXED("s0d4",       R8A7795_CLK_S0D4,  CLK_S0,         4, 1),
+	DEF_FIXED("s1d1",       R8A7795_CLK_S1D1,  CLK_S1,         1, 1),
+	DEF_FIXED("s1d2",       R8A7795_CLK_S1D2,  CLK_S1,         2, 1),
+	DEF_FIXED("s1d4",       R8A7795_CLK_S1D4,  CLK_S1,         4, 1),
+	DEF_FIXED("s2d1",       R8A7795_CLK_S2D1,  CLK_S2,         1, 1),
+	DEF_FIXED("s2d2",       R8A7795_CLK_S2D2,  CLK_S2,         2, 1),
+	DEF_FIXED("s2d4",       R8A7795_CLK_S2D4,  CLK_S2,         4, 1),
+	DEF_FIXED("s3d1",       R8A7795_CLK_S3D1,  CLK_S3,         1, 1),
+	DEF_FIXED("s3d2",       R8A7795_CLK_S3D2,  CLK_S3,         2, 1),
+	DEF_FIXED("s3d4",       R8A7795_CLK_S3D4,  CLK_S3,         4, 1),
+	DEF_FIXED("cl",         R8A7795_CLK_CL,    CLK_PLL1_DIV2, 48, 1),
+	DEF_FIXED("cp",         R8A7795_CLK_CP,    CLK_EXTAL,      2, 1),
+
+	DEF_DIV6P1("mso",       R8A7795_CLK_MSO,   CLK_PLL1_DIV4, 0x014),
+	DEF_DIV6P1("hdmi",      R8A7795_CLK_HDMI,  CLK_PLL1_DIV2, 0x250),
+};
+
+static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = {
+	DEF_MOD("scif5",		 202,	R8A7795_CLK_S3D4),
+	DEF_MOD("scif4",		 203,	R8A7795_CLK_S3D4),
+	DEF_MOD("scif3",		 204,	R8A7795_CLK_S3D4),
+	DEF_MOD("scif1",		 206,	R8A7795_CLK_S3D4),
+	DEF_MOD("scif0",		 207,	R8A7795_CLK_S3D4),
+	DEF_MOD("msiof3",		 208,	R8A7795_CLK_MSO),
+	DEF_MOD("msiof2",		 209,	R8A7795_CLK_MSO),
+	DEF_MOD("msiof1",		 210,	R8A7795_CLK_MSO),
+	DEF_MOD("msiof0",		 211,	R8A7795_CLK_MSO),
+	DEF_MOD("sys-dmac2",		 217,	R8A7795_CLK_S3D1),
+	DEF_MOD("sys-dmac1",		 218,	R8A7795_CLK_S3D1),
+	DEF_MOD("sys-dmac0",		 219,	R8A7795_CLK_S3D1),
+	DEF_MOD("scif2",		 310,	R8A7795_CLK_S3D4),
+	DEF_MOD("intc-ap",		 408,	R8A7795_CLK_S3D1),
+	DEF_MOD("audmac0",		 502,	R8A7795_CLK_S3D4),
+	DEF_MOD("audmac1",		 501,	R8A7795_CLK_S3D4),
+	DEF_MOD("hscif4",		 516,	R8A7795_CLK_S3D1),
+	DEF_MOD("hscif3",		 517,	R8A7795_CLK_S3D1),
+	DEF_MOD("hscif2",		 518,	R8A7795_CLK_S3D1),
+	DEF_MOD("hscif1",		 519,	R8A7795_CLK_S3D1),
+	DEF_MOD("hscif0",		 520,	R8A7795_CLK_S3D1),
+	DEF_MOD("vspd3",		 620,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspd2",		 621,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspd1",		 622,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspd0",		 623,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspbc",		 624,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspbd",		 626,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspi2",		 629,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspi1",		 630,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspi0",		 631,	R8A7795_CLK_S2D1),
+	DEF_MOD("ehci2",		 701,	R8A7795_CLK_S3D4),
+	DEF_MOD("ehci1",		 702,	R8A7795_CLK_S3D4),
+	DEF_MOD("ehci0",		 703,	R8A7795_CLK_S3D4),
+	DEF_MOD("hsusb",		 704,	R8A7795_CLK_S3D4),
+	DEF_MOD("du3",			 721,	R8A7795_CLK_S2D1),
+	DEF_MOD("du2",			 722,	R8A7795_CLK_S2D1),
+	DEF_MOD("du1",			 723,	R8A7795_CLK_S2D1),
+	DEF_MOD("du0",			 724,	R8A7795_CLK_S2D1),
+	DEF_MOD("hdmi1",		 728,	R8A7795_CLK_HDMI),
+	DEF_MOD("hdmi0",		 729,	R8A7795_CLK_HDMI),
+	DEF_MOD("etheravb",		 812,	R8A7795_CLK_S3D2),
+	DEF_MOD("gpio7",		 905,	R8A7795_CLK_CP),
+	DEF_MOD("gpio6",		 906,	R8A7795_CLK_CP),
+	DEF_MOD("gpio5",		 907,	R8A7795_CLK_CP),
+	DEF_MOD("gpio4",		 908,	R8A7795_CLK_CP),
+	DEF_MOD("gpio3",		 909,	R8A7795_CLK_CP),
+	DEF_MOD("gpio2",		 910,	R8A7795_CLK_CP),
+	DEF_MOD("gpio1",		 911,	R8A7795_CLK_CP),
+	DEF_MOD("gpio0",		 912,	R8A7795_CLK_CP),
+	DEF_MOD("i2c6",			 918,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c5",			 919,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c4",			 927,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c3",			 928,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c2",			 929,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c1",			 930,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c0",			 931,	R8A7795_CLK_S3D2),
+	DEF_MOD("ssi-all",		1005,	R8A7795_CLK_S3D4),
+	DEF_MOD("ssi9",			1006,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi8",			1007,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi7",			1008,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi6",			1009,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi5",			1010,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi4",			1011,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi3",			1012,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi2",			1013,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi1",			1014,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi0",			1015,	MOD_CLK_ID(1005)),
+	DEF_MOD("scu-all",		1017,	R8A7795_CLK_S3D4),
+	DEF_MOD("scu-dvc1",		1018,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-dvc0",		1019,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-ctu1-mix1",	1020,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-ctu0-mix0",	1021,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src9",		1022,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src8",		1023,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src7",		1024,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src6",		1025,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src5",		1026,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src4",		1027,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src3",		1028,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src2",		1029,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src1",		1030,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src0",		1031,	MOD_CLK_ID(1017)),
+};
+
+static const unsigned int r8a7795_crit_mod_clks[] __initconst = {
+	MOD_CLK_ID(408),	/* INTC-AP (GIC) */
+};
+
+
+#define CPG_PLL0CR	0x00d8
+#define CPG_PLL2CR	0x002c
+
+/*
+ * CPG Clock Data
+ */
+
+/*
+ *   MD		EXTAL		PLL0	PLL1	PLL2	PLL3	PLL4
+ * 14 13 19 17	(MHz)
+ *-------------------------------------------------------------------
+ * 0  0  0  0	16.66 x 1	x180	x192	x144	x192	x144
+ * 0  0  0  1	16.66 x 1	x180	x192	x144	x128	x144
+ * 0  0  1  0	Prohibited setting
+ * 0  0  1  1	16.66 x 1	x180	x192	x144	x192	x144
+ * 0  1  0  0	20    x 1	x150	x156	x120	x156	x120
+ * 0  1  0  1	20    x 1	x150	x156	x120	x106	x120
+ * 0  1  1  0	Prohibited setting
+ * 0  1  1  1	20    x 1	x150	x156	x120	x156	x120
+ * 1  0  0  0	25    x 1	x120	x128	x96	x128	x96
+ * 1  0  0  1	25    x 1	x120	x128	x96	x84	x96
+ * 1  0  1  0	Prohibited setting
+ * 1  0  1  1	25    x 1	x120	x128	x96	x128	x96
+ * 1  1  0  0	33.33 / 2	x180	x192	x144	x192	x144
+ * 1  1  0  1	33.33 / 2	x180	x192	x144	x128	x144
+ * 1  1  1  0	Prohibited setting
+ * 1  1  1  1	33.33 / 2	x180	x192	x144	x192	x144
+ */
+#define CPG_PLL_CONFIG_INDEX(md)	((((md) & BIT(14)) >> 11) | \
+					 (((md) & BIT(13)) >> 11) | \
+					 (((md) & BIT(19)) >> 18) | \
+					 (((md) & BIT(17)) >> 17))
+
+struct cpg_pll_config {
+	unsigned int extal_div;
+	unsigned int pll1_mult;
+	unsigned int pll3_mult;
+	unsigned int pll4_mult;
+};
+
+static const struct cpg_pll_config cpg_pll_configs[16] __initconst = {
+/* EXTAL div	PLL1	PLL3	PLL4 */
+	{ 1,	192,	192,	144, },
+	{ 1,	192,	128,	144, },
+	{ 0,	0,	0,	0,   }, /* Prohibited setting */
+	{ 1,	192,	192,	144, },
+	{ 1,	156,	156,	120, },
+	{ 1,	156,	106,	120, },
+	{ 0,	0,	0,	0,   }, /* Prohibited setting */
+	{ 1,	156,	156,	120, },
+	{ 1,	128,	128,	96,  },
+	{ 1,	128,	84,	96,  },
+	{ 0,	0,	0,	0,   }, /* Prohibited setting */
+	{ 1,	128,	128,	96,  },
+	{ 2,	192,	192,	144, },
+	{ 2,	192,	128,	144, },
+	{ 0,	0,	0,	0,   }, /* Prohibited setting */
+	{ 2,	192,	192,	144, },
+};
+
+static const struct cpg_pll_config *cpg_pll_config __initdata;
+
+static
+struct clk * __init r8a7795_cpg_clk_register(struct device *dev,
+					     const struct cpg_core_clk *core,
+					     const struct cpg_mssr_info *info,
+					     struct clk **clks,
+					     void __iomem *base)
+{
+	const struct clk *parent;
+	unsigned int mult = 1;
+	unsigned int div = 1;
+	u32 value;
+
+	parent = clks[core->parent];
+	if (IS_ERR(parent))
+		return ERR_CAST(parent);
+
+	switch (core->type) {
+	case CLK_TYPE_GEN3_MAIN:
+		div = cpg_pll_config->extal_div;
+		break;
+
+	case CLK_TYPE_GEN3_PLL0:
+		/*
+		 * PLL0 is a configurable multiplier clock. Register it as a
+		 * fixed factor clock for now as there's no generic multiplier
+		 * clock implementation and we currently have no need to change
+		 * the multiplier value.
+		 */
+		value = readl(base + CPG_PLL0CR);
+		mult = ((value >> 24) & 0x3f) + 1;
+		break;
+
+	case CLK_TYPE_GEN3_PLL1:
+		mult = cpg_pll_config->pll1_mult;
+		break;
+
+	case CLK_TYPE_GEN3_PLL2:
+		/*
+		 * PLL2 is a configurable multiplier clock. Register it as a
+		 * fixed factor clock for now as there's no generic multiplier
+		 * clock implementation and we currently have no need to change
+		 * the multiplier value.
+		 */
+		value = readl(base + CPG_PLL2CR);
+		mult = ((value >> 24) & 0x3f) + 1;
+		break;
+
+	case CLK_TYPE_GEN3_PLL3:
+		mult = cpg_pll_config->pll3_mult;
+		break;
+
+	case CLK_TYPE_GEN3_PLL4:
+		mult = cpg_pll_config->pll4_mult;
+		break;
+
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
+	return clk_register_fixed_factor(NULL, core->name,
+					 __clk_get_name(parent), 0, mult, div);
+}
+
+/*
+ * Reset register definitions.
+ */
+#define MODEMR	0xe6160060
+
+static u32 rcar_gen3_read_mode_pins(void)
+{
+	void __iomem *modemr = ioremap_nocache(MODEMR, 4);
+	u32 mode;
+
+	BUG_ON(!modemr);
+	mode = ioread32(modemr);
+	iounmap(modemr);
+
+	return mode;
+}
+
+static int __init r8a7795_cpg_mssr_init(struct device *dev)
+{
+	u32 cpg_mode = rcar_gen3_read_mode_pins();
+
+	cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
+	if (!cpg_pll_config->extal_div) {
+		dev_err(dev, "Prohibited setting (cpg_mode=0x%x)\n", cpg_mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+const struct cpg_mssr_info r8a7795_cpg_mssr_info __initconst = {
+	/* Core Clocks */
+	.core_clks = r8a7795_core_clks,
+	.num_core_clks = ARRAY_SIZE(r8a7795_core_clks),
+	.last_dt_core_clk = LAST_DT_CORE_CLK,
+	.num_total_core_clks = MOD_CLK_BASE,
+
+	/* Module Clocks */
+	.mod_clks = r8a7795_mod_clks,
+	.num_mod_clks = ARRAY_SIZE(r8a7795_mod_clks),
+	.num_hw_mod_clks = 12 * 32,
+
+	/* Critical Module Clocks */
+	.crit_mod_clks = r8a7795_crit_mod_clks,
+	.num_crit_mod_clks = ARRAY_SIZE(r8a7795_crit_mod_clks),
+
+	/* Callbacks */
+	.init = r8a7795_cpg_mssr_init,
+	.cpg_clk_register = r8a7795_cpg_clk_register,
+};
diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.c b/drivers/clk/shmobile/renesas-cpg-mssr.c
index e4382ba4e1e31aca..a2cccc40fca783bf 100644
--- a/drivers/clk/shmobile/renesas-cpg-mssr.c
+++ b/drivers/clk/shmobile/renesas-cpg-mssr.c
@@ -498,6 +498,12 @@ static inline int cpg_mssr_add_clk_domain(struct device *dev,
 
 
 static const struct of_device_id cpg_mssr_match[] = {
+#ifdef CONFIG_ARCH_R8A7795
+	{
+		.compatible = "renesas,r8a7795-cpg-mssr",
+		.data = &r8a7795_cpg_mssr_info,
+	},
+#endif
 	{ /* sentinel */ }
 };
 
diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.h b/drivers/clk/shmobile/renesas-cpg-mssr.h
index e6d24875b56f7755..e09f03cbf086b1d3 100644
--- a/drivers/clk/shmobile/renesas-cpg-mssr.h
+++ b/drivers/clk/shmobile/renesas-cpg-mssr.h
@@ -128,4 +128,5 @@ struct cpg_mssr_info {
 					struct clk **clks, void __iomem *base);
 };
 
+extern const struct cpg_mssr_info r8a7795_cpg_mssr_info;
 #endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v5 5/5] clk: shmobile: r8a7795: Add new CPG/MSSR driver
  2015-10-29 11:21 ` [PATCH v5 5/5] clk: shmobile: r8a7795: Add new CPG/MSSR driver Geert Uytterhoeven
@ 2015-10-30  8:27   ` Geert Uytterhoeven
  0 siblings, 0 replies; 10+ messages in thread
From: Geert Uytterhoeven @ 2015-10-30  8:27 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Michael Turquette, Stephen Boyd, Magnus Damm, Simon Horman,
	Laurent Pinchart, linux-clk, Linux-sh list, linux-kernel

On Thu, Oct 29, 2015 at 12:21 PM, Geert Uytterhoeven
<geert+renesas@glider.be> wrote:
> Add a new R-Car H3 Clock Pulse Generator / Module Standby and Software
> Reset driver, using the new CPG/MSSR driver core.
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
> v5:

>   - Enter shmobile subdir if CONFIG_ARCH_RENESAS=y,

BTW, I kept wondering how I had forgotten that in v4.

Found it: "[PATCH v3 01/04] clk: shmobile: Get rid of
CONFIG_ARCH_SHMOBILE_MULTI" did ...

> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -67,6 +67,7 @@ obj-$(CONFIG_COMMON_CLK_QCOM)         += qcom/
>  obj-$(CONFIG_ARCH_ROCKCHIP)            += rockchip/
>  obj-$(CONFIG_COMMON_CLK_SAMSUNG)       += samsung/
>  obj-$(CONFIG_ARCH_SHMOBILE_MULTI)      += shmobile/

... s/CONFIG_ARCH_SHMOBILE_MULTI/CONFIG_ARCH_SHMOBILE/,
which is IMHO a better solution, but that disappeared in v4 and later.

> +obj-$(CONFIG_ARCH_RENESAS)             += shmobile/

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v5 2/5] clk: shmobile: div6: Make clock-output-names optional
  2015-10-29 11:21 ` [PATCH v5 2/5] clk: shmobile: div6: Make clock-output-names optional Geert Uytterhoeven
@ 2015-10-30 13:47   ` Laurent Pinchart
  2015-10-30 13:57     ` Geert Uytterhoeven
  0 siblings, 1 reply; 10+ messages in thread
From: Laurent Pinchart @ 2015-10-30 13:47 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Michael Turquette, Stephen Boyd, Magnus Damm, Simon Horman,
	linux-clk, linux-sh, linux-kernel

Hi Geert,

Thank you for the patch.

On Thursday 29 October 2015 12:21:01 Geert Uytterhoeven wrote:
> Renesas DIV6 clocks provide a single clock output.  Hence make the
> "clock-output-names" DT property optional instead of mandatory. In case
> the DT property is omitted the DT node name will be used.
> 
> Rename the variable "name" to "clk_name" to make the code more similar
> with fixed-factor-clock.c, and to avoid a conflict with a nested local
> variable while we're at it.
> 
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
> v5:
>   - Integrated in this series as a dependency.

The patch looks sane, by why is it a dependency ?

> ---
>  .../devicetree/bindings/clock/renesas,cpg-div6-clocks.txt   |  4 ++++
>  drivers/clk/shmobile/clk-div6.c                             | 13
>  +++----------
>  2 files changed, 7 insertions(+), 10 deletions(-)
> 
> diff --git
> a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
> b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt index
> 5ddb68418655d569..86008ad354cf4bbd 100644
> --- a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
> +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
> @@ -20,6 +20,10 @@ Required Properties:
>      clocks must be specified.  For clocks with multiple parents, invalid
>      settings must be specified as "<0>".
>    - #clock-cells: Must be 0
> +
> +
> +Optional Properties:
> +
>    - clock-output-names: The name of the clock as a free-form string
> 
> 
> diff --git a/drivers/clk/shmobile/clk-div6.c
> b/drivers/clk/shmobile/clk-div6.c index 036a692c72195db9..c89566a918290246
> 100644
> --- a/drivers/clk/shmobile/clk-div6.c
> +++ b/drivers/clk/shmobile/clk-div6.c
> @@ -178,10 +178,9 @@ static void __init cpg_div6_clock_init(struct
> device_node *np) const char **parent_names;
>  	struct clk_init_data init;
>  	struct div6_clock *clock;
> -	const char *name;
> +	const char *clk_name = np->name;
>  	struct clk *clk;
>  	unsigned int i;
> -	int ret;
> 
>  	clock = kzalloc(sizeof(*clock), GFP_KERNEL);
>  	if (!clock)
> @@ -215,13 +214,7 @@ static void __init cpg_div6_clock_init(struct
> device_node *np) clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) +
> 1;
> 
>  	/* Parse the DT properties. */
> -	ret = of_property_read_string(np, "clock-output-names", &name);
> -	if (ret < 0) {
> -		pr_err("%s: failed to get %s DIV6 clock output name\n",
> -		       __func__, np->name);
> -		goto error;
> -	}
> -
> +	of_property_read_string(np, "clock-output-names", &clk_name);
> 
>  	for (i = 0, valid_parents = 0; i < num_parents; i++) {
>  		const char *name = of_clk_get_parent_name(np, i);
> @@ -255,7 +248,7 @@ static void __init cpg_div6_clock_init(struct
> device_node *np) }
> 
>  	/* Register the clock. */
> -	init.name = name;
> +	init.name = clk_name;
>  	init.ops = &cpg_div6_clock_ops;
>  	init.flags = CLK_IS_BASIC;
>  	init.parent_names = parent_names;

-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v5 3/5] clk: shmobile: div6: Extract cpg_div6_register()
  2015-10-29 11:21 ` [PATCH v5 3/5] clk: shmobile: div6: Extract cpg_div6_register() Geert Uytterhoeven
@ 2015-10-30 13:54   ` Laurent Pinchart
  0 siblings, 0 replies; 10+ messages in thread
From: Laurent Pinchart @ 2015-10-30 13:54 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Michael Turquette, Stephen Boyd, Magnus Damm, Simon Horman,
	linux-clk, linux-sh, linux-kernel

Hi Geert,

Thank you for the patch.

On Thursday 29 October 2015 12:21:02 Geert Uytterhoeven wrote:
> Extract cpg_div6_register(), to allow registering div6 clocks from
> another clock driver.
> 
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
> v5:
>   - Document cpg_div6_register(),
>   - Free clock on clock->parents allocation failure,
>   - Add include guards to clk-div6.h,
>   - Drop RFC state,
> 
> v4:
>   - New.
> ---
>  drivers/clk/shmobile/clk-div6.c | 132 ++++++++++++++++++++++++------------
>  drivers/clk/shmobile/clk-div6.h |   7 +++
>  2 files changed, 94 insertions(+), 45 deletions(-)
>  create mode 100644 drivers/clk/shmobile/clk-div6.h
> 
> diff --git a/drivers/clk/shmobile/clk-div6.c
> b/drivers/clk/shmobile/clk-div6.c index c89566a918290246..5970d6a1506a9075
> 100644
> --- a/drivers/clk/shmobile/clk-div6.c
> +++ b/drivers/clk/shmobile/clk-div6.c
> @@ -18,6 +18,8 @@
>  #include <linux/of.h>
>  #include <linux/of_address.h>
> 
> +#include "clk-div6.h"
> +
>  #define CPG_DIV6_CKSTP		BIT(8)
>  #define CPG_DIV6_DIV(d)		((d) & 0x3f)
>  #define CPG_DIV6_DIV_MASK	0x3f
> @@ -172,60 +174,44 @@ static const struct clk_ops cpg_div6_clock_ops = {
>  	.set_rate = cpg_div6_clock_set_rate,
>  };
> 
> -static void __init cpg_div6_clock_init(struct device_node *np)
> +
> +/**
> + * cpg_div6_register - Register a DIV6 clock
> + * @name: Name of the DIV6 clock
> + * @num_parents: Number of parent clocks of the DIV6 clock (1, 4, or 8)
> + * @parent_names: Array containing the names of the parent clocks
> + * @reg: Mapped register used to control the DIV6 clock
> + */
> +struct clk * __init cpg_div6_register(const char *name,
> +				      unsigned int num_parents,
> +				      const char **parent_names,
> +				      void __iomem *reg)
>  {
> -	unsigned int num_parents, valid_parents;
> -	const char **parent_names;
> +	unsigned int valid_parents;
>  	struct clk_init_data init;
>  	struct div6_clock *clock;
> -	const char *clk_name = np->name;
>  	struct clk *clk;
>  	unsigned int i;
> 
>  	clock = kzalloc(sizeof(*clock), GFP_KERNEL);
>  	if (!clock)
> -		return;
> +		return ERR_PTR(-ENOMEM);
> 
> -	num_parents = of_clk_get_parent_count(np);
> -	if (num_parents < 1) {
> -		pr_err("%s: no parent found for %s DIV6 clock\n",
> -		       __func__, np->name);
> -		return;
> +	clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
> +				       GFP_KERNEL);
> +	if (!clock->parents) {
> +		clk = ERR_PTR(-ENOMEM);
> +		goto free_clock;
>  	}
> 
> -	clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
> -		GFP_KERNEL);
> -	parent_names = kmalloc_array(num_parents, sizeof(*parent_names),
> -				GFP_KERNEL);
> -	if (!parent_names)
> -		return;
> +	clock->reg = reg;
> 
> -	/* Remap the clock register and read the divisor. Disabling the
> -	 * clock overwrites the divisor, so we need to cache its value for the
> -	 * enable operation.
> +	/*
> +	 * Read the divisor. Disabling the clock overwrites the divisor, so we
> +	 * need to cache its value for the enable operation.
>  	 */
> -	clock->reg = of_iomap(np, 0);
> -	if (clock->reg == NULL) {
> -		pr_err("%s: failed to map %s DIV6 clock register\n",
> -		       __func__, np->name);
> -		goto error;
> -	}
> -
>  	clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1;
> 
> -	/* Parse the DT properties. */
> -	of_property_read_string(np, "clock-output-names", &clk_name);
> -
> -	for (i = 0, valid_parents = 0; i < num_parents; i++) {
> -		const char *name = of_clk_get_parent_name(np, i);
> -
> -		if (name) {
> -			parent_names[valid_parents] = name;
> -			clock->parents[valid_parents] = i;
> -			valid_parents++;
> -		}
> -	}
> -
>  	switch (num_parents) {
>  	case 1:
>  		/* fixed parent clock */
> @@ -243,12 +229,22 @@ static void __init cpg_div6_clock_init(struct
> device_node *np) break;
>  	default:
>  		pr_err("%s: invalid number of parents for DIV6 clock %s\n",
> -		       __func__, np->name);
> -		goto error;
> +		       __func__, name);
> +		clk = ERR_PTR(-EINVAL);
> +		goto free_parents;
> +	}
> +
> +	/* Filter out invalid parents */
> +	for (i = 0, valid_parents = 0; i < num_parents; i++) {
> +		if (parent_names[i]) {
> +			parent_names[valid_parents] = parent_names[i];
> +			clock->parents[valid_parents] = i;
> +			valid_parents++;
> +		}
>  	}
> 
>  	/* Register the clock. */
> -	init.name = clk_name;
> +	init.name = name;
>  	init.ops = &cpg_div6_clock_ops;
>  	init.flags = CLK_IS_BASIC;
>  	init.parent_names = parent_names;
> @@ -257,6 +253,53 @@ static void __init cpg_div6_clock_init(struct
> device_node *np) clock->hw.init = &init;
> 
>  	clk = clk_register(NULL, &clock->hw);
> +	if (IS_ERR(clk))
> +		goto free_parents;
> +
> +	return clk;
> +
> +free_parents:
> +	kfree(clock->parents);
> +free_clock:
> +	kfree(clock);
> +	return clk;
> +}
> +
> +static void __init cpg_div6_clock_init(struct device_node *np)
> +{
> +	unsigned int num_parents;
> +	const char **parent_names;
> +	const char *clk_name = np->name;
> +	void __iomem *reg;
> +	struct clk *clk;
> +	unsigned int i;
> +
> +	num_parents = of_clk_get_parent_count(np);
> +	if (num_parents < 1) {
> +		pr_err("%s: no parent found for %s DIV6 clock\n",
> +		       __func__, np->name);
> +		return;
> +	}
> +
> +	parent_names = kmalloc_array(num_parents, sizeof(*parent_names),
> +				GFP_KERNEL);
> +	if (!parent_names)
> +		return;
> +
> +	reg = of_iomap(np, 0);
> +	if (reg == NULL) {
> +		pr_err("%s: failed to map %s DIV6 clock register\n",
> +		       __func__, np->name);
> +		goto error;
> +	}
> +
> +	/* Parse the DT properties. */
> +	of_property_read_string(np, "clock-output-names", &clk_name);
> +
> +	for (i = 0; i < num_parents; i++)
> +		parent_names[i] = of_clk_get_parent_name(np, i);
> +
> +	clk = cpg_div6_register(clk_name, num_parents, parent_names, reg);
>  	if (IS_ERR(clk)) {
>  		pr_err("%s: failed to register %s DIV6 clock (%ld)\n",
>  		       __func__, np->name, PTR_ERR(clk));
> @@ -269,9 +312,8 @@ static void __init cpg_div6_clock_init(struct
> device_node *np) return;
> 
>  error:
> -	if (clock->reg)
> -		iounmap(clock->reg);
> +	if (reg)
> +		iounmap(reg);
>  	kfree(parent_names);
> -	kfree(clock);
>  }
>  CLK_OF_DECLARE(cpg_div6_clk, "renesas,cpg-div6-clock",
> cpg_div6_clock_init); diff --git a/drivers/clk/shmobile/clk-div6.h
> b/drivers/clk/shmobile/clk-div6.h new file mode 100644
> index 0000000000000000..9a85a95188daa813
> --- /dev/null
> +++ b/drivers/clk/shmobile/clk-div6.h
> @@ -0,0 +1,7 @@
> +#ifndef __SHMOBILE_CLK_DIV6_H__
> +#define __SHMOBILE_CLK_DIV6_H__
> +
> +struct clk *cpg_div6_register(const char *name, unsigned int num_parents,
> +			      const char **parent_names, void __iomem *reg);
> +
> +#endif

-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v5 2/5] clk: shmobile: div6: Make clock-output-names optional
  2015-10-30 13:47   ` Laurent Pinchart
@ 2015-10-30 13:57     ` Geert Uytterhoeven
  0 siblings, 0 replies; 10+ messages in thread
From: Geert Uytterhoeven @ 2015-10-30 13:57 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Geert Uytterhoeven, Michael Turquette, Stephen Boyd, Magnus Damm,
	Simon Horman, linux-clk, Linux-sh list, linux-kernel

On Fri, Oct 30, 2015 at 2:47 PM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> On Thursday 29 October 2015 12:21:01 Geert Uytterhoeven wrote:
>> Renesas DIV6 clocks provide a single clock output.  Hence make the
>> "clock-output-names" DT property optional instead of mandatory. In case
>> the DT property is omitted the DT node name will be used.
>>
>> Rename the variable "name" to "clk_name" to make the code more similar
>> with fixed-factor-clock.c, and to avoid a conflict with a nested local
>> variable while we're at it.
>>
>> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
>> ---
>> v5:
>>   - Integrated in this series as a dependency.
>
> The patch looks sane, by why is it a dependency ?

Sorry, the cover letter is clearer about this: "contextual dependency".

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2015-10-30 13:57 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-29 11:20 [PATCH v5 0/5] clk: shmobile: Add new CPG/MSSR driver Geert Uytterhoeven
2015-10-29 11:21 ` [PATCH v5 1/5] clk: shmobile: Rework CONFIG_ARCH_SHMOBILE_MULTI Geert Uytterhoeven
2015-10-29 11:21 ` [PATCH v5 2/5] clk: shmobile: div6: Make clock-output-names optional Geert Uytterhoeven
2015-10-30 13:47   ` Laurent Pinchart
2015-10-30 13:57     ` Geert Uytterhoeven
2015-10-29 11:21 ` [PATCH v5 3/5] clk: shmobile: div6: Extract cpg_div6_register() Geert Uytterhoeven
2015-10-30 13:54   ` Laurent Pinchart
2015-10-29 11:21 ` [PATCH v5 4/5] clk: shmobile: Add new CPG/MSSR driver core Geert Uytterhoeven
2015-10-29 11:21 ` [PATCH v5 5/5] clk: shmobile: r8a7795: Add new CPG/MSSR driver Geert Uytterhoeven
2015-10-30  8:27   ` Geert Uytterhoeven

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).