Commit | Line | Data |
---|---|---|
4c3d8852 MP |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * R9A09G032 clock driver | |
4 | * | |
5 | * Copyright (C) 2018 Renesas Electronics Europe Limited | |
6 | * | |
7 | * Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com> | |
8 | */ | |
9 | ||
10 | #include <linux/clk.h> | |
11 | #include <linux/clk-provider.h> | |
12 | #include <linux/delay.h> | |
13 | #include <linux/init.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/math64.h> | |
16 | #include <linux/of.h> | |
17 | #include <linux/of_address.h> | |
18 | #include <linux/platform_device.h> | |
19 | #include <linux/slab.h> | |
20 | #include <linux/spinlock.h> | |
21 | #include <dt-bindings/clock/r9a06g032-sysctrl.h> | |
22 | ||
23 | struct r9a06g032_gate { | |
24 | u16 gate, reset, ready, midle, | |
25 | scon, mirack, mistat; | |
26 | }; | |
27 | ||
28 | /* This is used to describe a clock for instantiation */ | |
29 | struct r9a06g032_clkdesc { | |
30 | const char *name; | |
31 | uint32_t type: 3; | |
32 | uint32_t index: 8; | |
33 | uint32_t source : 8; /* source index + 1 (0 == none) */ | |
34 | /* these are used to populate the bitsel struct */ | |
35 | union { | |
36 | struct r9a06g032_gate gate; | |
37 | /* for dividers */ | |
38 | struct { | |
39 | unsigned int div_min : 10, div_max : 10, reg: 10; | |
40 | u16 div_table[4]; | |
41 | }; | |
42 | /* For fixed-factor ones */ | |
43 | struct { | |
44 | u16 div, mul; | |
45 | }; | |
46 | unsigned int factor; | |
47 | unsigned int frequency; | |
48 | /* for dual gate */ | |
49 | struct { | |
50 | uint16_t group : 1, index: 3; | |
51 | u16 sel, g1, r1, g2, r2; | |
52 | } dual; | |
53 | }; | |
54 | } __packed; | |
55 | ||
56 | #define I_GATE(_clk, _rst, _rdy, _midle, _scon, _mirack, _mistat) \ | |
57 | { .gate = _clk, .reset = _rst, \ | |
58 | .ready = _rdy, .midle = _midle, \ | |
59 | .scon = _scon, .mirack = _mirack, .mistat = _mistat } | |
60 | #define D_GATE(_idx, _n, _src, ...) \ | |
61 | { .type = K_GATE, .index = R9A06G032_##_idx, \ | |
62 | .source = 1 + R9A06G032_##_src, .name = _n, \ | |
63 | .gate = I_GATE(__VA_ARGS__), } | |
64 | #define D_ROOT(_idx, _n, _mul, _div) \ | |
65 | { .type = K_FFC, .index = R9A06G032_##_idx, .name = _n, \ | |
66 | .div = _div, .mul = _mul } | |
67 | #define D_FFC(_idx, _n, _src, _div) \ | |
68 | { .type = K_FFC, .index = R9A06G032_##_idx, \ | |
69 | .source = 1 + R9A06G032_##_src, .name = _n, \ | |
70 | .div = _div, .mul = 1} | |
71 | #define D_DIV(_idx, _n, _src, _reg, _min, _max, ...) \ | |
72 | { .type = K_DIV, .index = R9A06G032_##_idx, \ | |
73 | .source = 1 + R9A06G032_##_src, .name = _n, \ | |
74 | .reg = _reg, .div_min = _min, .div_max = _max, \ | |
75 | .div_table = { __VA_ARGS__ } } | |
76 | #define D_UGATE(_idx, _n, _src, _g, _gi, _g1, _r1, _g2, _r2) \ | |
77 | { .type = K_DUALGATE, .index = R9A06G032_##_idx, \ | |
78 | .source = 1 + R9A06G032_##_src, .name = _n, \ | |
79 | .dual = { .group = _g, .index = _gi, \ | |
80 | .g1 = _g1, .r1 = _r1, .g2 = _g2, .r2 = _r2 }, } | |
81 | ||
82 | enum { K_GATE = 0, K_FFC, K_DIV, K_BITSEL, K_DUALGATE }; | |
83 | ||
84 | /* Internal clock IDs */ | |
85 | #define R9A06G032_CLKOUT 0 | |
86 | #define R9A06G032_CLKOUT_D10 2 | |
87 | #define R9A06G032_CLKOUT_D16 3 | |
88 | #define R9A06G032_CLKOUT_D160 4 | |
89 | #define R9A06G032_CLKOUT_D1OR2 5 | |
90 | #define R9A06G032_CLKOUT_D20 6 | |
91 | #define R9A06G032_CLKOUT_D40 7 | |
92 | #define R9A06G032_CLKOUT_D5 8 | |
93 | #define R9A06G032_CLKOUT_D8 9 | |
94 | #define R9A06G032_DIV_ADC 10 | |
95 | #define R9A06G032_DIV_I2C 11 | |
96 | #define R9A06G032_DIV_NAND 12 | |
97 | #define R9A06G032_DIV_P1_PG 13 | |
98 | #define R9A06G032_DIV_P2_PG 14 | |
99 | #define R9A06G032_DIV_P3_PG 15 | |
100 | #define R9A06G032_DIV_P4_PG 16 | |
101 | #define R9A06G032_DIV_P5_PG 17 | |
102 | #define R9A06G032_DIV_P6_PG 18 | |
103 | #define R9A06G032_DIV_QSPI0 19 | |
104 | #define R9A06G032_DIV_QSPI1 20 | |
105 | #define R9A06G032_DIV_REF_SYNC 21 | |
106 | #define R9A06G032_DIV_SDIO0 22 | |
107 | #define R9A06G032_DIV_SDIO1 23 | |
108 | #define R9A06G032_DIV_SWITCH 24 | |
109 | #define R9A06G032_DIV_UART 25 | |
110 | #define R9A06G032_DIV_MOTOR 64 | |
111 | #define R9A06G032_CLK_DDRPHY_PLLCLK_D4 78 | |
112 | #define R9A06G032_CLK_ECAT100_D4 79 | |
113 | #define R9A06G032_CLK_HSR100_D2 80 | |
114 | #define R9A06G032_CLK_REF_SYNC_D4 81 | |
115 | #define R9A06G032_CLK_REF_SYNC_D8 82 | |
116 | #define R9A06G032_CLK_SERCOS100_D2 83 | |
117 | #define R9A06G032_DIV_CA7 84 | |
118 | ||
119 | #define R9A06G032_UART_GROUP_012 154 | |
120 | #define R9A06G032_UART_GROUP_34567 155 | |
121 | ||
122 | #define R9A06G032_CLOCK_COUNT (R9A06G032_UART_GROUP_34567 + 1) | |
123 | ||
124 | static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = { | |
125 | D_ROOT(CLKOUT, "clkout", 25, 1), | |
126 | D_ROOT(CLK_PLL_USB, "clk_pll_usb", 12, 10), | |
127 | D_FFC(CLKOUT_D10, "clkout_d10", CLKOUT, 10), | |
128 | D_FFC(CLKOUT_D16, "clkout_d16", CLKOUT, 16), | |
129 | D_FFC(CLKOUT_D160, "clkout_d160", CLKOUT, 160), | |
130 | D_DIV(CLKOUT_D1OR2, "clkout_d1or2", CLKOUT, 0, 1, 2), | |
131 | D_FFC(CLKOUT_D20, "clkout_d20", CLKOUT, 20), | |
132 | D_FFC(CLKOUT_D40, "clkout_d40", CLKOUT, 40), | |
133 | D_FFC(CLKOUT_D5, "clkout_d5", CLKOUT, 5), | |
134 | D_FFC(CLKOUT_D8, "clkout_d8", CLKOUT, 8), | |
135 | D_DIV(DIV_ADC, "div_adc", CLKOUT, 77, 50, 250), | |
136 | D_DIV(DIV_I2C, "div_i2c", CLKOUT, 78, 12, 16), | |
137 | D_DIV(DIV_NAND, "div_nand", CLKOUT, 82, 12, 32), | |
138 | D_DIV(DIV_P1_PG, "div_p1_pg", CLKOUT, 68, 12, 200), | |
139 | D_DIV(DIV_P2_PG, "div_p2_pg", CLKOUT, 62, 12, 128), | |
140 | D_DIV(DIV_P3_PG, "div_p3_pg", CLKOUT, 64, 8, 128), | |
141 | D_DIV(DIV_P4_PG, "div_p4_pg", CLKOUT, 66, 8, 128), | |
142 | D_DIV(DIV_P5_PG, "div_p5_pg", CLKOUT, 71, 10, 40), | |
143 | D_DIV(DIV_P6_PG, "div_p6_pg", CLKOUT, 18, 12, 64), | |
144 | D_DIV(DIV_QSPI0, "div_qspi0", CLKOUT, 73, 3, 7), | |
145 | D_DIV(DIV_QSPI1, "div_qspi1", CLKOUT, 25, 3, 7), | |
146 | D_DIV(DIV_REF_SYNC, "div_ref_sync", CLKOUT, 56, 2, 16, 2, 4, 8, 16), | |
147 | D_DIV(DIV_SDIO0, "div_sdio0", CLKOUT, 74, 20, 128), | |
148 | D_DIV(DIV_SDIO1, "div_sdio1", CLKOUT, 75, 20, 128), | |
149 | D_DIV(DIV_SWITCH, "div_switch", CLKOUT, 37, 5, 40), | |
150 | D_DIV(DIV_UART, "div_uart", CLKOUT, 79, 12, 128), | |
151 | D_GATE(CLK_25_PG4, "clk_25_pg4", CLKOUT_D40, 0x749, 0x74a, 0x74b, 0, 0xae3, 0, 0), | |
152 | D_GATE(CLK_25_PG5, "clk_25_pg5", CLKOUT_D40, 0x74c, 0x74d, 0x74e, 0, 0xae4, 0, 0), | |
153 | D_GATE(CLK_25_PG6, "clk_25_pg6", CLKOUT_D40, 0x74f, 0x750, 0x751, 0, 0xae5, 0, 0), | |
154 | D_GATE(CLK_25_PG7, "clk_25_pg7", CLKOUT_D40, 0x752, 0x753, 0x754, 0, 0xae6, 0, 0), | |
155 | D_GATE(CLK_25_PG8, "clk_25_pg8", CLKOUT_D40, 0x755, 0x756, 0x757, 0, 0xae7, 0, 0), | |
156 | D_GATE(CLK_ADC, "clk_adc", DIV_ADC, 0x1ea, 0x1eb, 0, 0, 0, 0, 0), | |
157 | D_GATE(CLK_ECAT100, "clk_ecat100", CLKOUT_D10, 0x405, 0, 0, 0, 0, 0, 0), | |
158 | D_GATE(CLK_HSR100, "clk_hsr100", CLKOUT_D10, 0x483, 0, 0, 0, 0, 0, 0), | |
159 | D_GATE(CLK_I2C0, "clk_i2c0", DIV_I2C, 0x1e6, 0x1e7, 0, 0, 0, 0, 0), | |
160 | D_GATE(CLK_I2C1, "clk_i2c1", DIV_I2C, 0x1e8, 0x1e9, 0, 0, 0, 0, 0), | |
161 | D_GATE(CLK_MII_REF, "clk_mii_ref", CLKOUT_D40, 0x342, 0, 0, 0, 0, 0, 0), | |
162 | D_GATE(CLK_NAND, "clk_nand", DIV_NAND, 0x284, 0x285, 0, 0, 0, 0, 0), | |
163 | D_GATE(CLK_NOUSBP2_PG6, "clk_nousbp2_pg6", DIV_P2_PG, 0x774, 0x775, 0, 0, 0, 0, 0), | |
164 | D_GATE(CLK_P1_PG2, "clk_p1_pg2", DIV_P1_PG, 0x862, 0x863, 0, 0, 0, 0, 0), | |
165 | D_GATE(CLK_P1_PG3, "clk_p1_pg3", DIV_P1_PG, 0x864, 0x865, 0, 0, 0, 0, 0), | |
166 | D_GATE(CLK_P1_PG4, "clk_p1_pg4", DIV_P1_PG, 0x866, 0x867, 0, 0, 0, 0, 0), | |
167 | D_GATE(CLK_P4_PG3, "clk_p4_pg3", DIV_P4_PG, 0x824, 0x825, 0, 0, 0, 0, 0), | |
168 | D_GATE(CLK_P4_PG4, "clk_p4_pg4", DIV_P4_PG, 0x826, 0x827, 0, 0, 0, 0, 0), | |
169 | D_GATE(CLK_P6_PG1, "clk_p6_pg1", DIV_P6_PG, 0x8a0, 0x8a1, 0x8a2, 0, 0xb60, 0, 0), | |
170 | D_GATE(CLK_P6_PG2, "clk_p6_pg2", DIV_P6_PG, 0x8a3, 0x8a4, 0x8a5, 0, 0xb61, 0, 0), | |
171 | D_GATE(CLK_P6_PG3, "clk_p6_pg3", DIV_P6_PG, 0x8a6, 0x8a7, 0x8a8, 0, 0xb62, 0, 0), | |
172 | D_GATE(CLK_P6_PG4, "clk_p6_pg4", DIV_P6_PG, 0x8a9, 0x8aa, 0x8ab, 0, 0xb63, 0, 0), | |
173 | D_GATE(CLK_QSPI0, "clk_qspi0", DIV_QSPI0, 0x2a4, 0x2a5, 0, 0, 0, 0, 0), | |
174 | D_GATE(CLK_QSPI1, "clk_qspi1", DIV_QSPI1, 0x484, 0x485, 0, 0, 0, 0, 0), | |
175 | D_GATE(CLK_RGMII_REF, "clk_rgmii_ref", CLKOUT_D8, 0x340, 0, 0, 0, 0, 0, 0), | |
176 | D_GATE(CLK_RMII_REF, "clk_rmii_ref", CLKOUT_D20, 0x341, 0, 0, 0, 0, 0, 0), | |
177 | D_GATE(CLK_SDIO0, "clk_sdio0", DIV_SDIO0, 0x64, 0, 0, 0, 0, 0, 0), | |
178 | D_GATE(CLK_SDIO1, "clk_sdio1", DIV_SDIO1, 0x644, 0, 0, 0, 0, 0, 0), | |
179 | D_GATE(CLK_SERCOS100, "clk_sercos100", CLKOUT_D10, 0x425, 0, 0, 0, 0, 0, 0), | |
180 | D_GATE(CLK_SLCD, "clk_slcd", DIV_P1_PG, 0x860, 0x861, 0, 0, 0, 0, 0), | |
181 | D_GATE(CLK_SPI0, "clk_spi0", DIV_P3_PG, 0x7e0, 0x7e1, 0, 0, 0, 0, 0), | |
182 | D_GATE(CLK_SPI1, "clk_spi1", DIV_P3_PG, 0x7e2, 0x7e3, 0, 0, 0, 0, 0), | |
183 | D_GATE(CLK_SPI2, "clk_spi2", DIV_P3_PG, 0x7e4, 0x7e5, 0, 0, 0, 0, 0), | |
184 | D_GATE(CLK_SPI3, "clk_spi3", DIV_P3_PG, 0x7e6, 0x7e7, 0, 0, 0, 0, 0), | |
185 | D_GATE(CLK_SPI4, "clk_spi4", DIV_P4_PG, 0x820, 0x821, 0, 0, 0, 0, 0), | |
186 | D_GATE(CLK_SPI5, "clk_spi5", DIV_P4_PG, 0x822, 0x823, 0, 0, 0, 0, 0), | |
187 | D_GATE(CLK_SWITCH, "clk_switch", DIV_SWITCH, 0x982, 0x983, 0, 0, 0, 0, 0), | |
188 | D_DIV(DIV_MOTOR, "div_motor", CLKOUT_D5, 84, 2, 8), | |
189 | D_GATE(HCLK_ECAT125, "hclk_ecat125", CLKOUT_D8, 0x400, 0x401, 0, 0x402, 0, 0x440, 0x441), | |
190 | D_GATE(HCLK_PINCONFIG, "hclk_pinconfig", CLKOUT_D40, 0x740, 0x741, 0x742, 0, 0xae0, 0, 0), | |
191 | D_GATE(HCLK_SERCOS, "hclk_sercos", CLKOUT_D10, 0x420, 0x422, 0, 0x421, 0, 0x460, 0x461), | |
192 | D_GATE(HCLK_SGPIO2, "hclk_sgpio2", DIV_P5_PG, 0x8c3, 0x8c4, 0x8c5, 0, 0xb41, 0, 0), | |
193 | D_GATE(HCLK_SGPIO3, "hclk_sgpio3", DIV_P5_PG, 0x8c6, 0x8c7, 0x8c8, 0, 0xb42, 0, 0), | |
194 | D_GATE(HCLK_SGPIO4, "hclk_sgpio4", DIV_P5_PG, 0x8c9, 0x8ca, 0x8cb, 0, 0xb43, 0, 0), | |
195 | D_GATE(HCLK_TIMER0, "hclk_timer0", CLKOUT_D40, 0x743, 0x744, 0x745, 0, 0xae1, 0, 0), | |
196 | D_GATE(HCLK_TIMER1, "hclk_timer1", CLKOUT_D40, 0x746, 0x747, 0x748, 0, 0xae2, 0, 0), | |
197 | D_GATE(HCLK_USBF, "hclk_usbf", CLKOUT_D8, 0xe3, 0, 0, 0xe4, 0, 0x102, 0x103), | |
198 | D_GATE(HCLK_USBH, "hclk_usbh", CLKOUT_D8, 0xe0, 0xe1, 0, 0xe2, 0, 0x100, 0x101), | |
199 | D_GATE(HCLK_USBPM, "hclk_usbpm", CLKOUT_D8, 0xe5, 0, 0, 0, 0, 0, 0), | |
200 | D_GATE(CLK_48_PG_F, "clk_48_pg_f", CLK_48, 0x78c, 0x78d, 0, 0x78e, 0, 0xb04, 0xb05), | |
201 | D_GATE(CLK_48_PG4, "clk_48_pg4", CLK_48, 0x789, 0x78a, 0x78b, 0, 0xb03, 0, 0), | |
202 | D_FFC(CLK_DDRPHY_PLLCLK_D4, "clk_ddrphy_pllclk_d4", CLK_DDRPHY_PLLCLK, 4), | |
203 | D_FFC(CLK_ECAT100_D4, "clk_ecat100_d4", CLK_ECAT100, 4), | |
204 | D_FFC(CLK_HSR100_D2, "clk_hsr100_d2", CLK_HSR100, 2), | |
205 | D_FFC(CLK_REF_SYNC_D4, "clk_ref_sync_d4", CLK_REF_SYNC, 4), | |
206 | D_FFC(CLK_REF_SYNC_D8, "clk_ref_sync_d8", CLK_REF_SYNC, 8), | |
207 | D_FFC(CLK_SERCOS100_D2, "clk_sercos100_d2", CLK_SERCOS100, 2), | |
208 | D_DIV(DIV_CA7, "div_ca7", CLK_REF_SYNC, 57, 1, 4, 1, 2, 4), | |
209 | D_GATE(HCLK_CAN0, "hclk_can0", CLK_48, 0x783, 0x784, 0x785, 0, 0xb01, 0, 0), | |
210 | D_GATE(HCLK_CAN1, "hclk_can1", CLK_48, 0x786, 0x787, 0x788, 0, 0xb02, 0, 0), | |
211 | D_GATE(HCLK_DELTASIGMA, "hclk_deltasigma", DIV_MOTOR, 0x1ef, 0x1f0, 0x1f1, 0, 0, 0, 0), | |
212 | D_GATE(HCLK_PWMPTO, "hclk_pwmpto", DIV_MOTOR, 0x1ec, 0x1ed, 0x1ee, 0, 0, 0, 0), | |
213 | D_GATE(HCLK_RSV, "hclk_rsv", CLK_48, 0x780, 0x781, 0x782, 0, 0xb00, 0, 0), | |
214 | D_GATE(HCLK_SGPIO0, "hclk_sgpio0", DIV_MOTOR, 0x1e0, 0x1e1, 0x1e2, 0, 0, 0, 0), | |
215 | D_GATE(HCLK_SGPIO1, "hclk_sgpio1", DIV_MOTOR, 0x1e3, 0x1e4, 0x1e5, 0, 0, 0, 0), | |
216 | D_DIV(RTOS_MDC, "rtos_mdc", CLK_REF_SYNC, 100, 80, 640, 80, 160, 320, 640), | |
217 | D_GATE(CLK_CM3, "clk_cm3", CLK_REF_SYNC_D4, 0xba0, 0xba1, 0, 0xba2, 0, 0xbc0, 0xbc1), | |
218 | D_GATE(CLK_DDRC, "clk_ddrc", CLK_DDRPHY_PLLCLK_D4, 0x323, 0x324, 0, 0, 0, 0, 0), | |
219 | D_GATE(CLK_ECAT25, "clk_ecat25", CLK_ECAT100_D4, 0x403, 0x404, 0, 0, 0, 0, 0), | |
220 | D_GATE(CLK_HSR50, "clk_hsr50", CLK_HSR100_D2, 0x484, 0x485, 0, 0, 0, 0, 0), | |
221 | D_GATE(CLK_HW_RTOS, "clk_hw_rtos", CLK_REF_SYNC_D4, 0xc60, 0xc61, 0, 0, 0, 0, 0), | |
222 | D_GATE(CLK_SERCOS50, "clk_sercos50", CLK_SERCOS100_D2, 0x424, 0x423, 0, 0, 0, 0, 0), | |
223 | D_GATE(HCLK_ADC, "hclk_adc", CLK_REF_SYNC_D8, 0x1af, 0x1b0, 0x1b1, 0, 0, 0, 0), | |
224 | D_GATE(HCLK_CM3, "hclk_cm3", CLK_REF_SYNC_D4, 0xc20, 0xc21, 0xc22, 0, 0, 0, 0), | |
225 | D_GATE(HCLK_CRYPTO_EIP150, "hclk_crypto_eip150", CLK_REF_SYNC_D4, 0x123, 0x124, 0x125, 0, 0x142, 0, 0), | |
226 | D_GATE(HCLK_CRYPTO_EIP93, "hclk_crypto_eip93", CLK_REF_SYNC_D4, 0x120, 0x121, 0, 0x122, 0, 0x140, 0x141), | |
227 | D_GATE(HCLK_DDRC, "hclk_ddrc", CLK_REF_SYNC_D4, 0x320, 0x322, 0, 0x321, 0, 0x3a0, 0x3a1), | |
228 | D_GATE(HCLK_DMA0, "hclk_dma0", CLK_REF_SYNC_D4, 0x260, 0x261, 0x262, 0x263, 0x2c0, 0x2c1, 0x2c2), | |
229 | D_GATE(HCLK_DMA1, "hclk_dma1", CLK_REF_SYNC_D4, 0x264, 0x265, 0x266, 0x267, 0x2c3, 0x2c4, 0x2c5), | |
230 | D_GATE(HCLK_GMAC0, "hclk_gmac0", CLK_REF_SYNC_D4, 0x360, 0x361, 0x362, 0x363, 0x3c0, 0x3c1, 0x3c2), | |
231 | D_GATE(HCLK_GMAC1, "hclk_gmac1", CLK_REF_SYNC_D4, 0x380, 0x381, 0x382, 0x383, 0x3e0, 0x3e1, 0x3e2), | |
232 | D_GATE(HCLK_GPIO0, "hclk_gpio0", CLK_REF_SYNC_D4, 0x212, 0x213, 0x214, 0, 0, 0, 0), | |
233 | D_GATE(HCLK_GPIO1, "hclk_gpio1", CLK_REF_SYNC_D4, 0x215, 0x216, 0x217, 0, 0, 0, 0), | |
234 | D_GATE(HCLK_GPIO2, "hclk_gpio2", CLK_REF_SYNC_D4, 0x229, 0x22a, 0x22b, 0, 0, 0, 0), | |
235 | D_GATE(HCLK_HSR, "hclk_hsr", CLK_HSR100_D2, 0x480, 0x482, 0, 0x481, 0, 0x4c0, 0x4c1), | |
236 | D_GATE(HCLK_I2C0, "hclk_i2c0", CLK_REF_SYNC_D8, 0x1a9, 0x1aa, 0x1ab, 0, 0, 0, 0), | |
237 | D_GATE(HCLK_I2C1, "hclk_i2c1", CLK_REF_SYNC_D8, 0x1ac, 0x1ad, 0x1ae, 0, 0, 0, 0), | |
238 | D_GATE(HCLK_LCD, "hclk_lcd", CLK_REF_SYNC_D4, 0x7a0, 0x7a1, 0x7a2, 0, 0xb20, 0, 0), | |
239 | D_GATE(HCLK_MSEBI_M, "hclk_msebi_m", CLK_REF_SYNC_D4, 0x164, 0x165, 0x166, 0, 0x183, 0, 0), | |
240 | D_GATE(HCLK_MSEBI_S, "hclk_msebi_s", CLK_REF_SYNC_D4, 0x160, 0x161, 0x162, 0x163, 0x180, 0x181, 0x182), | |
241 | D_GATE(HCLK_NAND, "hclk_nand", CLK_REF_SYNC_D4, 0x280, 0x281, 0x282, 0x283, 0x2e0, 0x2e1, 0x2e2), | |
242 | D_GATE(HCLK_PG_I, "hclk_pg_i", CLK_REF_SYNC_D4, 0x7ac, 0x7ad, 0, 0x7ae, 0, 0xb24, 0xb25), | |
243 | D_GATE(HCLK_PG19, "hclk_pg19", CLK_REF_SYNC_D4, 0x22c, 0x22d, 0x22e, 0, 0, 0, 0), | |
244 | D_GATE(HCLK_PG20, "hclk_pg20", CLK_REF_SYNC_D4, 0x22f, 0x230, 0x231, 0, 0, 0, 0), | |
245 | D_GATE(HCLK_PG3, "hclk_pg3", CLK_REF_SYNC_D4, 0x7a6, 0x7a7, 0x7a8, 0, 0xb22, 0, 0), | |
246 | D_GATE(HCLK_PG4, "hclk_pg4", CLK_REF_SYNC_D4, 0x7a9, 0x7aa, 0x7ab, 0, 0xb23, 0, 0), | |
247 | D_GATE(HCLK_QSPI0, "hclk_qspi0", CLK_REF_SYNC_D4, 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x300, 0x301, 0x302), | |
248 | D_GATE(HCLK_QSPI1, "hclk_qspi1", CLK_REF_SYNC_D4, 0x480, 0x481, 0x482, 0x483, 0x4c0, 0x4c1, 0x4c2), | |
249 | D_GATE(HCLK_ROM, "hclk_rom", CLK_REF_SYNC_D4, 0xaa0, 0xaa1, 0xaa2, 0, 0xb80, 0, 0), | |
250 | D_GATE(HCLK_RTC, "hclk_rtc", CLK_REF_SYNC_D8, 0xa00, 0, 0, 0, 0, 0, 0), | |
251 | D_GATE(HCLK_SDIO0, "hclk_sdio0", CLK_REF_SYNC_D4, 0x60, 0x61, 0x62, 0x63, 0x80, 0x81, 0x82), | |
252 | D_GATE(HCLK_SDIO1, "hclk_sdio1", CLK_REF_SYNC_D4, 0x640, 0x641, 0x642, 0x643, 0x660, 0x661, 0x662), | |
253 | D_GATE(HCLK_SEMAP, "hclk_semap", CLK_REF_SYNC_D4, 0x7a3, 0x7a4, 0x7a5, 0, 0xb21, 0, 0), | |
254 | D_GATE(HCLK_SPI0, "hclk_spi0", CLK_REF_SYNC_D4, 0x200, 0x201, 0x202, 0, 0, 0, 0), | |
255 | D_GATE(HCLK_SPI1, "hclk_spi1", CLK_REF_SYNC_D4, 0x203, 0x204, 0x205, 0, 0, 0, 0), | |
256 | D_GATE(HCLK_SPI2, "hclk_spi2", CLK_REF_SYNC_D4, 0x206, 0x207, 0x208, 0, 0, 0, 0), | |
257 | D_GATE(HCLK_SPI3, "hclk_spi3", CLK_REF_SYNC_D4, 0x209, 0x20a, 0x20b, 0, 0, 0, 0), | |
258 | D_GATE(HCLK_SPI4, "hclk_spi4", CLK_REF_SYNC_D4, 0x20c, 0x20d, 0x20e, 0, 0, 0, 0), | |
259 | D_GATE(HCLK_SPI5, "hclk_spi5", CLK_REF_SYNC_D4, 0x20f, 0x210, 0x211, 0, 0, 0, 0), | |
260 | D_GATE(HCLK_SWITCH, "hclk_switch", CLK_REF_SYNC_D4, 0x980, 0, 0x981, 0, 0, 0, 0), | |
261 | D_GATE(HCLK_SWITCH_RG, "hclk_switch_rg", CLK_REF_SYNC_D4, 0xc40, 0xc41, 0xc42, 0, 0, 0, 0), | |
262 | D_GATE(HCLK_UART0, "hclk_uart0", CLK_REF_SYNC_D8, 0x1a0, 0x1a1, 0x1a2, 0, 0, 0, 0), | |
263 | D_GATE(HCLK_UART1, "hclk_uart1", CLK_REF_SYNC_D8, 0x1a3, 0x1a4, 0x1a5, 0, 0, 0, 0), | |
264 | D_GATE(HCLK_UART2, "hclk_uart2", CLK_REF_SYNC_D8, 0x1a6, 0x1a7, 0x1a8, 0, 0, 0, 0), | |
265 | D_GATE(HCLK_UART3, "hclk_uart3", CLK_REF_SYNC_D4, 0x218, 0x219, 0x21a, 0, 0, 0, 0), | |
266 | D_GATE(HCLK_UART4, "hclk_uart4", CLK_REF_SYNC_D4, 0x21b, 0x21c, 0x21d, 0, 0, 0, 0), | |
267 | D_GATE(HCLK_UART5, "hclk_uart5", CLK_REF_SYNC_D4, 0x220, 0x221, 0x222, 0, 0, 0, 0), | |
268 | D_GATE(HCLK_UART6, "hclk_uart6", CLK_REF_SYNC_D4, 0x223, 0x224, 0x225, 0, 0, 0, 0), | |
269 | D_GATE(HCLK_UART7, "hclk_uart7", CLK_REF_SYNC_D4, 0x226, 0x227, 0x228, 0, 0, 0, 0), | |
270 | /* | |
271 | * These are not hardware clocks, but are needed to handle the special | |
272 | * case where we have a 'selector bit' that doesn't just change the | |
273 | * parent for a clock, but also the gate it's suposed to use. | |
274 | */ | |
275 | { | |
276 | .index = R9A06G032_UART_GROUP_012, | |
277 | .name = "uart_group_012", | |
278 | .type = K_BITSEL, | |
279 | .source = 1 + R9A06G032_DIV_UART, | |
280 | /* R9A06G032_SYSCTRL_REG_PWRCTRL_PG1_PR2 */ | |
281 | .dual.sel = ((0xec / 4) << 5) | 24, | |
282 | .dual.group = 0, | |
283 | }, | |
284 | { | |
285 | .index = R9A06G032_UART_GROUP_34567, | |
286 | .name = "uart_group_34567", | |
287 | .type = K_BITSEL, | |
288 | .source = 1 + R9A06G032_DIV_P2_PG, | |
289 | /* R9A06G032_SYSCTRL_REG_PWRCTRL_PG0_0 */ | |
290 | .dual.sel = ((0x34 / 4) << 5) | 30, | |
291 | .dual.group = 1, | |
292 | }, | |
293 | D_UGATE(CLK_UART0, "clk_uart0", UART_GROUP_012, 0, 0, 0x1b2, 0x1b3, 0x1b4, 0x1b5), | |
294 | D_UGATE(CLK_UART1, "clk_uart1", UART_GROUP_012, 0, 1, 0x1b6, 0x1b7, 0x1b8, 0x1b9), | |
295 | D_UGATE(CLK_UART2, "clk_uart2", UART_GROUP_012, 0, 2, 0x1ba, 0x1bb, 0x1bc, 0x1bd), | |
296 | D_UGATE(CLK_UART3, "clk_uart3", UART_GROUP_34567, 1, 0, 0x760, 0x761, 0x762, 0x763), | |
297 | D_UGATE(CLK_UART4, "clk_uart4", UART_GROUP_34567, 1, 1, 0x764, 0x765, 0x766, 0x767), | |
298 | D_UGATE(CLK_UART5, "clk_uart5", UART_GROUP_34567, 1, 2, 0x768, 0x769, 0x76a, 0x76b), | |
299 | D_UGATE(CLK_UART6, "clk_uart6", UART_GROUP_34567, 1, 3, 0x76c, 0x76d, 0x76e, 0x76f), | |
300 | D_UGATE(CLK_UART7, "clk_uart7", UART_GROUP_34567, 1, 4, 0x770, 0x771, 0x772, 0x773), | |
301 | }; | |
302 | ||
303 | struct r9a06g032_priv { | |
304 | struct clk_onecell_data data; | |
305 | spinlock_t lock; /* protects concurent access to gates */ | |
306 | void __iomem *reg; | |
307 | }; | |
308 | ||
309 | /* register/bit pairs are encoded as an uint16_t */ | |
310 | static void | |
311 | clk_rdesc_set(struct r9a06g032_priv *clocks, | |
312 | u16 one, unsigned int on) | |
313 | { | |
314 | u32 __iomem *reg = clocks->reg + (4 * (one >> 5)); | |
315 | u32 val = readl(reg); | |
316 | ||
317 | val = (val & ~(1U << (one & 0x1f))) | ((!!on) << (one & 0x1f)); | |
318 | writel(val, reg); | |
319 | } | |
320 | ||
321 | static int | |
322 | clk_rdesc_get(struct r9a06g032_priv *clocks, | |
323 | uint16_t one) | |
324 | { | |
325 | u32 __iomem *reg = clocks->reg + (4 * (one >> 5)); | |
326 | u32 val = readl(reg); | |
327 | ||
328 | return !!(val & (1U << (one & 0x1f))); | |
329 | } | |
330 | ||
331 | /* | |
332 | * This implements the R9A09G032 clock gate 'driver'. We cannot use the system's | |
333 | * clock gate framework as the gates on the R9A09G032 have a special enabling | |
334 | * sequence, therefore we use this little proxy. | |
335 | */ | |
336 | struct r9a06g032_clk_gate { | |
337 | struct clk_hw hw; | |
338 | struct r9a06g032_priv *clocks; | |
339 | u16 index; | |
340 | ||
341 | struct r9a06g032_gate gate; | |
342 | }; | |
343 | ||
344 | #define to_r9a06g032_gate(_hw) container_of(_hw, struct r9a06g032_clk_gate, hw) | |
345 | ||
346 | static void | |
347 | r9a06g032_clk_gate_set(struct r9a06g032_priv *clocks, | |
348 | struct r9a06g032_gate *g, int on) | |
349 | { | |
350 | unsigned long flags; | |
351 | ||
352 | WARN_ON(!g->gate); | |
353 | ||
354 | spin_lock_irqsave(&clocks->lock, flags); | |
355 | clk_rdesc_set(clocks, g->gate, on); | |
356 | /* De-assert reset */ | |
357 | if (g->reset) | |
358 | clk_rdesc_set(clocks, g->reset, 1); | |
359 | spin_unlock_irqrestore(&clocks->lock, flags); | |
360 | ||
361 | /* Hardware manual recommends 5us delay after enabling clock & reset */ | |
362 | udelay(5); | |
363 | ||
364 | /* If the peripheral is memory mapped (i.e. an AXI slave), there is an | |
365 | * associated SLVRDY bit in the System Controller that needs to be set | |
366 | * so that the FlexWAY bus fabric passes on the read/write requests. | |
367 | */ | |
368 | if (g->ready || g->midle) { | |
369 | spin_lock_irqsave(&clocks->lock, flags); | |
370 | if (g->ready) | |
371 | clk_rdesc_set(clocks, g->ready, on); | |
372 | /* Clear 'Master Idle Request' bit */ | |
373 | if (g->midle) | |
374 | clk_rdesc_set(clocks, g->midle, !on); | |
375 | spin_unlock_irqrestore(&clocks->lock, flags); | |
376 | } | |
377 | /* Note: We don't wait for FlexWAY Socket Connection signal */ | |
378 | } | |
379 | ||
380 | static int r9a06g032_clk_gate_enable(struct clk_hw *hw) | |
381 | { | |
382 | struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw); | |
383 | ||
384 | r9a06g032_clk_gate_set(g->clocks, &g->gate, 1); | |
385 | return 0; | |
386 | } | |
387 | ||
388 | static void r9a06g032_clk_gate_disable(struct clk_hw *hw) | |
389 | { | |
390 | struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw); | |
391 | ||
392 | r9a06g032_clk_gate_set(g->clocks, &g->gate, 0); | |
393 | } | |
394 | ||
395 | static int r9a06g032_clk_gate_is_enabled(struct clk_hw *hw) | |
396 | { | |
397 | struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw); | |
398 | ||
399 | /* if clock is in reset, the gate might be on, and still not 'be' on */ | |
400 | if (g->gate.reset && !clk_rdesc_get(g->clocks, g->gate.reset)) | |
401 | return 0; | |
402 | ||
403 | return clk_rdesc_get(g->clocks, g->gate.gate); | |
404 | } | |
405 | ||
406 | static const struct clk_ops r9a06g032_clk_gate_ops = { | |
407 | .enable = r9a06g032_clk_gate_enable, | |
408 | .disable = r9a06g032_clk_gate_disable, | |
409 | .is_enabled = r9a06g032_clk_gate_is_enabled, | |
410 | }; | |
411 | ||
412 | static struct clk * | |
413 | r9a06g032_register_gate(struct r9a06g032_priv *clocks, | |
414 | const char *parent_name, | |
415 | const struct r9a06g032_clkdesc *desc) | |
416 | { | |
417 | struct clk *clk; | |
418 | struct r9a06g032_clk_gate *g; | |
419 | struct clk_init_data init; | |
420 | ||
421 | g = kzalloc(sizeof(*g), GFP_KERNEL); | |
422 | if (!g) | |
423 | return NULL; | |
424 | ||
425 | init.name = desc->name; | |
426 | init.ops = &r9a06g032_clk_gate_ops; | |
ddbae665 | 427 | init.flags = CLK_SET_RATE_PARENT; |
4c3d8852 MP |
428 | init.parent_names = parent_name ? &parent_name : NULL; |
429 | init.num_parents = parent_name ? 1 : 0; | |
430 | ||
431 | g->clocks = clocks; | |
432 | g->index = desc->index; | |
433 | g->gate = desc->gate; | |
434 | g->hw.init = &init; | |
435 | ||
436 | /* | |
437 | * important here, some clocks are already in use by the CM3, we | |
438 | * have to assume they are not Linux's to play with and try to disable | |
439 | * at the end of the boot! | |
440 | */ | |
441 | if (r9a06g032_clk_gate_is_enabled(&g->hw)) { | |
442 | init.flags |= CLK_IS_CRITICAL; | |
443 | pr_debug("%s was enabled, making read-only\n", desc->name); | |
444 | } | |
445 | ||
446 | clk = clk_register(NULL, &g->hw); | |
447 | if (IS_ERR(clk)) { | |
448 | kfree(g); | |
449 | return NULL; | |
450 | } | |
451 | return clk; | |
452 | } | |
453 | ||
454 | struct r9a06g032_clk_div { | |
455 | struct clk_hw hw; | |
456 | struct r9a06g032_priv *clocks; | |
457 | u16 index; | |
458 | u16 reg; | |
459 | u16 min, max; | |
460 | u8 table_size; | |
461 | u16 table[8]; /* we know there are no more than 8 */ | |
462 | }; | |
463 | ||
464 | #define to_r9a06g032_div(_hw) \ | |
465 | container_of(_hw, struct r9a06g032_clk_div, hw) | |
466 | ||
467 | static unsigned long | |
468 | r9a06g032_div_recalc_rate(struct clk_hw *hw, | |
469 | unsigned long parent_rate) | |
470 | { | |
471 | struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw); | |
472 | u32 __iomem *reg = clk->clocks->reg + (4 * clk->reg); | |
473 | u32 div = readl(reg); | |
474 | ||
475 | if (div < clk->min) | |
476 | div = clk->min; | |
477 | else if (div > clk->max) | |
478 | div = clk->max; | |
479 | return DIV_ROUND_UP(parent_rate, div); | |
480 | } | |
481 | ||
482 | /* | |
483 | * Attempts to find a value that is in range of min,max, | |
484 | * and if a table of set dividers was specified for this | |
485 | * register, try to find the fixed divider that is the closest | |
486 | * to the target frequency | |
487 | */ | |
488 | static long | |
489 | r9a06g032_div_clamp_div(struct r9a06g032_clk_div *clk, | |
490 | unsigned long rate, unsigned long prate) | |
491 | { | |
492 | /* + 1 to cope with rates that have the remainder dropped */ | |
493 | u32 div = DIV_ROUND_UP(prate, rate + 1); | |
494 | int i; | |
495 | ||
496 | if (div <= clk->min) | |
497 | return clk->min; | |
498 | if (div >= clk->max) | |
499 | return clk->max; | |
500 | ||
501 | for (i = 0; clk->table_size && i < clk->table_size - 1; i++) { | |
502 | if (div >= clk->table[i] && div <= clk->table[i + 1]) { | |
503 | unsigned long m = rate - | |
504 | DIV_ROUND_UP(prate, clk->table[i]); | |
505 | unsigned long p = | |
506 | DIV_ROUND_UP(prate, clk->table[i + 1]) - | |
507 | rate; | |
508 | /* | |
509 | * select the divider that generates | |
510 | * the value closest to the ideal frequency | |
511 | */ | |
512 | div = p >= m ? clk->table[i] : clk->table[i + 1]; | |
513 | return div; | |
514 | } | |
515 | } | |
516 | return div; | |
517 | } | |
518 | ||
519 | static long | |
520 | r9a06g032_div_round_rate(struct clk_hw *hw, | |
521 | unsigned long rate, unsigned long *prate) | |
522 | { | |
523 | struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw); | |
524 | u32 div = DIV_ROUND_UP(*prate, rate); | |
525 | ||
526 | pr_devel("%s %pC %ld (prate %ld) (wanted div %u)\n", __func__, | |
527 | hw->clk, rate, *prate, div); | |
528 | pr_devel(" min %d (%ld) max %d (%ld)\n", | |
529 | clk->min, DIV_ROUND_UP(*prate, clk->min), | |
530 | clk->max, DIV_ROUND_UP(*prate, clk->max)); | |
531 | ||
532 | div = r9a06g032_div_clamp_div(clk, rate, *prate); | |
533 | /* | |
534 | * this is a hack. Currently the serial driver asks for a clock rate | |
535 | * that is 16 times the baud rate -- and that is wildly outside the | |
536 | * range of the UART divider, somehow there is no provision for that | |
537 | * case of 'let the divider as is if outside range'. | |
538 | * The serial driver *shouldn't* play with these clocks anyway, there's | |
539 | * several uarts attached to this divider, and changing this impacts | |
540 | * everyone. | |
541 | */ | |
ee02950d PE |
542 | if (clk->index == R9A06G032_DIV_UART || |
543 | clk->index == R9A06G032_DIV_P2_PG) { | |
4c3d8852 MP |
544 | pr_devel("%s div uart hack!\n", __func__); |
545 | return clk_get_rate(hw->clk); | |
546 | } | |
547 | pr_devel("%s %pC %ld / %u = %ld\n", __func__, hw->clk, | |
548 | *prate, div, DIV_ROUND_UP(*prate, div)); | |
549 | return DIV_ROUND_UP(*prate, div); | |
550 | } | |
551 | ||
552 | static int | |
553 | r9a06g032_div_set_rate(struct clk_hw *hw, | |
554 | unsigned long rate, unsigned long parent_rate) | |
555 | { | |
556 | struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw); | |
557 | /* + 1 to cope with rates that have the remainder dropped */ | |
558 | u32 div = DIV_ROUND_UP(parent_rate, rate + 1); | |
559 | u32 __iomem *reg = clk->clocks->reg + (4 * clk->reg); | |
560 | ||
561 | pr_devel("%s %pC rate %ld parent %ld div %d\n", __func__, hw->clk, | |
562 | rate, parent_rate, div); | |
563 | ||
564 | /* | |
565 | * Need to write the bit 31 with the divider value to | |
566 | * latch it. Technically we should wait until it has been | |
567 | * cleared too. | |
568 | * TODO: Find whether this callback is sleepable, in case | |
569 | * the hardware /does/ require some sort of spinloop here. | |
570 | */ | |
571 | writel(div | BIT(31), reg); | |
572 | ||
573 | return 0; | |
574 | } | |
575 | ||
576 | static const struct clk_ops r9a06g032_clk_div_ops = { | |
577 | .recalc_rate = r9a06g032_div_recalc_rate, | |
578 | .round_rate = r9a06g032_div_round_rate, | |
579 | .set_rate = r9a06g032_div_set_rate, | |
580 | }; | |
581 | ||
582 | static struct clk * | |
583 | r9a06g032_register_div(struct r9a06g032_priv *clocks, | |
584 | const char *parent_name, | |
585 | const struct r9a06g032_clkdesc *desc) | |
586 | { | |
587 | struct r9a06g032_clk_div *div; | |
588 | struct clk *clk; | |
589 | struct clk_init_data init; | |
590 | unsigned int i; | |
591 | ||
592 | div = kzalloc(sizeof(*div), GFP_KERNEL); | |
593 | if (!div) | |
594 | return NULL; | |
595 | ||
596 | init.name = desc->name; | |
597 | init.ops = &r9a06g032_clk_div_ops; | |
ddbae665 | 598 | init.flags = CLK_SET_RATE_PARENT; |
4c3d8852 MP |
599 | init.parent_names = parent_name ? &parent_name : NULL; |
600 | init.num_parents = parent_name ? 1 : 0; | |
601 | ||
602 | div->clocks = clocks; | |
603 | div->index = desc->index; | |
604 | div->reg = desc->reg; | |
605 | div->hw.init = &init; | |
606 | div->min = desc->div_min; | |
607 | div->max = desc->div_max; | |
608 | /* populate (optional) divider table fixed values */ | |
609 | for (i = 0; i < ARRAY_SIZE(div->table) && | |
610 | i < ARRAY_SIZE(desc->div_table) && desc->div_table[i]; i++) { | |
611 | div->table[div->table_size++] = desc->div_table[i]; | |
612 | } | |
613 | ||
614 | clk = clk_register(NULL, &div->hw); | |
615 | if (IS_ERR(clk)) { | |
616 | kfree(div); | |
617 | return NULL; | |
618 | } | |
619 | return clk; | |
620 | } | |
621 | ||
622 | /* | |
623 | * This clock provider handles the case of the R9A06G032 where you have | |
624 | * peripherals that have two potential clock source and two gates, one for | |
625 | * each of the clock source - the used clock source (for all sub clocks) | |
626 | * is selected by a single bit. | |
627 | * That single bit affects all sub-clocks, and therefore needs to change the | |
628 | * active gate (and turn the others off) and force a recalculation of the rates. | |
629 | * | |
630 | * This implements two clock providers, one 'bitselect' that | |
631 | * handles the switch between both parents, and another 'dualgate' | |
632 | * that knows which gate to poke at, depending on the parent's bit position. | |
633 | */ | |
634 | struct r9a06g032_clk_bitsel { | |
635 | struct clk_hw hw; | |
636 | struct r9a06g032_priv *clocks; | |
637 | u16 index; | |
638 | u16 selector; /* selector register + bit */ | |
639 | }; | |
640 | ||
641 | #define to_clk_bitselect(_hw) \ | |
642 | container_of(_hw, struct r9a06g032_clk_bitsel, hw) | |
643 | ||
644 | static u8 r9a06g032_clk_mux_get_parent(struct clk_hw *hw) | |
645 | { | |
646 | struct r9a06g032_clk_bitsel *set = to_clk_bitselect(hw); | |
647 | ||
648 | return clk_rdesc_get(set->clocks, set->selector); | |
649 | } | |
650 | ||
651 | static int r9a06g032_clk_mux_set_parent(struct clk_hw *hw, u8 index) | |
652 | { | |
653 | struct r9a06g032_clk_bitsel *set = to_clk_bitselect(hw); | |
654 | ||
655 | /* a single bit in the register selects one of two parent clocks */ | |
656 | clk_rdesc_set(set->clocks, set->selector, !!index); | |
657 | ||
658 | return 0; | |
659 | } | |
660 | ||
661 | static const struct clk_ops clk_bitselect_ops = { | |
662 | .get_parent = r9a06g032_clk_mux_get_parent, | |
663 | .set_parent = r9a06g032_clk_mux_set_parent, | |
664 | }; | |
665 | ||
666 | static struct clk * | |
667 | r9a06g032_register_bitsel(struct r9a06g032_priv *clocks, | |
668 | const char *parent_name, | |
669 | const struct r9a06g032_clkdesc *desc) | |
670 | { | |
671 | struct clk *clk; | |
672 | struct r9a06g032_clk_bitsel *g; | |
673 | struct clk_init_data init; | |
674 | const char *names[2]; | |
675 | ||
676 | /* allocate the gate */ | |
677 | g = kzalloc(sizeof(*g), GFP_KERNEL); | |
678 | if (!g) | |
679 | return NULL; | |
680 | ||
681 | names[0] = parent_name; | |
682 | names[1] = "clk_pll_usb"; | |
683 | ||
684 | init.name = desc->name; | |
685 | init.ops = &clk_bitselect_ops; | |
ddbae665 | 686 | init.flags = CLK_SET_RATE_PARENT; |
4c3d8852 MP |
687 | init.parent_names = names; |
688 | init.num_parents = 2; | |
689 | ||
690 | g->clocks = clocks; | |
691 | g->index = desc->index; | |
692 | g->selector = desc->dual.sel; | |
693 | g->hw.init = &init; | |
694 | ||
695 | clk = clk_register(NULL, &g->hw); | |
696 | if (IS_ERR(clk)) { | |
697 | kfree(g); | |
698 | return NULL; | |
699 | } | |
700 | return clk; | |
701 | } | |
702 | ||
703 | struct r9a06g032_clk_dualgate { | |
704 | struct clk_hw hw; | |
705 | struct r9a06g032_priv *clocks; | |
706 | u16 index; | |
707 | u16 selector; /* selector register + bit */ | |
708 | struct r9a06g032_gate gate[2]; | |
709 | }; | |
710 | ||
711 | #define to_clk_dualgate(_hw) \ | |
712 | container_of(_hw, struct r9a06g032_clk_dualgate, hw) | |
713 | ||
714 | static int | |
715 | r9a06g032_clk_dualgate_setenable(struct r9a06g032_clk_dualgate *g, int enable) | |
716 | { | |
717 | u8 sel_bit = clk_rdesc_get(g->clocks, g->selector); | |
718 | ||
719 | /* we always turn off the 'other' gate, regardless */ | |
720 | r9a06g032_clk_gate_set(g->clocks, &g->gate[!sel_bit], 0); | |
721 | r9a06g032_clk_gate_set(g->clocks, &g->gate[sel_bit], enable); | |
722 | ||
723 | return 0; | |
724 | } | |
725 | ||
726 | static int r9a06g032_clk_dualgate_enable(struct clk_hw *hw) | |
727 | { | |
728 | struct r9a06g032_clk_dualgate *gate = to_clk_dualgate(hw); | |
729 | ||
730 | r9a06g032_clk_dualgate_setenable(gate, 1); | |
731 | ||
732 | return 0; | |
733 | } | |
734 | ||
735 | static void r9a06g032_clk_dualgate_disable(struct clk_hw *hw) | |
736 | { | |
737 | struct r9a06g032_clk_dualgate *gate = to_clk_dualgate(hw); | |
738 | ||
739 | r9a06g032_clk_dualgate_setenable(gate, 0); | |
740 | } | |
741 | ||
742 | static int r9a06g032_clk_dualgate_is_enabled(struct clk_hw *hw) | |
743 | { | |
744 | struct r9a06g032_clk_dualgate *g = to_clk_dualgate(hw); | |
745 | u8 sel_bit = clk_rdesc_get(g->clocks, g->selector); | |
746 | ||
747 | return clk_rdesc_get(g->clocks, g->gate[sel_bit].gate); | |
748 | } | |
749 | ||
750 | static const struct clk_ops r9a06g032_clk_dualgate_ops = { | |
751 | .enable = r9a06g032_clk_dualgate_enable, | |
752 | .disable = r9a06g032_clk_dualgate_disable, | |
753 | .is_enabled = r9a06g032_clk_dualgate_is_enabled, | |
754 | }; | |
755 | ||
756 | static struct clk * | |
757 | r9a06g032_register_dualgate(struct r9a06g032_priv *clocks, | |
758 | const char *parent_name, | |
759 | const struct r9a06g032_clkdesc *desc, | |
760 | uint16_t sel) | |
761 | { | |
762 | struct r9a06g032_clk_dualgate *g; | |
763 | struct clk *clk; | |
764 | struct clk_init_data init; | |
765 | ||
766 | /* allocate the gate */ | |
767 | g = kzalloc(sizeof(*g), GFP_KERNEL); | |
768 | if (!g) | |
769 | return NULL; | |
770 | g->clocks = clocks; | |
771 | g->index = desc->index; | |
772 | g->selector = sel; | |
773 | g->gate[0].gate = desc->dual.g1; | |
774 | g->gate[0].reset = desc->dual.r1; | |
775 | g->gate[1].gate = desc->dual.g2; | |
776 | g->gate[1].reset = desc->dual.r2; | |
777 | ||
778 | init.name = desc->name; | |
779 | init.ops = &r9a06g032_clk_dualgate_ops; | |
ddbae665 | 780 | init.flags = CLK_SET_RATE_PARENT; |
4c3d8852 MP |
781 | init.parent_names = &parent_name; |
782 | init.num_parents = 1; | |
783 | g->hw.init = &init; | |
784 | /* | |
785 | * important here, some clocks are already in use by the CM3, we | |
786 | * have to assume they are not Linux's to play with and try to disable | |
787 | * at the end of the boot! | |
788 | */ | |
789 | if (r9a06g032_clk_dualgate_is_enabled(&g->hw)) { | |
790 | init.flags |= CLK_IS_CRITICAL; | |
791 | pr_debug("%s was enabled, making read-only\n", desc->name); | |
792 | } | |
793 | ||
794 | clk = clk_register(NULL, &g->hw); | |
795 | if (IS_ERR(clk)) { | |
796 | kfree(g); | |
797 | return NULL; | |
798 | } | |
799 | return clk; | |
800 | } | |
801 | ||
802 | static void r9a06g032_clocks_del_clk_provider(void *data) | |
803 | { | |
804 | of_clk_del_provider(data); | |
805 | } | |
806 | ||
807 | static int __init r9a06g032_clocks_probe(struct platform_device *pdev) | |
808 | { | |
809 | struct device *dev = &pdev->dev; | |
810 | struct device_node *np = dev->of_node; | |
811 | struct r9a06g032_priv *clocks; | |
812 | struct clk **clks; | |
813 | struct clk *mclk; | |
814 | unsigned int i; | |
815 | u16 uart_group_sel[2]; | |
816 | int error; | |
817 | ||
818 | clocks = devm_kzalloc(dev, sizeof(*clocks), GFP_KERNEL); | |
819 | clks = devm_kcalloc(dev, R9A06G032_CLOCK_COUNT, sizeof(struct clk *), | |
820 | GFP_KERNEL); | |
821 | if (!clocks || !clks) | |
822 | return -ENOMEM; | |
823 | ||
824 | spin_lock_init(&clocks->lock); | |
825 | ||
826 | clocks->data.clks = clks; | |
827 | clocks->data.clk_num = R9A06G032_CLOCK_COUNT; | |
828 | ||
829 | mclk = devm_clk_get(dev, "mclk"); | |
830 | if (IS_ERR(mclk)) | |
831 | return PTR_ERR(mclk); | |
832 | ||
833 | clocks->reg = of_iomap(np, 0); | |
834 | if (WARN_ON(!clocks->reg)) | |
835 | return -ENOMEM; | |
836 | for (i = 0; i < ARRAY_SIZE(r9a06g032_clocks); ++i) { | |
837 | const struct r9a06g032_clkdesc *d = &r9a06g032_clocks[i]; | |
838 | const char *parent_name = d->source ? | |
839 | __clk_get_name(clocks->data.clks[d->source - 1]) : | |
840 | __clk_get_name(mclk); | |
841 | struct clk *clk = NULL; | |
842 | ||
843 | switch (d->type) { | |
844 | case K_FFC: | |
845 | clk = clk_register_fixed_factor(NULL, d->name, | |
846 | parent_name, 0, | |
847 | d->mul, d->div); | |
848 | break; | |
849 | case K_GATE: | |
850 | clk = r9a06g032_register_gate(clocks, parent_name, d); | |
851 | break; | |
852 | case K_DIV: | |
853 | clk = r9a06g032_register_div(clocks, parent_name, d); | |
854 | break; | |
855 | case K_BITSEL: | |
856 | /* keep that selector register around */ | |
857 | uart_group_sel[d->dual.group] = d->dual.sel; | |
858 | clk = r9a06g032_register_bitsel(clocks, parent_name, d); | |
859 | break; | |
860 | case K_DUALGATE: | |
861 | clk = r9a06g032_register_dualgate(clocks, parent_name, | |
862 | d, | |
863 | uart_group_sel[d->dual.group]); | |
864 | break; | |
865 | } | |
866 | clocks->data.clks[d->index] = clk; | |
867 | } | |
868 | error = of_clk_add_provider(np, of_clk_src_onecell_get, &clocks->data); | |
869 | if (error) | |
870 | return error; | |
871 | ||
872 | return devm_add_action_or_reset(dev, | |
873 | r9a06g032_clocks_del_clk_provider, np); | |
874 | } | |
875 | ||
876 | static const struct of_device_id r9a06g032_match[] = { | |
877 | { .compatible = "renesas,r9a06g032-sysctrl" }, | |
878 | { } | |
879 | }; | |
880 | ||
881 | static struct platform_driver r9a06g032_clock_driver = { | |
882 | .driver = { | |
883 | .name = "renesas,r9a06g032-sysctrl", | |
884 | .of_match_table = r9a06g032_match, | |
885 | }, | |
886 | }; | |
887 | ||
888 | static int __init r9a06g032_clocks_init(void) | |
889 | { | |
890 | return platform_driver_probe(&r9a06g032_clock_driver, | |
891 | r9a06g032_clocks_probe); | |
892 | } | |
893 | ||
894 | subsys_initcall(r9a06g032_clocks_init); |