1 // SPDX-License-Identifier: GPL-2.0
3 * R7S9210 Clock Pulse Generator / Module Standby
5 * Based on r8a7795-cpg-mssr.c
7 * Copyright (C) 2018 Chris Brandt
8 * Copyright (C) 2018 Renesas Electronics Corp.
12 #include <linux/clk.h>
13 #include <linux/clk-provider.h>
15 #include <dt-bindings/clock/r7s9210-cpg-mssr.h>
16 #include "renesas-cpg-mssr.h"
18 #define CPG_FRQCR 0x00
22 /* Internal Clock ratio table */
28 /* p0 is always 32 */;
29 } ratio_tab
[5] = { /* I, G, B, P1 */
30 { 2, 4, 8, 16}, /* FRQCR = 0x012 */
31 { 4, 4, 8, 16}, /* FRQCR = 0x112 */
32 { 8, 4, 8, 16}, /* FRQCR = 0x212 */
33 { 16, 8, 16, 16}, /* FRQCR = 0x322 */
34 { 16, 16, 32, 32}, /* FRQCR = 0x333 */
38 CLK_TYPE_RZA_MAIN
= CLK_TYPE_CUSTOM
,
43 /* Core Clock Outputs exported to DT */
44 LAST_DT_CORE_CLK
= R7S9210_CLK_P0
,
46 /* External Input Clocks */
49 /* Internal Core Clocks */
57 static struct cpg_core_clk r7s9210_early_core_clks
[] = {
58 /* External Clock Inputs */
59 DEF_INPUT("extal", CLK_EXTAL
),
61 /* Internal Core Clocks */
62 DEF_BASE(".main", CLK_MAIN
, CLK_TYPE_RZA_MAIN
, CLK_EXTAL
),
63 DEF_BASE(".pll", CLK_PLL
, CLK_TYPE_RZA_PLL
, CLK_MAIN
),
65 /* Core Clock Outputs */
66 DEF_FIXED("p1c", R7S9210_CLK_P1C
, CLK_PLL
, 16, 1),
69 static const struct mssr_mod_clk r7s9210_early_mod_clks
[] __initconst
= {
70 DEF_MOD_STB("ostm2", 34, R7S9210_CLK_P1C
),
71 DEF_MOD_STB("ostm1", 35, R7S9210_CLK_P1C
),
72 DEF_MOD_STB("ostm0", 36, R7S9210_CLK_P1C
),
75 static struct cpg_core_clk r7s9210_core_clks
[] = {
76 /* Core Clock Outputs */
77 DEF_FIXED("i", R7S9210_CLK_I
, CLK_PLL
, 2, 1),
78 DEF_FIXED("g", R7S9210_CLK_G
, CLK_PLL
, 4, 1),
79 DEF_FIXED("b", R7S9210_CLK_B
, CLK_PLL
, 8, 1),
80 DEF_FIXED("p1", R7S9210_CLK_P1
, CLK_PLL
, 16, 1),
81 DEF_FIXED("p0", R7S9210_CLK_P0
, CLK_PLL
, 32, 1),
84 static const struct mssr_mod_clk r7s9210_mod_clks
[] __initconst
= {
85 DEF_MOD_STB("scif4", 43, R7S9210_CLK_P1C
),
86 DEF_MOD_STB("scif3", 44, R7S9210_CLK_P1C
),
87 DEF_MOD_STB("scif2", 45, R7S9210_CLK_P1C
),
88 DEF_MOD_STB("scif1", 46, R7S9210_CLK_P1C
),
89 DEF_MOD_STB("scif0", 47, R7S9210_CLK_P1C
),
91 DEF_MOD_STB("usb1", 60, R7S9210_CLK_B
),
92 DEF_MOD_STB("usb0", 61, R7S9210_CLK_B
),
93 DEF_MOD_STB("ether1", 64, R7S9210_CLK_B
),
94 DEF_MOD_STB("ether0", 65, R7S9210_CLK_B
),
96 DEF_MOD_STB("spibsc", 83, R7S9210_CLK_P1
),
97 DEF_MOD_STB("i2c3", 84, R7S9210_CLK_P1
),
98 DEF_MOD_STB("i2c2", 85, R7S9210_CLK_P1
),
99 DEF_MOD_STB("i2c1", 86, R7S9210_CLK_P1
),
100 DEF_MOD_STB("i2c0", 87, R7S9210_CLK_P1
),
102 DEF_MOD_STB("spi2", 95, R7S9210_CLK_P1
),
103 DEF_MOD_STB("spi1", 96, R7S9210_CLK_P1
),
104 DEF_MOD_STB("spi0", 97, R7S9210_CLK_P1
),
106 DEF_MOD_STB("sdhi11", 100, R7S9210_CLK_B
),
107 DEF_MOD_STB("sdhi10", 101, R7S9210_CLK_B
),
108 DEF_MOD_STB("sdhi01", 102, R7S9210_CLK_B
),
109 DEF_MOD_STB("sdhi00", 103, R7S9210_CLK_B
),
112 /* The clock dividers in the table vary based on DT and register settings */
113 static void __init
r7s9210_update_clk_table(struct clk
*extal_clk
,
120 /* If EXTAL is above 12MHz, then we know it is Mode 1 */
121 if (clk_get_rate(extal_clk
) > 12000000)
124 frqcr
= readl(base
+ CPG_FRQCR
) & 0xFFF;
127 else if (frqcr
== 0x112)
129 else if (frqcr
== 0x212)
131 else if (frqcr
== 0x322)
133 else if (frqcr
== 0x333)
136 BUG_ON(1); /* Illegal FRQCR value */
138 for (i
= 0; i
< ARRAY_SIZE(r7s9210_core_clks
); i
++) {
139 switch (r7s9210_core_clks
[i
].id
) {
141 r7s9210_core_clks
[i
].div
= ratio_tab
[index
].i
;
144 r7s9210_core_clks
[i
].div
= ratio_tab
[index
].g
;
147 r7s9210_core_clks
[i
].div
= ratio_tab
[index
].b
;
150 case R7S9210_CLK_P1C
:
151 r7s9210_core_clks
[i
].div
= ratio_tab
[index
].p1
;
154 r7s9210_core_clks
[i
].div
= 32;
160 static struct clk
* __init
rza2_cpg_clk_register(struct device
*dev
,
161 const struct cpg_core_clk
*core
, const struct cpg_mssr_info
*info
,
162 struct clk
**clks
, void __iomem
*base
,
163 struct raw_notifier_head
*notifiers
)
166 unsigned int mult
= 1;
167 unsigned int div
= 1;
169 parent
= clks
[core
->parent
];
171 return ERR_CAST(parent
);
179 mult
= 44; /* Divider 1 is 1/2 */
181 mult
= 88; /* Divider 1 is 1 */
185 return ERR_PTR(-EINVAL
);
188 if (core
->id
== CLK_MAIN
)
189 r7s9210_update_clk_table(parent
, base
);
191 return clk_register_fixed_factor(NULL
, core
->name
,
192 __clk_get_name(parent
), 0, mult
, div
);
195 const struct cpg_mssr_info r7s9210_cpg_mssr_info __initconst
= {
197 .early_core_clks
= r7s9210_early_core_clks
,
198 .num_early_core_clks
= ARRAY_SIZE(r7s9210_early_core_clks
),
199 .early_mod_clks
= r7s9210_early_mod_clks
,
200 .num_early_mod_clks
= ARRAY_SIZE(r7s9210_early_mod_clks
),
203 .core_clks
= r7s9210_core_clks
,
204 .num_core_clks
= ARRAY_SIZE(r7s9210_core_clks
),
205 .last_dt_core_clk
= LAST_DT_CORE_CLK
,
206 .num_total_core_clks
= MOD_CLK_BASE
,
209 .mod_clks
= r7s9210_mod_clks
,
210 .num_mod_clks
= ARRAY_SIZE(r7s9210_mod_clks
),
211 .num_hw_mod_clks
= 11 * 32, /* includes STBCR0 which doesn't exist */
214 .cpg_clk_register
= rza2_cpg_clk_register
,
216 /* RZ/A2 has Standby Control Registers */
220 static void __init
r7s9210_cpg_mssr_early_init(struct device_node
*np
)
222 cpg_mssr_early_init(np
, &r7s9210_cpg_mssr_info
);
225 CLK_OF_DECLARE_DRIVER(cpg_mstp_clks
, "renesas,r7s9210-cpg-mssr",
226 r7s9210_cpg_mssr_early_init
);