diff mbox series

clk: renesas: cpg-mssr: Add R7S9210 support

Message ID 20180821032020.81254-1-chris.brandt@renesas.com (mailing list archive)
State Superseded
Delegated to: Geert Uytterhoeven
Headers show
Series clk: renesas: cpg-mssr: Add R7S9210 support | expand

Commit Message

Chris Brandt Aug. 21, 2018, 3:20 a.m. UTC
Add support for the R7S9210 (RZ/A2) Clock Pulse Generator and Module
Standby.

The Module Standby HW in the RZ/A series is very close to R-Car HW, except
for how the registers are laid out.
The MSTP registers are only 8-bits wide, there is no status registers
(MSTPST), and the register offsets are a little different. Since the RZ/A
hardware manuals refer to these registers as the Standby Control Registers,
we'll use that name to distinguish the RZ/A type for the R-Car type.

Signed-off-by: Chris Brandt <chris.brandt@renesas.com>
---
 .../devicetree/bindings/clock/renesas,cpg-mssr.txt |   3 +-
 drivers/clk/renesas/Kconfig                        |   5 +
 drivers/clk/renesas/Makefile                       |   1 +
 drivers/clk/renesas/r7s9210-cpg-mssr.c             | 189 +++++++++++++++++++++
 drivers/clk/renesas/renesas-cpg-mssr.c             |  66 +++++--
 drivers/clk/renesas/renesas-cpg-mssr.h             |   6 +
 include/dt-bindings/clock/r7s9210-cpg-mssr.h       |  21 +++
 7 files changed, 280 insertions(+), 11 deletions(-)
 create mode 100644 drivers/clk/renesas/r7s9210-cpg-mssr.c
 create mode 100644 include/dt-bindings/clock/r7s9210-cpg-mssr.h

Comments

Geert Uytterhoeven Aug. 27, 2018, 4:37 p.m. UTC | #1
Hi Chris,

On Tue, Aug 21, 2018 at 5:20 AM Chris Brandt <chris.brandt@renesas.com> wrote:
> Add support for the R7S9210 (RZ/A2) Clock Pulse Generator and Module
> Standby.

Thanks for your patch, looks mostly OK to me!

> The Module Standby HW in the RZ/A series is very close to R-Car HW, except
> for how the registers are laid out.
> The MSTP registers are only 8-bits wide, there is no status registers
> (MSTPST), and the register offsets are a little different. Since the RZ/A
> hardware manuals refer to these registers as the Standby Control Registers,
> we'll use that name to distinguish the RZ/A type for the R-Car type.

And it doesn't have the reset control registers, so you should not register
the reset controller (or register a different one, when you add the support).

> Signed-off-by: Chris Brandt <chris.brandt@renesas.com>

Given the differences, and the limited amount of RAM on RZ/A2, I think you
would be better off with a separate renesas-cpg-stbcr driver, and an
r7s9210-cpg-stbcr counterpart.

That means:

>  .../devicetree/bindings/clock/renesas,cpg-mssr.txt |   3 +-

1. A separate binding document.

>  drivers/clk/renesas/Kconfig                        |   5 +
>  drivers/clk/renesas/Makefile                       |   1 +
>  drivers/clk/renesas/r7s9210-cpg-mssr.c             | 189 +++++++++++++++++++++
>  drivers/clk/renesas/renesas-cpg-mssr.c             |  66 +++++--
>  drivers/clk/renesas/renesas-cpg-mssr.h             |   6 +
>  include/dt-bindings/clock/r7s9210-cpg-mssr.h       |  21 +++
>  7 files changed, 280 insertions(+), 11 deletions(-)
>  create mode 100644 drivers/clk/renesas/r7s9210-cpg-mssr.c
>  create mode 100644 include/dt-bindings/clock/r7s9210-cpg-mssr.h
>
> diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
> index db542abadb75..66ca973edd77 100644
> --- a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
> +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
> @@ -13,6 +13,7 @@ They provide the following functionalities:
>
>  Required Properties:
>    - compatible: Must be one of:
> +      - "renesas,r7s9210-cpg-mssr" for the r7s9210 SoC (RZ/A2)
>        - "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M)
>        - "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E)
>        - "renesas,r8a77470-cpg-mssr" for the r8a77470 SoC (RZ/G1C)
> @@ -37,7 +38,7 @@ Required Properties:
>    - clock-names: List of external parent clock names. Valid names are:
>        - "extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7792,
>                  r8a7793, r8a7794, r8a7795, r8a7796, r8a77965, r8a77970,
> -                r8a77980, r8a77990, r8a77995)
> +                r8a77980, r8a77990, r8a77995, r7s9210)
>        - "extalr" (r8a7795, r8a7796, r8a77965, r8a77970, r8a77980)
>        - "usb_extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7793,
>                      r8a7794)
> diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
> index 9022bbe1297e..d8ccdaba5103 100644
> --- a/drivers/clk/renesas/Kconfig
> +++ b/drivers/clk/renesas/Kconfig

> @@ -45,6 +46,10 @@ config CLK_RZA1
>         bool "RZ/A1H clock support" if COMPILE_TEST
>         select CLK_RENESAS_CPG_MSTP
>
> +config CLK_R7S9210
> +       bool "RZ/A2 clock support" if COMPILE_TEST
> +       select CLK_RENESAS_CPG_MSSR

2. a separate CLK_RENESAS_CPG_STBCR symbol.

> --- /dev/null
> +++ b/drivers/clk/renesas/r7s9210-cpg-mssr.c

3. Almost all of this can stay the same, modulo some renames.

> +static const struct mssr_mod_clk r7s9210_mod_clks[] __initconst = {
> +       DEF_MOD("ostm0",         306,   R7S9210_CLK_P1C),

4. Your module clocks can use e.g. "36" instead of "306" (also in the DTS),
   matching the datasheet.

> --- /dev/null
> +++ b/include/dt-bindings/clock/r7s9210-cpg-mssr.h

5. Almost all of this can stay the same, modulo some renames.

What do you think?

Gr{oetje,eeting}s,

                        Geert
Chris Brandt Aug. 27, 2018, 4:58 p.m. UTC | #2
Hi Geert,

Thank you for having a look at this.

On Monday, August 27, 2018 1, Geert Uytterhoeven wrote:
> Given the differences, and the limited amount of RAM on RZ/A2, I think you
> would be better off with a separate renesas-cpg-stbcr driver, and an
> r7s9210-cpg-stbcr counterpart.

If you really think there will be a lot of wasted RAM, then I will look 
into it.

So are you saying I should first copy/rename renesas-cpg-mssr.c to 
renesas-cpg-stbr.c and then start hacking away at it?


> 4. Your module clocks can use e.g. "36" instead of "306" (also in the DTS),
>    matching the datasheet.

Yes, that would be much nicer!


Just FYI,
I like this new driver method, but the one downfall is that I have to go
back and change my timer driver (renesas-ostm.c). The current OSTM 
driver uses TIMER_OF_DECLARE(). But when you use TIMER_OF_DECLARE, your 
timer driver gets probed VERY early in boot, before subsys_initcall, so none
of your clocks are registered yet and the probe fails.


Chris


> 
> That means:
> 
> >  .../devicetree/bindings/clock/renesas,cpg-mssr.txt |   3 +-
> 
> 1. A separate binding document.
> 
> >  drivers/clk/renesas/Kconfig                        |   5 +
> >  drivers/clk/renesas/Makefile                       |   1 +
> >  drivers/clk/renesas/r7s9210-cpg-mssr.c             | 189
> +++++++++++++++++++++
> >  drivers/clk/renesas/renesas-cpg-mssr.c             |  66 +++++--
> >  drivers/clk/renesas/renesas-cpg-mssr.h             |   6 +
> >  include/dt-bindings/clock/r7s9210-cpg-mssr.h       |  21 +++
> >  7 files changed, 280 insertions(+), 11 deletions(-)
> >  create mode 100644 drivers/clk/renesas/r7s9210-cpg-mssr.c
> >  create mode 100644 include/dt-bindings/clock/r7s9210-cpg-mssr.h
> >
> > diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-
> mssr.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
> > index db542abadb75..66ca973edd77 100644
> > --- a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
> > +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
> > @@ -13,6 +13,7 @@ They provide the following functionalities:
> >
> >  Required Properties:
> >    - compatible: Must be one of:
> > +      - "renesas,r7s9210-cpg-mssr" for the r7s9210 SoC (RZ/A2)
> >        - "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M)
> >        - "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E)
> >        - "renesas,r8a77470-cpg-mssr" for the r8a77470 SoC (RZ/G1C)
> > @@ -37,7 +38,7 @@ Required Properties:
> >    - clock-names: List of external parent clock names. Valid names are:
> >        - "extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7792,
> >                  r8a7793, r8a7794, r8a7795, r8a7796, r8a77965, r8a77970,
> > -                r8a77980, r8a77990, r8a77995)
> > +                r8a77980, r8a77990, r8a77995, r7s9210)
> >        - "extalr" (r8a7795, r8a7796, r8a77965, r8a77970, r8a77980)
> >        - "usb_extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791,
> r8a7793,
> >                      r8a7794)
> > diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
> > index 9022bbe1297e..d8ccdaba5103 100644
> > --- a/drivers/clk/renesas/Kconfig
> > +++ b/drivers/clk/renesas/Kconfig
> 
> > @@ -45,6 +46,10 @@ config CLK_RZA1
> >         bool "RZ/A1H clock support" if COMPILE_TEST
> >         select CLK_RENESAS_CPG_MSTP
> >
> > +config CLK_R7S9210
> > +       bool "RZ/A2 clock support" if COMPILE_TEST
> > +       select CLK_RENESAS_CPG_MSSR
> 
> 2. a separate CLK_RENESAS_CPG_STBCR symbol.
> 
> > --- /dev/null
> > +++ b/drivers/clk/renesas/r7s9210-cpg-mssr.c
> 
> 3. Almost all of this can stay the same, modulo some renames.
> 
> > +static const struct mssr_mod_clk r7s9210_mod_clks[] __initconst = {
> > +       DEF_MOD("ostm0",         306,   R7S9210_CLK_P1C),
> 
> 4. Your module clocks can use e.g. "36" instead of "306" (also in the DTS),
>    matching the datasheet.
> 
> > --- /dev/null
> > +++ b/include/dt-bindings/clock/r7s9210-cpg-mssr.h
> 
> 5. Almost all of this can stay the same, modulo some renames.
> 
> What do you think?
> 
> 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
Geert Uytterhoeven Aug. 27, 2018, 6:31 p.m. UTC | #3
Hi Chris,

On Mon, Aug 27, 2018 at 6:59 PM Chris Brandt <Chris.Brandt@renesas.com> wrote:
> On Monday, August 27, 2018 1, Geert Uytterhoeven wrote:
> > Given the differences, and the limited amount of RAM on RZ/A2, I think you
> > would be better off with a separate renesas-cpg-stbcr driver, and an
> > r7s9210-cpg-stbcr counterpart.
>
> If you really think there will be a lot of wasted RAM, then I will look
> into it.
>
> So are you saying I should first copy/rename renesas-cpg-mssr.c to
> renesas-cpg-stbr.c and then start hacking away at it?

Exactly.

It's debatable: from one side, it's good to reuse code. From the other other,
to much conditional logic complicates everything.

The reset controller part will be different anyway.
But the clock domain part and most of the core/module logic is the same.
Perhaps some common code can be spun off?

> > 4. Your module clocks can use e.g. "36" instead of "306" (also in the DTS),
> >    matching the datasheet.
>
> Yes, that would be much nicer!

At least in DTS and the module clock table, you can get that with cpg-mssr, too,
if you use a different macro.

> Just FYI,
> I like this new driver method, but the one downfall is that I have to go
> back and change my timer driver (renesas-ostm.c). The current OSTM
> driver uses TIMER_OF_DECLARE(). But when you use TIMER_OF_DECLARE, your
> timer driver gets probed VERY early in boot, before subsys_initcall, so none
> of your clocks are registered yet and the probe fails.

IC. When CPG/MSSR was introduced, we had ordering issues on R-Car, too.

Gr{oetje,eeting}s,

                        Geert
Chris Brandt Aug. 27, 2018, 10:13 p.m. UTC | #4
Hi Geert,

On Monday, August 27, 2018 1, Geert Uytterhoeven wrote:
> Given the differences, and the limited amount of RAM on RZ/A2, I think you
> would be better off with a separate renesas-cpg-stbcr driver, and an
> r7s9210-cpg-stbcr counterpart.

I went and measured the amount of RAM being used by the driver 
(allocated during boot when the driver is loaded and probed), and it's only 8KB. 
That's not really much compared to other drivers and subsystems being 
loaded in the system. Of course RZ/A tries to be RAM sensitive...but 8KB 
for a clock driver is not my biggest concern.

So with that said, I could add in a driver option to not register the 
reset controller. And, also make a macro so users can specify "36" instead
of "306" in the DT.
And then, I no longer have to worry about duplicate code (2 drivers do 
almost the same thing).

What do you think?
Were you expecting the driver to allocate more than 8K of RAM on boot?

Thanks,
Chris
Geert Uytterhoeven Aug. 28, 2018, 7:10 a.m. UTC | #5
Hi Chris,

On Tue, Aug 28, 2018 at 12:13 AM Chris Brandt <Chris.Brandt@renesas.com> wrote:
> On Monday, August 27, 2018 1, Geert Uytterhoeven wrote:
> > Given the differences, and the limited amount of RAM on RZ/A2, I think you
> > would be better off with a separate renesas-cpg-stbcr driver, and an
> > r7s9210-cpg-stbcr counterpart.
>
> I went and measured the amount of RAM being used by the driver
> (allocated during boot when the driver is loaded and probed), and it's only 8KB.
> That's not really much compared to other drivers and subsystems being
> loaded in the system. Of course RZ/A tries to be RAM sensitive...but 8KB
> for a clock driver is not my biggest concern.
>
> So with that said, I could add in a driver option to not register the
> reset controller. And, also make a macro so users can specify "36" instead
> of "306" in the DT.
> And then, I no longer have to worry about duplicate code (2 drivers do
> almost the same thing).
>
> What do you think?

OK for me.

Changing the print format in the debug prints is probably too much work,
but those matter less than the clock numbers in the DTS.

> Were you expecting the driver to allocate more than 8K of RAM on boot?

I was thinking mainly about code size. But you're right, (a) you use XIP
(with plenty of FLASH?), and (b) RAM size should be similar for a combined
and a separate driver.

Gr{oetje,eeting}s,

                        Geert
Chris Brandt Aug. 28, 2018, 5:17 p.m. UTC | #6
Hi Geert,

Since my config for RZ/A2 does not set CONFIG_RESET_CONTROLLER, none of 
the reset code is built and cpg_mssr_reset_controller_register() just 
ends up being an empty function.

So basically my only change at this point is to make DTS and the module 
clock table use "36" instead of "306".

Are you OK with the idea of adding a macro ("STBCR_ID") in 
include/dt-bindings/clock/renesas-cpg-mssr.h?


DTS:
--------------------
	ostm0: timer@e803b000 {
		compatible = "renesas,r7s9210-ostm", "renesas,ostm";
		reg = <0xe803b000 0x30>;
		interrupts = <GIC_SPI 56 IRQ_TYPE_EDGE_RISING>;
		clocks = <&cpg CPG_MOD STBCR_ID(36)>;
		clock-names = "ostm0";
		power-domains = <&cpg>;
		status = "disabled";
	};



r7s9210-cpg-mssr.c:
--------------------
static const struct mssr_mod_clk r7s9210_mod_clks[] __initconst = {
	DEF_MOD("ostm0",	STBCR_ID(36),	R7S9210_CLK_P1C),
	DEF_MOD("ostm1",	STBCR_ID(35),	R7S9210_CLK_P1C),
	DEF_MOD("ostm2",	STBCR_ID(34),	R7S9210_CLK_P1C),


Thanks,
Chris
Geert Uytterhoeven Aug. 28, 2018, 5:35 p.m. UTC | #7
Hi Chris,

On Tue, Aug 28, 2018 at 7:18 PM Chris Brandt <Chris.Brandt@renesas.com> wrote:
> Since my config for RZ/A2 does not set CONFIG_RESET_CONTROLLER, none of
> the reset code is built and cpg_mssr_reset_controller_register() just
> ends up being an empty function.

Let's try shmobile_defconfig instead :-)

Seriously, you do have to prevent registering the reset controller when
running on RZ/A2 (based on cpg_mssr_info.stbyctrl or some other indicator).

> So basically my only change at this point is to make DTS and the module
> clock table use "36" instead of "306".
>
> Are you OK with the idea of adding a macro ("STBCR_ID") in
> include/dt-bindings/clock/renesas-cpg-mssr.h?
>
>
> DTS:
> --------------------
>         ostm0: timer@e803b000 {
>                 compatible = "renesas,r7s9210-ostm", "renesas,ostm";
>                 reg = <0xe803b000 0x30>;
>                 interrupts = <GIC_SPI 56 IRQ_TYPE_EDGE_RISING>;
>                 clocks = <&cpg CPG_MOD STBCR_ID(36)>;
>                 clock-names = "ostm0";
>                 power-domains = <&cpg>;
>                 status = "disabled";
>         };

When running on RZ/A2, I'd use a different pack function in
cpg_mssr_clk_src_twocell_get() instead, so you can just write:

    clock = <&cpg CPG_MOD 36>;

> r7s9210-cpg-mssr.c:
> --------------------
> static const struct mssr_mod_clk r7s9210_mod_clks[] __initconst = {
>         DEF_MOD("ostm0",        STBCR_ID(36),   R7S9210_CLK_P1C),
>         DEF_MOD("ostm1",        STBCR_ID(35),   R7S9210_CLK_P1C),
>         DEF_MOD("ostm2",        STBCR_ID(34),   R7S9210_CLK_P1C),

... and a different DEF_MOD() macro here, so you can just write:

    DEF_MOD("ostm0",        36,   R7S9210_CLK_P1C),

Gr{oetje,eeting}s,

                        Geert
Chris Brandt Aug. 28, 2018, 6:04 p.m. UTC | #8
Hi Geert,

On Tuesday, August 28, 2018, Geert Uytterhoeven wrote:
> Seriously, you do have to prevent registering the reset controller when
> running on RZ/A2 (based on cpg_mssr_info.stbyctrl or some other indicator).

OK. Since the reset controller registration is the last thing done 
cpg_mssr_probe, I'll just return.

+	if (info->stbyctrl)
+		return 0;
+
	error = cpg_mssr_reset_controller_register(priv);
	if (error)
		return error;

	return 0;
}


> When running on RZ/A2, I'd use a different pack function in
> cpg_mssr_clk_src_twocell_get() instead, so you can just write:
> 
>     clock = <&cpg CPG_MOD 36>;
> 
> > r7s9210-cpg-mssr.c:
> > --------------------
> > static const struct mssr_mod_clk r7s9210_mod_clks[] __initconst = {
> >         DEF_MOD("ostm0",        STBCR_ID(36),   R7S9210_CLK_P1C),
> >         DEF_MOD("ostm1",        STBCR_ID(35),   R7S9210_CLK_P1C),
> >         DEF_MOD("ostm2",        STBCR_ID(34),   R7S9210_CLK_P1C),
> 
> ... and a different DEF_MOD() macro here, so you can just write:
> 
>     DEF_MOD("ostm0",        36,   R7S9210_CLK_P1C),

OK. I will do that instead.


Thank you,
Chris
diff mbox series

Patch

diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
index db542abadb75..66ca973edd77 100644
--- a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
+++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
@@ -13,6 +13,7 @@  They provide the following functionalities:
 
 Required Properties:
   - compatible: Must be one of:
+      - "renesas,r7s9210-cpg-mssr" for the r7s9210 SoC (RZ/A2)
       - "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M)
       - "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E)
       - "renesas,r8a77470-cpg-mssr" for the r8a77470 SoC (RZ/G1C)
@@ -37,7 +38,7 @@  Required Properties:
   - clock-names: List of external parent clock names. Valid names are:
       - "extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7792,
 		 r8a7793, r8a7794, r8a7795, r8a7796, r8a77965, r8a77970,
-		 r8a77980, r8a77990, r8a77995)
+		 r8a77980, r8a77990, r8a77995, r7s9210)
       - "extalr" (r8a7795, r8a7796, r8a77965, r8a77970, r8a77980)
       - "usb_extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7793,
 		     r8a7794)
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index 9022bbe1297e..d8ccdaba5103 100644
--- a/drivers/clk/renesas/Kconfig
+++ b/drivers/clk/renesas/Kconfig
@@ -3,6 +3,7 @@  config CLK_RENESAS
 	default y if ARCH_RENESAS
 	select CLK_EMEV2 if ARCH_EMEV2
 	select CLK_RZA1 if ARCH_R7S72100
+	select CLK_R7S9210 if ARCH_R7S9210
 	select CLK_R8A73A4 if ARCH_R8A73A4
 	select CLK_R8A7740 if ARCH_R8A7740
 	select CLK_R8A7743 if ARCH_R8A7743
@@ -45,6 +46,10 @@  config CLK_RZA1
 	bool "RZ/A1H clock support" if COMPILE_TEST
 	select CLK_RENESAS_CPG_MSTP
 
+config CLK_R7S9210
+	bool "RZ/A2 clock support" if COMPILE_TEST
+	select CLK_RENESAS_CPG_MSSR
+
 config CLK_R8A73A4
 	bool "R-Mobile APE6 clock support" if COMPILE_TEST
 	select CLK_RENESAS_CPG_MSTP
diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile
index e4aa3d6143d2..d95bfd758a14 100644
--- a/drivers/clk/renesas/Makefile
+++ b/drivers/clk/renesas/Makefile
@@ -2,6 +2,7 @@ 
 # SoC
 obj-$(CONFIG_CLK_EMEV2)			+= clk-emev2.o
 obj-$(CONFIG_CLK_RZA1)			+= clk-rz.o
+obj-$(CONFIG_CLK_R7S9210)		+= r7s9210-cpg-mssr.o
 obj-$(CONFIG_CLK_R8A73A4)		+= clk-r8a73a4.o
 obj-$(CONFIG_CLK_R8A7740)		+= clk-r8a7740.o
 obj-$(CONFIG_CLK_R8A7743)		+= r8a7743-cpg-mssr.o
diff --git a/drivers/clk/renesas/r7s9210-cpg-mssr.c b/drivers/clk/renesas/r7s9210-cpg-mssr.c
new file mode 100644
index 000000000000..8b4bdd0ec06a
--- /dev/null
+++ b/drivers/clk/renesas/r7s9210-cpg-mssr.c
@@ -0,0 +1,189 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * r7s9210 Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Based on r8a7795-cpg-mssr.c
+ *
+ * Copyright (C) 2018 Chris Brandt
+ * Copyright (C) 2018 Renesas Electronics Corp.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <dt-bindings/clock/r7s9210-cpg-mssr.h>
+#include "renesas-cpg-mssr.h"
+
+#define CPG_FRQCR	0x00
+#define CPG_CKIOSEL	0xF0
+#define CPG_SCLKSEL	0xF4
+
+#define PORTL_PIDR	0xFCFFE074
+static u8 cpg_mode;
+
+/* Internal Clock ratio table */
+static const unsigned int ratio_tab[5][5] = {
+			/* I,  G,  B, P1, P0 */
+			{  2,  4,  8, 16, 32 },	/* FRQCR = 0x012 */
+			{  4,  4,  8, 16, 32 },	/* FRQCR = 0x112 */
+			{  8,  4,  8, 16, 32 },	/* FRQCR = 0x212 */
+			{ 16,  8, 16, 16, 32 },	/* FRQCR = 0x322 */
+			{ 16, 16, 32, 32, 32 },	/* FRQCR = 0x333 */
+			};
+
+enum rz_clk_types {
+	CLK_TYPE_RZA_MAIN = CLK_TYPE_CUSTOM,
+	CLK_TYPE_RZA_PLL,
+};
+
+enum clk_ids {
+	/* Core Clock Outputs exported to DT */
+	LAST_DT_CORE_CLK = R7S9210_CLK_P0,
+
+	/* External Input Clocks */
+	CLK_EXTAL,
+
+	/* Internal Core Clocks */
+	CLK_MAIN,
+	CLK_PLL,
+	CLK_I,
+	CLK_G,
+	CLK_B,
+	CLK_P1,
+	CLK_P1C,
+	CLK_P0,
+
+	/* Module Clocks */
+	MOD_CLK_BASE
+};
+
+static struct cpg_core_clk r7s9210_core_clks[] = {
+	/* External Clock Inputs */
+	DEF_INPUT("extal",     CLK_EXTAL),
+
+	/* Internal Core Clocks */
+	DEF_BASE(".main",       CLK_MAIN, CLK_TYPE_RZA_MAIN, CLK_EXTAL),
+	DEF_BASE(".pll",       CLK_PLL, CLK_TYPE_RZA_PLL, CLK_MAIN),
+
+	/* Core Clock Outputs */
+	DEF_FIXED("i",      R7S9210_CLK_I,     CLK_PLL,          2, 1),
+	DEF_FIXED("g",      R7S9210_CLK_G,     CLK_PLL,          4, 1),
+	DEF_FIXED("b",      R7S9210_CLK_B,     CLK_PLL,          8, 1),
+	DEF_FIXED("p1",     R7S9210_CLK_P1,    CLK_PLL,         16, 1),
+	DEF_FIXED("p1c",    R7S9210_CLK_P1C,   CLK_PLL,         16, 1),
+	DEF_FIXED("p0",     R7S9210_CLK_P0,    CLK_PLL,         32, 1),
+};
+
+static const struct mssr_mod_clk r7s9210_mod_clks[] __initconst = {
+	DEF_MOD("ostm0",	 306,	R7S9210_CLK_P1C),
+	DEF_MOD("ostm1",	 305,	R7S9210_CLK_P1C),
+	DEF_MOD("ostm2",	 304,	R7S9210_CLK_P1C),
+
+	DEF_MOD("scif0",	 407,	R7S9210_CLK_P1C),
+	DEF_MOD("scif1",	 406,	R7S9210_CLK_P1C),
+	DEF_MOD("scif2",	 405,	R7S9210_CLK_P1C),
+	DEF_MOD("scif3",	 404,	R7S9210_CLK_P1C),
+	DEF_MOD("scif4",	 403,	R7S9210_CLK_P1C),
+
+	DEF_MOD("i2c0",		 807,	R7S9210_CLK_P1),
+	DEF_MOD("i2c1",		 806,	R7S9210_CLK_P1),
+	DEF_MOD("i2c2",		 805,	R7S9210_CLK_P1),
+	DEF_MOD("i2c3",		 804,	R7S9210_CLK_P1),
+};
+
+struct clk * __init rza2_cpg_clk_register(struct device *dev,
+	const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
+	struct clk **clks, void __iomem *base,
+	struct raw_notifier_head *notifiers)
+{
+	const struct clk *parent;
+	unsigned int mult = 1;
+	unsigned int div = 1;
+	u16 frqcr;
+	u8 index;
+	int i;
+
+	parent = clks[core->parent];
+	if (IS_ERR(parent))
+		return ERR_CAST(parent);
+
+	switch (core->id) {
+	case CLK_MAIN:
+		break;
+
+	case CLK_PLL:
+		if (cpg_mode)
+			mult = 44;	/* Divider 1 is 1/2 */
+		else
+			mult = 88;	/* Divider 1 is 1 */
+		break;
+
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Adjust the dividers based on the current FRQCR setting */
+	if (core->id == CLK_MAIN) {
+
+		/* If EXTAL is above 12MHz, then we know it is Mode 1 */
+		if (clk_get_rate((struct clk *)parent) > 12000000)
+			cpg_mode = 1;
+
+		frqcr = clk_readl(base + CPG_FRQCR) & 0xFFF;
+		if (frqcr == 0x012)
+			index = 0;
+		else if (frqcr == 0x112)
+			index = 1;
+		else if (frqcr == 0x212)
+			index = 2;
+		else if (frqcr == 0x322)
+			index = 3;
+		else if (frqcr == 0x333)
+			index = 4;
+		else
+			BUG_ON(1);	/* Illegal FRQCR value */
+
+		for (i = 0; i < ARRAY_SIZE(r7s9210_core_clks); i++) {
+			switch (r7s9210_core_clks[i].id) {
+			case R7S9210_CLK_I:
+				r7s9210_core_clks[i].div = ratio_tab[index][0];
+				break;
+			case R7S9210_CLK_G:
+				r7s9210_core_clks[i].div = ratio_tab[index][1];
+				break;
+			case R7S9210_CLK_B:
+				r7s9210_core_clks[i].div = ratio_tab[index][2];
+				break;
+			case R7S9210_CLK_P1:
+			case R7S9210_CLK_P1C:
+				r7s9210_core_clks[i].div = ratio_tab[index][3];
+				break;
+			case R7S9210_CLK_P0:
+				r7s9210_core_clks[i].div = ratio_tab[index][4];
+				break;
+			}
+		}
+	}
+
+	return clk_register_fixed_factor(NULL, core->name,
+					 __clk_get_name(parent), 0, mult, div);
+}
+
+const struct cpg_mssr_info r7s9210_cpg_mssr_info __initconst = {
+	/* Core Clocks */
+	.core_clks = r7s9210_core_clks,
+	.num_core_clks = ARRAY_SIZE(r7s9210_core_clks),
+	.last_dt_core_clk = LAST_DT_CORE_CLK,
+	.num_total_core_clks = MOD_CLK_BASE,
+
+	/* Module Clocks */
+	.mod_clks = r7s9210_mod_clks,
+	.num_mod_clks = ARRAY_SIZE(r7s9210_mod_clks),
+	.num_hw_mod_clks = 9 * 32, /* includes STBCR0/1/2 which don't exist */
+
+	/* Callbacks */
+	.cpg_clk_register = rza2_cpg_clk_register,
+
+	/* RZ/A2 has Standby Control Registers */
+	.stbyctrl = true,
+};
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c
index e04338932786..80882eadf95f 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -73,6 +73,17 @@  static const u16 smstpcr[] = {
 
 #define	SMSTPCR(i)	smstpcr[i]
 
+/*
+ * Standby Control Register offsets (RZ/A)
+ * Base address is FRQCR register
+ */
+
+static const u16 stbcr[] = {
+	0x000, 0x000, 0x014, 0x410, 0x414, 0x418, 0x41C, 0x420,
+	0x424, 0x428, 0x42C, 0x430, 0x434, 0x460,
+};
+
+#define	STBCR(i)	stbcr[i]
 
 /*
  * Software Reset Register offsets
@@ -110,6 +121,7 @@  static const u16 srcr[] = {
  * @notifiers: Notifier chain to save/restore clock state for system resume
  * @smstpcr_saved[].mask: Mask of SMSTPCR[] bits under our control
  * @smstpcr_saved[].val: Saved values of SMSTPCR[]
+ * @stbyctrl: This device has Standby Control Registers
  */
 struct cpg_mssr_priv {
 #ifdef CONFIG_RESET_CONTROLLER
@@ -123,6 +135,7 @@  struct cpg_mssr_priv {
 	unsigned int num_core_clks;
 	unsigned int num_mod_clks;
 	unsigned int last_dt_core_clk;
+	bool stbyctrl;
 
 	struct raw_notifier_head notifiers;
 	struct {
@@ -162,16 +175,29 @@  static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
 		enable ? "ON" : "OFF");
 	spin_lock_irqsave(&priv->rmw_lock, flags);
 
-	value = readl(priv->base + SMSTPCR(reg));
-	if (enable)
-		value &= ~bitmask;
-	else
-		value |= bitmask;
-	writel(value, priv->base + SMSTPCR(reg));
+	if (priv->stbyctrl) {
+		value = readb(priv->base + STBCR(reg));
+		if (enable)
+			value &= ~bitmask;
+		else
+			value |= bitmask;
+		writeb(value, priv->base + STBCR(reg));
+
+		/* dummy read to ensure write has completed */
+		readb(priv->base + STBCR(reg));
+		barrier_data(priv->base + STBCR(reg));
+	} else {
+		value = readl(priv->base + SMSTPCR(reg));
+		if (enable)
+			value &= ~bitmask;
+		else
+			value |= bitmask;
+		writel(value, priv->base + SMSTPCR(reg));
+	}
 
 	spin_unlock_irqrestore(&priv->rmw_lock, flags);
 
-	if (!enable)
+	if (!enable || priv->stbyctrl)
 		return 0;
 
 	for (i = 1000; i > 0; --i) {
@@ -205,7 +231,10 @@  static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
 	struct cpg_mssr_priv *priv = clock->priv;
 	u32 value;
 
-	value = readl(priv->base + MSTPSR(clock->index / 32));
+	if (priv->stbyctrl)
+		value = readb(priv->base + STBCR(clock->index / 32));
+	else
+		value = readl(priv->base + MSTPSR(clock->index / 32));
 
 	return !(value & BIT(clock->index % 32));
 }
@@ -734,6 +763,12 @@  static const struct of_device_id cpg_mssr_match[] = {
 		.compatible = "renesas,r8a77995-cpg-mssr",
 		.data = &r8a77995_cpg_mssr_info,
 	},
+#endif
+#ifdef CONFIG_CLK_R7S9210
+	{
+		.compatible = "renesas,r7s9210-cpg-mssr",
+		.data = &r7s9210_cpg_mssr_info,
+	},
 #endif
 	{ /* sentinel */ }
 };
@@ -785,13 +820,23 @@  static int cpg_mssr_resume_noirq(struct device *dev)
 		if (!mask)
 			continue;
 
-		oldval = readl(priv->base + SMSTPCR(reg));
+		if (priv->stbyctrl)
+			oldval = readb(priv->base + STBCR(reg));
+		else
+			oldval = readl(priv->base + SMSTPCR(reg));
 		newval = oldval & ~mask;
 		newval |= priv->smstpcr_saved[reg].val & mask;
 		if (newval == oldval)
 			continue;
 
-		writel(newval, priv->base + SMSTPCR(reg));
+		if (priv->stbyctrl) {
+			writeb(newval, priv->base + STBCR(reg));
+			/* dummy read to ensure write has completed */
+			readb(priv->base + STBCR(reg));
+			barrier_data(priv->base + STBCR(reg));
+			continue;
+		} else
+			writel(newval, priv->base + SMSTPCR(reg));
 
 		/* Wait until enabled clocks are really enabled */
 		mask &= ~priv->smstpcr_saved[reg].val;
@@ -863,6 +908,7 @@  static int __init cpg_mssr_probe(struct platform_device *pdev)
 	priv->num_mod_clks = info->num_hw_mod_clks;
 	priv->last_dt_core_clk = info->last_dt_core_clk;
 	RAW_INIT_NOTIFIER_HEAD(&priv->notifiers);
+	priv->stbyctrl = info->stbyctrl;
 
 	for (i = 0; i < nclks; i++)
 		clks[i] = ERR_PTR(-ENOENT);
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h
index 87bb8f368d4e..e65259ed4052 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.h
+++ b/drivers/clk/renesas/renesas-cpg-mssr.h
@@ -103,6 +103,10 @@  struct device_node;
      *
      * @init: Optional callback to perform SoC-specific initialization
      * @cpg_clk_register: Optional callback to handle special Core Clock types
+     *
+     * @stbyctrl: This device has Standby Control Registers which are 8-bits
+     *            wide, no status registers (MSTPSR) and have different address
+     *            offsets.
      */
 
 struct cpg_mssr_info {
@@ -111,6 +115,7 @@  struct cpg_mssr_info {
 	unsigned int num_core_clks;
 	unsigned int last_dt_core_clk;
 	unsigned int num_total_core_clks;
+	bool stbyctrl;
 
 	/* Module Clocks */
 	const struct mssr_mod_clk *mod_clks;
@@ -148,6 +153,7 @@  extern const struct cpg_mssr_info r8a77970_cpg_mssr_info;
 extern const struct cpg_mssr_info r8a77980_cpg_mssr_info;
 extern const struct cpg_mssr_info r8a77990_cpg_mssr_info;
 extern const struct cpg_mssr_info r8a77995_cpg_mssr_info;
+extern const struct cpg_mssr_info r7s9210_cpg_mssr_info;
 
 
     /*
diff --git a/include/dt-bindings/clock/r7s9210-cpg-mssr.h b/include/dt-bindings/clock/r7s9210-cpg-mssr.h
new file mode 100644
index 000000000000..b124bb65e9fc
--- /dev/null
+++ b/include/dt-bindings/clock/r7s9210-cpg-mssr.h
@@ -0,0 +1,21 @@ 
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) 2018 Renesas Electronics Corp.
+ *
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_R7S9210_CPG_MSSR_H__
+#define __DT_BINDINGS_CLOCK_R7S9210_CPG_MSSR_H__
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+/* R7S9210 CPG Core Clocks */
+#define R7S9210_CLK_PLL			0
+#define R7S9210_CLK_I			1
+#define R7S9210_CLK_G			2
+#define R7S9210_CLK_B			3
+#define R7S9210_CLK_P1			4
+#define R7S9210_CLK_P1C			5
+#define R7S9210_CLK_P0			6
+
+#endif /* __DT_BINDINGS_CLOCK_R7S9210_CPG_MSSR_H__ */