]>
Commit | Line | Data |
---|---|---|
6693e219 QD |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Amlogic Meson-AXG Clock Controller Driver | |
4 | * | |
5 | * Copyright (c) 2016 Baylibre SAS. | |
6 | * Author: Michael Turquette <mturquette@baylibre.com> | |
7 | * | |
8 | * Copyright (c) 2018 Amlogic, inc. | |
9 | * Author: Qiufang Dai <qiufang.dai@amlogic.com> | |
10 | */ | |
11 | #include <linux/clk-provider.h> | |
12 | #include <linux/platform_device.h> | |
13 | #include <linux/reset-controller.h> | |
14 | #include <linux/mfd/syscon.h> | |
6693e219 QD |
15 | #include "meson-aoclk.h" |
16 | #include "axg-aoclk.h" | |
17 | ||
889c2b7e JB |
18 | #include "clk-regmap.h" |
19 | #include "clk-dualdiv.h" | |
20 | ||
439a6bb5 JB |
21 | #define IN_PREFIX "ao-in-" |
22 | ||
172e9534 JB |
23 | /* |
24 | * AO Configuration Clock registers offsets | |
25 | * Register offsets from the data sheet must be multiplied by 4. | |
26 | */ | |
27 | #define AO_RTI_PWR_CNTL_REG1 0x0C | |
28 | #define AO_RTI_PWR_CNTL_REG0 0x10 | |
29 | #define AO_RTI_GEN_CNTL_REG0 0x40 | |
30 | #define AO_OSCIN_CNTL 0x58 | |
31 | #define AO_CRT_CLK_CNTL1 0x68 | |
32 | #define AO_SAR_CLK 0x90 | |
33 | #define AO_RTC_ALT_CLK_CNTL0 0x94 | |
34 | #define AO_RTC_ALT_CLK_CNTL1 0x98 | |
35 | ||
6693e219 QD |
36 | #define AXG_AO_GATE(_name, _bit) \ |
37 | static struct clk_regmap axg_aoclk_##_name = { \ | |
38 | .data = &(struct clk_regmap_gate_data) { \ | |
39 | .offset = (AO_RTI_GEN_CNTL_REG0), \ | |
40 | .bit_idx = (_bit), \ | |
41 | }, \ | |
42 | .hw.init = &(struct clk_init_data) { \ | |
43 | .name = "axg_ao_" #_name, \ | |
44 | .ops = &clk_regmap_gate_ops, \ | |
439a6bb5 | 45 | .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \ |
6693e219 QD |
46 | .num_parents = 1, \ |
47 | .flags = CLK_IGNORE_UNUSED, \ | |
48 | }, \ | |
49 | } | |
50 | ||
51 | AXG_AO_GATE(remote, 0); | |
52 | AXG_AO_GATE(i2c_master, 1); | |
53 | AXG_AO_GATE(i2c_slave, 2); | |
54 | AXG_AO_GATE(uart1, 3); | |
55 | AXG_AO_GATE(uart2, 5); | |
56 | AXG_AO_GATE(ir_blaster, 6); | |
57 | AXG_AO_GATE(saradc, 7); | |
58 | ||
172e9534 JB |
59 | static struct clk_regmap axg_aoclk_cts_oscin = { |
60 | .data = &(struct clk_regmap_gate_data){ | |
61 | .offset = AO_RTI_PWR_CNTL_REG0, | |
62 | .bit_idx = 14, | |
63 | }, | |
64 | .hw.init = &(struct clk_init_data){ | |
65 | .name = "cts_oscin", | |
66 | .ops = &clk_regmap_gate_ro_ops, | |
439a6bb5 | 67 | .parent_names = (const char *[]){ IN_PREFIX "xtal" }, |
172e9534 JB |
68 | .num_parents = 1, |
69 | }, | |
70 | }; | |
71 | ||
72 | static struct clk_regmap axg_aoclk_32k_pre = { | |
73 | .data = &(struct clk_regmap_gate_data){ | |
74 | .offset = AO_RTC_ALT_CLK_CNTL0, | |
75 | .bit_idx = 31, | |
76 | }, | |
77 | .hw.init = &(struct clk_init_data){ | |
78 | .name = "axg_ao_32k_pre", | |
79 | .ops = &clk_regmap_gate_ops, | |
80 | .parent_names = (const char *[]){ "cts_oscin" }, | |
81 | .num_parents = 1, | |
82 | }, | |
83 | }; | |
84 | ||
85 | static const struct meson_clk_dualdiv_param axg_32k_div_table[] = { | |
86 | { | |
87 | .dual = 1, | |
88 | .n1 = 733, | |
89 | .m1 = 8, | |
90 | .n2 = 732, | |
91 | .m2 = 11, | |
92 | }, {} | |
93 | }; | |
94 | ||
95 | static struct clk_regmap axg_aoclk_32k_div = { | |
96 | .data = &(struct meson_clk_dualdiv_data){ | |
97 | .n1 = { | |
98 | .reg_off = AO_RTC_ALT_CLK_CNTL0, | |
99 | .shift = 0, | |
100 | .width = 12, | |
101 | }, | |
102 | .n2 = { | |
103 | .reg_off = AO_RTC_ALT_CLK_CNTL0, | |
104 | .shift = 12, | |
105 | .width = 12, | |
106 | }, | |
107 | .m1 = { | |
108 | .reg_off = AO_RTC_ALT_CLK_CNTL1, | |
109 | .shift = 0, | |
110 | .width = 12, | |
111 | }, | |
112 | .m2 = { | |
113 | .reg_off = AO_RTC_ALT_CLK_CNTL1, | |
114 | .shift = 12, | |
115 | .width = 12, | |
116 | }, | |
117 | .dual = { | |
118 | .reg_off = AO_RTC_ALT_CLK_CNTL0, | |
119 | .shift = 28, | |
120 | .width = 1, | |
121 | }, | |
122 | .table = axg_32k_div_table, | |
123 | }, | |
124 | .hw.init = &(struct clk_init_data){ | |
125 | .name = "axg_ao_32k_div", | |
126 | .ops = &meson_clk_dualdiv_ops, | |
127 | .parent_names = (const char *[]){ "axg_ao_32k_pre" }, | |
128 | .num_parents = 1, | |
129 | }, | |
130 | }; | |
131 | ||
132 | static struct clk_regmap axg_aoclk_32k_sel = { | |
133 | .data = &(struct clk_regmap_mux_data) { | |
134 | .offset = AO_RTC_ALT_CLK_CNTL1, | |
135 | .mask = 0x1, | |
136 | .shift = 24, | |
137 | .flags = CLK_MUX_ROUND_CLOSEST, | |
138 | }, | |
139 | .hw.init = &(struct clk_init_data){ | |
140 | .name = "axg_ao_32k_sel", | |
141 | .ops = &clk_regmap_mux_ops, | |
142 | .parent_names = (const char *[]){ "axg_ao_32k_div", | |
143 | "axg_ao_32k_pre" }, | |
144 | .num_parents = 2, | |
145 | .flags = CLK_SET_RATE_PARENT, | |
146 | }, | |
147 | }; | |
148 | ||
149 | static struct clk_regmap axg_aoclk_32k = { | |
150 | .data = &(struct clk_regmap_gate_data){ | |
151 | .offset = AO_RTC_ALT_CLK_CNTL0, | |
152 | .bit_idx = 30, | |
153 | }, | |
154 | .hw.init = &(struct clk_init_data){ | |
155 | .name = "axg_ao_32k", | |
156 | .ops = &clk_regmap_gate_ops, | |
157 | .parent_names = (const char *[]){ "axg_ao_32k_sel" }, | |
158 | .num_parents = 1, | |
159 | .flags = CLK_SET_RATE_PARENT, | |
160 | }, | |
161 | }; | |
162 | ||
163 | static struct clk_regmap axg_aoclk_cts_rtc_oscin = { | |
164 | .data = &(struct clk_regmap_mux_data) { | |
165 | .offset = AO_RTI_PWR_CNTL_REG0, | |
166 | .mask = 0x1, | |
167 | .shift = 10, | |
168 | .flags = CLK_MUX_ROUND_CLOSEST, | |
169 | }, | |
170 | .hw.init = &(struct clk_init_data){ | |
171 | .name = "axg_ao_cts_rtc_oscin", | |
172 | .ops = &clk_regmap_mux_ops, | |
173 | .parent_names = (const char *[]){ "axg_ao_32k", | |
439a6bb5 | 174 | IN_PREFIX "ext_32k-0" }, |
172e9534 JB |
175 | .num_parents = 2, |
176 | .flags = CLK_SET_RATE_PARENT, | |
177 | }, | |
178 | }; | |
179 | ||
6693e219 QD |
180 | static struct clk_regmap axg_aoclk_clk81 = { |
181 | .data = &(struct clk_regmap_mux_data) { | |
182 | .offset = AO_RTI_PWR_CNTL_REG0, | |
183 | .mask = 0x1, | |
184 | .shift = 8, | |
172e9534 | 185 | .flags = CLK_MUX_ROUND_CLOSEST, |
6693e219 QD |
186 | }, |
187 | .hw.init = &(struct clk_init_data){ | |
188 | .name = "axg_ao_clk81", | |
189 | .ops = &clk_regmap_mux_ro_ops, | |
439a6bb5 | 190 | .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk", |
172e9534 | 191 | "axg_ao_cts_rtc_oscin"}, |
6693e219 | 192 | .num_parents = 2, |
172e9534 | 193 | .flags = CLK_SET_RATE_PARENT, |
6693e219 QD |
194 | }, |
195 | }; | |
196 | ||
197 | static struct clk_regmap axg_aoclk_saradc_mux = { | |
198 | .data = &(struct clk_regmap_mux_data) { | |
199 | .offset = AO_SAR_CLK, | |
200 | .mask = 0x3, | |
201 | .shift = 9, | |
202 | }, | |
203 | .hw.init = &(struct clk_init_data){ | |
204 | .name = "axg_ao_saradc_mux", | |
205 | .ops = &clk_regmap_mux_ops, | |
439a6bb5 JB |
206 | .parent_names = (const char *[]){ IN_PREFIX "xtal", |
207 | "axg_ao_clk81" }, | |
6693e219 QD |
208 | .num_parents = 2, |
209 | }, | |
210 | }; | |
211 | ||
212 | static struct clk_regmap axg_aoclk_saradc_div = { | |
213 | .data = &(struct clk_regmap_div_data) { | |
214 | .offset = AO_SAR_CLK, | |
215 | .shift = 0, | |
216 | .width = 8, | |
217 | }, | |
218 | .hw.init = &(struct clk_init_data){ | |
219 | .name = "axg_ao_saradc_div", | |
220 | .ops = &clk_regmap_divider_ops, | |
221 | .parent_names = (const char *[]){ "axg_ao_saradc_mux" }, | |
222 | .num_parents = 1, | |
223 | .flags = CLK_SET_RATE_PARENT, | |
224 | }, | |
225 | }; | |
226 | ||
227 | static struct clk_regmap axg_aoclk_saradc_gate = { | |
228 | .data = &(struct clk_regmap_gate_data) { | |
229 | .offset = AO_SAR_CLK, | |
230 | .bit_idx = 8, | |
231 | }, | |
232 | .hw.init = &(struct clk_init_data){ | |
233 | .name = "axg_ao_saradc_gate", | |
234 | .ops = &clk_regmap_gate_ops, | |
235 | .parent_names = (const char *[]){ "axg_ao_saradc_div" }, | |
236 | .num_parents = 1, | |
237 | .flags = CLK_SET_RATE_PARENT, | |
238 | }, | |
239 | }; | |
240 | ||
241 | static const unsigned int axg_aoclk_reset[] = { | |
242 | [RESET_AO_REMOTE] = 16, | |
243 | [RESET_AO_I2C_MASTER] = 18, | |
244 | [RESET_AO_I2C_SLAVE] = 19, | |
245 | [RESET_AO_UART1] = 17, | |
246 | [RESET_AO_UART2] = 22, | |
247 | [RESET_AO_IR_BLASTER] = 23, | |
248 | }; | |
249 | ||
250 | static struct clk_regmap *axg_aoclk_regmap[] = { | |
172e9534 JB |
251 | &axg_aoclk_remote, |
252 | &axg_aoclk_i2c_master, | |
253 | &axg_aoclk_i2c_slave, | |
254 | &axg_aoclk_uart1, | |
255 | &axg_aoclk_uart2, | |
256 | &axg_aoclk_ir_blaster, | |
257 | &axg_aoclk_saradc, | |
258 | &axg_aoclk_cts_oscin, | |
259 | &axg_aoclk_32k_pre, | |
260 | &axg_aoclk_32k_div, | |
261 | &axg_aoclk_32k_sel, | |
262 | &axg_aoclk_32k, | |
263 | &axg_aoclk_cts_rtc_oscin, | |
264 | &axg_aoclk_clk81, | |
265 | &axg_aoclk_saradc_mux, | |
266 | &axg_aoclk_saradc_div, | |
267 | &axg_aoclk_saradc_gate, | |
6693e219 QD |
268 | }; |
269 | ||
270 | static const struct clk_hw_onecell_data axg_aoclk_onecell_data = { | |
271 | .hws = { | |
272 | [CLKID_AO_REMOTE] = &axg_aoclk_remote.hw, | |
273 | [CLKID_AO_I2C_MASTER] = &axg_aoclk_i2c_master.hw, | |
274 | [CLKID_AO_I2C_SLAVE] = &axg_aoclk_i2c_slave.hw, | |
275 | [CLKID_AO_UART1] = &axg_aoclk_uart1.hw, | |
276 | [CLKID_AO_UART2] = &axg_aoclk_uart2.hw, | |
277 | [CLKID_AO_IR_BLASTER] = &axg_aoclk_ir_blaster.hw, | |
278 | [CLKID_AO_SAR_ADC] = &axg_aoclk_saradc.hw, | |
279 | [CLKID_AO_CLK81] = &axg_aoclk_clk81.hw, | |
280 | [CLKID_AO_SAR_ADC_SEL] = &axg_aoclk_saradc_mux.hw, | |
281 | [CLKID_AO_SAR_ADC_DIV] = &axg_aoclk_saradc_div.hw, | |
282 | [CLKID_AO_SAR_ADC_CLK] = &axg_aoclk_saradc_gate.hw, | |
172e9534 JB |
283 | [CLKID_AO_CTS_OSCIN] = &axg_aoclk_cts_oscin.hw, |
284 | [CLKID_AO_32K_PRE] = &axg_aoclk_32k_pre.hw, | |
285 | [CLKID_AO_32K_DIV] = &axg_aoclk_32k_div.hw, | |
286 | [CLKID_AO_32K_SEL] = &axg_aoclk_32k_sel.hw, | |
287 | [CLKID_AO_32K] = &axg_aoclk_32k.hw, | |
288 | [CLKID_AO_CTS_RTC_OSCIN] = &axg_aoclk_cts_rtc_oscin.hw, | |
6693e219 QD |
289 | }, |
290 | .num = NR_CLKS, | |
291 | }; | |
292 | ||
439a6bb5 JB |
293 | static const struct meson_aoclk_input axg_aoclk_inputs[] = { |
294 | { .name = "xtal", .required = true }, | |
295 | { .name = "mpeg-clk", .required = true }, | |
296 | { .name = "ext-32k-0", .required = false }, | |
297 | }; | |
298 | ||
6693e219 QD |
299 | static const struct meson_aoclk_data axg_aoclkc_data = { |
300 | .reset_reg = AO_RTI_GEN_CNTL_REG0, | |
301 | .num_reset = ARRAY_SIZE(axg_aoclk_reset), | |
302 | .reset = axg_aoclk_reset, | |
303 | .num_clks = ARRAY_SIZE(axg_aoclk_regmap), | |
304 | .clks = axg_aoclk_regmap, | |
305 | .hw_data = &axg_aoclk_onecell_data, | |
439a6bb5 JB |
306 | .inputs = axg_aoclk_inputs, |
307 | .num_inputs = ARRAY_SIZE(axg_aoclk_inputs), | |
308 | .input_prefix = IN_PREFIX, | |
6693e219 QD |
309 | }; |
310 | ||
311 | static const struct of_device_id axg_aoclkc_match_table[] = { | |
312 | { | |
313 | .compatible = "amlogic,meson-axg-aoclkc", | |
314 | .data = &axg_aoclkc_data, | |
315 | }, | |
316 | { } | |
317 | }; | |
318 | ||
319 | static struct platform_driver axg_aoclkc_driver = { | |
320 | .probe = meson_aoclkc_probe, | |
321 | .driver = { | |
322 | .name = "axg-aoclkc", | |
323 | .of_match_table = axg_aoclkc_match_table, | |
324 | }, | |
325 | }; | |
326 | ||
327 | builtin_platform_driver(axg_aoclkc_driver); |