GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / clk / meson / g12a-aoclk.c
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) 2019 Baylibre SAS.
9  * Author: Neil Armstrong <narmstrong@baylibre.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>
15 #include <linux/module.h>
16 #include "meson-aoclk.h"
17
18 #include "clk-regmap.h"
19 #include "clk-dualdiv.h"
20
21 #include <dt-bindings/clock/g12a-aoclkc.h>
22 #include <dt-bindings/reset/g12a-aoclkc.h>
23
24 /*
25  * AO Configuration Clock registers offsets
26  * Register offsets from the data sheet must be multiplied by 4.
27  */
28 #define AO_RTI_STATUS_REG3      0x0C
29 #define AO_RTI_PWR_CNTL_REG0    0x10
30 #define AO_RTI_GEN_CNTL_REG0    0x40
31 #define AO_CLK_GATE0            0x4c
32 #define AO_CLK_GATE0_SP         0x50
33 #define AO_OSCIN_CNTL           0x58
34 #define AO_CEC_CLK_CNTL_REG0    0x74
35 #define AO_CEC_CLK_CNTL_REG1    0x78
36 #define AO_SAR_CLK              0x90
37 #define AO_RTC_ALT_CLK_CNTL0    0x94
38 #define AO_RTC_ALT_CLK_CNTL1    0x98
39
40 /*
41  * Like every other peripheral clock gate in Amlogic Clock drivers,
42  * we are using CLK_IGNORE_UNUSED here, so we keep the state of the
43  * bootloader. The goal is to remove this flag at some point.
44  * Actually removing it will require some extensive test to be done safely.
45  */
46 #define AXG_AO_GATE(_name, _reg, _bit)                                  \
47 static struct clk_regmap g12a_aoclk_##_name = {                         \
48         .data = &(struct clk_regmap_gate_data) {                        \
49                 .offset = (_reg),                                       \
50                 .bit_idx = (_bit),                                      \
51         },                                                              \
52         .hw.init = &(struct clk_init_data) {                            \
53                 .name =  "g12a_ao_" #_name,                             \
54                 .ops = &clk_regmap_gate_ops,                            \
55                 .parent_data = &(const struct clk_parent_data) {        \
56                         .fw_name = "mpeg-clk",                          \
57                 },                                                      \
58                 .num_parents = 1,                                       \
59                 .flags = CLK_IGNORE_UNUSED,                             \
60         },                                                              \
61 }
62
63 AXG_AO_GATE(ahb, AO_CLK_GATE0, 0);
64 AXG_AO_GATE(ir_in, AO_CLK_GATE0, 1);
65 AXG_AO_GATE(i2c_m0, AO_CLK_GATE0, 2);
66 AXG_AO_GATE(i2c_s0, AO_CLK_GATE0, 3);
67 AXG_AO_GATE(uart, AO_CLK_GATE0, 4);
68 AXG_AO_GATE(prod_i2c, AO_CLK_GATE0, 5);
69 AXG_AO_GATE(uart2, AO_CLK_GATE0, 6);
70 AXG_AO_GATE(ir_out, AO_CLK_GATE0, 7);
71 AXG_AO_GATE(saradc, AO_CLK_GATE0, 8);
72 AXG_AO_GATE(mailbox, AO_CLK_GATE0_SP, 0);
73 AXG_AO_GATE(m3, AO_CLK_GATE0_SP, 1);
74 AXG_AO_GATE(ahb_sram, AO_CLK_GATE0_SP, 2);
75 AXG_AO_GATE(rti, AO_CLK_GATE0_SP, 3);
76 AXG_AO_GATE(m4_fclk, AO_CLK_GATE0_SP, 4);
77 AXG_AO_GATE(m4_hclk, AO_CLK_GATE0_SP, 5);
78
79 static struct clk_regmap g12a_aoclk_cts_oscin = {
80         .data = &(struct clk_regmap_gate_data){
81                 .offset = AO_RTI_PWR_CNTL_REG0,
82                 .bit_idx = 14,
83         },
84         .hw.init = &(struct clk_init_data){
85                 .name = "cts_oscin",
86                 .ops = &clk_regmap_gate_ro_ops,
87                 .parent_data = &(const struct clk_parent_data) {
88                         .fw_name = "xtal",
89                 },
90                 .num_parents = 1,
91         },
92 };
93
94 static const struct meson_clk_dualdiv_param g12a_32k_div_table[] = {
95         {
96                 .dual   = 1,
97                 .n1     = 733,
98                 .m1     = 8,
99                 .n2     = 732,
100                 .m2     = 11,
101         }, {}
102 };
103
104 /* 32k_by_oscin clock */
105
106 static struct clk_regmap g12a_aoclk_32k_by_oscin_pre = {
107         .data = &(struct clk_regmap_gate_data){
108                 .offset = AO_RTC_ALT_CLK_CNTL0,
109                 .bit_idx = 31,
110         },
111         .hw.init = &(struct clk_init_data){
112                 .name = "g12a_ao_32k_by_oscin_pre",
113                 .ops = &clk_regmap_gate_ops,
114                 .parent_hws = (const struct clk_hw *[]) {
115                         &g12a_aoclk_cts_oscin.hw
116                 },
117                 .num_parents = 1,
118         },
119 };
120
121 static struct clk_regmap g12a_aoclk_32k_by_oscin_div = {
122         .data = &(struct meson_clk_dualdiv_data){
123                 .n1 = {
124                         .reg_off = AO_RTC_ALT_CLK_CNTL0,
125                         .shift   = 0,
126                         .width   = 12,
127                 },
128                 .n2 = {
129                         .reg_off = AO_RTC_ALT_CLK_CNTL0,
130                         .shift   = 12,
131                         .width   = 12,
132                 },
133                 .m1 = {
134                         .reg_off = AO_RTC_ALT_CLK_CNTL1,
135                         .shift   = 0,
136                         .width   = 12,
137                 },
138                 .m2 = {
139                         .reg_off = AO_RTC_ALT_CLK_CNTL1,
140                         .shift   = 12,
141                         .width   = 12,
142                 },
143                 .dual = {
144                         .reg_off = AO_RTC_ALT_CLK_CNTL0,
145                         .shift   = 28,
146                         .width   = 1,
147                 },
148                 .table = g12a_32k_div_table,
149         },
150         .hw.init = &(struct clk_init_data){
151                 .name = "g12a_ao_32k_by_oscin_div",
152                 .ops = &meson_clk_dualdiv_ops,
153                 .parent_hws = (const struct clk_hw *[]) {
154                         &g12a_aoclk_32k_by_oscin_pre.hw
155                 },
156                 .num_parents = 1,
157         },
158 };
159
160 static struct clk_regmap g12a_aoclk_32k_by_oscin_sel = {
161         .data = &(struct clk_regmap_mux_data) {
162                 .offset = AO_RTC_ALT_CLK_CNTL1,
163                 .mask = 0x1,
164                 .shift = 24,
165                 .flags = CLK_MUX_ROUND_CLOSEST,
166         },
167         .hw.init = &(struct clk_init_data){
168                 .name = "g12a_ao_32k_by_oscin_sel",
169                 .ops = &clk_regmap_mux_ops,
170                 .parent_hws = (const struct clk_hw *[]) {
171                         &g12a_aoclk_32k_by_oscin_div.hw,
172                         &g12a_aoclk_32k_by_oscin_pre.hw,
173                 },
174                 .num_parents = 2,
175                 .flags = CLK_SET_RATE_PARENT,
176         },
177 };
178
179 static struct clk_regmap g12a_aoclk_32k_by_oscin = {
180         .data = &(struct clk_regmap_gate_data){
181                 .offset = AO_RTC_ALT_CLK_CNTL0,
182                 .bit_idx = 30,
183         },
184         .hw.init = &(struct clk_init_data){
185                 .name = "g12a_ao_32k_by_oscin",
186                 .ops = &clk_regmap_gate_ops,
187                 .parent_hws = (const struct clk_hw *[]) {
188                         &g12a_aoclk_32k_by_oscin_sel.hw
189                 },
190                 .num_parents = 1,
191                 .flags = CLK_SET_RATE_PARENT,
192         },
193 };
194
195 /* cec clock */
196
197 static struct clk_regmap g12a_aoclk_cec_pre = {
198         .data = &(struct clk_regmap_gate_data){
199                 .offset = AO_CEC_CLK_CNTL_REG0,
200                 .bit_idx = 31,
201         },
202         .hw.init = &(struct clk_init_data){
203                 .name = "g12a_ao_cec_pre",
204                 .ops = &clk_regmap_gate_ops,
205                 .parent_hws = (const struct clk_hw *[]) {
206                         &g12a_aoclk_cts_oscin.hw
207                 },
208                 .num_parents = 1,
209         },
210 };
211
212 static struct clk_regmap g12a_aoclk_cec_div = {
213         .data = &(struct meson_clk_dualdiv_data){
214                 .n1 = {
215                         .reg_off = AO_CEC_CLK_CNTL_REG0,
216                         .shift   = 0,
217                         .width   = 12,
218                 },
219                 .n2 = {
220                         .reg_off = AO_CEC_CLK_CNTL_REG0,
221                         .shift   = 12,
222                         .width   = 12,
223                 },
224                 .m1 = {
225                         .reg_off = AO_CEC_CLK_CNTL_REG1,
226                         .shift   = 0,
227                         .width   = 12,
228                 },
229                 .m2 = {
230                         .reg_off = AO_CEC_CLK_CNTL_REG1,
231                         .shift   = 12,
232                         .width   = 12,
233                 },
234                 .dual = {
235                         .reg_off = AO_CEC_CLK_CNTL_REG0,
236                         .shift   = 28,
237                         .width   = 1,
238                 },
239                 .table = g12a_32k_div_table,
240         },
241         .hw.init = &(struct clk_init_data){
242                 .name = "g12a_ao_cec_div",
243                 .ops = &meson_clk_dualdiv_ops,
244                 .parent_hws = (const struct clk_hw *[]) {
245                         &g12a_aoclk_cec_pre.hw
246                 },
247                 .num_parents = 1,
248         },
249 };
250
251 static struct clk_regmap g12a_aoclk_cec_sel = {
252         .data = &(struct clk_regmap_mux_data) {
253                 .offset = AO_CEC_CLK_CNTL_REG1,
254                 .mask = 0x1,
255                 .shift = 24,
256                 .flags = CLK_MUX_ROUND_CLOSEST,
257         },
258         .hw.init = &(struct clk_init_data){
259                 .name = "g12a_ao_cec_sel",
260                 .ops = &clk_regmap_mux_ops,
261                 .parent_hws = (const struct clk_hw *[]) {
262                         &g12a_aoclk_cec_div.hw,
263                         &g12a_aoclk_cec_pre.hw,
264                 },
265                 .num_parents = 2,
266                 .flags = CLK_SET_RATE_PARENT,
267         },
268 };
269
270 static struct clk_regmap g12a_aoclk_cec = {
271         .data = &(struct clk_regmap_gate_data){
272                 .offset = AO_CEC_CLK_CNTL_REG0,
273                 .bit_idx = 30,
274         },
275         .hw.init = &(struct clk_init_data){
276                 .name = "g12a_ao_cec",
277                 .ops = &clk_regmap_gate_ops,
278                 .parent_hws = (const struct clk_hw *[]) {
279                         &g12a_aoclk_cec_sel.hw
280                 },
281                 .num_parents = 1,
282                 .flags = CLK_SET_RATE_PARENT,
283         },
284 };
285
286 static struct clk_regmap g12a_aoclk_cts_rtc_oscin = {
287         .data = &(struct clk_regmap_mux_data) {
288                 .offset = AO_RTI_PWR_CNTL_REG0,
289                 .mask = 0x1,
290                 .shift = 10,
291                 .flags = CLK_MUX_ROUND_CLOSEST,
292         },
293         .hw.init = &(struct clk_init_data){
294                 .name = "g12a_ao_cts_rtc_oscin",
295                 .ops = &clk_regmap_mux_ops,
296                 .parent_data = (const struct clk_parent_data []) {
297                         { .hw = &g12a_aoclk_32k_by_oscin.hw },
298                         { .fw_name = "ext-32k-0", },
299                 },
300                 .num_parents = 2,
301                 .flags = CLK_SET_RATE_PARENT,
302         },
303 };
304
305 static struct clk_regmap g12a_aoclk_clk81 = {
306         .data = &(struct clk_regmap_mux_data) {
307                 .offset = AO_RTI_PWR_CNTL_REG0,
308                 .mask = 0x1,
309                 .shift = 8,
310                 .flags = CLK_MUX_ROUND_CLOSEST,
311         },
312         .hw.init = &(struct clk_init_data){
313                 .name = "g12a_ao_clk81",
314                 .ops = &clk_regmap_mux_ro_ops,
315                 .parent_data = (const struct clk_parent_data []) {
316                         { .fw_name = "mpeg-clk", },
317                         { .hw = &g12a_aoclk_cts_rtc_oscin.hw },
318                 },
319                 .num_parents = 2,
320                 .flags = CLK_SET_RATE_PARENT,
321         },
322 };
323
324 static struct clk_regmap g12a_aoclk_saradc_mux = {
325         .data = &(struct clk_regmap_mux_data) {
326                 .offset = AO_SAR_CLK,
327                 .mask = 0x3,
328                 .shift = 9,
329         },
330         .hw.init = &(struct clk_init_data){
331                 .name = "g12a_ao_saradc_mux",
332                 .ops = &clk_regmap_mux_ops,
333                 .parent_data = (const struct clk_parent_data []) {
334                         { .fw_name = "xtal", },
335                         { .hw = &g12a_aoclk_clk81.hw },
336                 },
337                 .num_parents = 2,
338         },
339 };
340
341 static struct clk_regmap g12a_aoclk_saradc_div = {
342         .data = &(struct clk_regmap_div_data) {
343                 .offset = AO_SAR_CLK,
344                 .shift = 0,
345                 .width = 8,
346         },
347         .hw.init = &(struct clk_init_data){
348                 .name = "g12a_ao_saradc_div",
349                 .ops = &clk_regmap_divider_ops,
350                 .parent_hws = (const struct clk_hw *[]) {
351                         &g12a_aoclk_saradc_mux.hw
352                 },
353                 .num_parents = 1,
354                 .flags = CLK_SET_RATE_PARENT,
355         },
356 };
357
358 static struct clk_regmap g12a_aoclk_saradc_gate = {
359         .data = &(struct clk_regmap_gate_data) {
360                 .offset = AO_SAR_CLK,
361                 .bit_idx = 8,
362         },
363         .hw.init = &(struct clk_init_data){
364                 .name = "g12a_ao_saradc_gate",
365                 .ops = &clk_regmap_gate_ops,
366                 .parent_hws = (const struct clk_hw *[]) {
367                         &g12a_aoclk_saradc_div.hw
368                 },
369                 .num_parents = 1,
370                 .flags = CLK_SET_RATE_PARENT,
371         },
372 };
373
374 static const unsigned int g12a_aoclk_reset[] = {
375         [RESET_AO_IR_IN]        = 16,
376         [RESET_AO_UART]         = 17,
377         [RESET_AO_I2C_M]        = 18,
378         [RESET_AO_I2C_S]        = 19,
379         [RESET_AO_SAR_ADC]      = 20,
380         [RESET_AO_UART2]        = 22,
381         [RESET_AO_IR_OUT]       = 23,
382 };
383
384 static struct clk_regmap *g12a_aoclk_regmap[] = {
385         &g12a_aoclk_ahb,
386         &g12a_aoclk_ir_in,
387         &g12a_aoclk_i2c_m0,
388         &g12a_aoclk_i2c_s0,
389         &g12a_aoclk_uart,
390         &g12a_aoclk_prod_i2c,
391         &g12a_aoclk_uart2,
392         &g12a_aoclk_ir_out,
393         &g12a_aoclk_saradc,
394         &g12a_aoclk_mailbox,
395         &g12a_aoclk_m3,
396         &g12a_aoclk_ahb_sram,
397         &g12a_aoclk_rti,
398         &g12a_aoclk_m4_fclk,
399         &g12a_aoclk_m4_hclk,
400         &g12a_aoclk_cts_oscin,
401         &g12a_aoclk_32k_by_oscin_pre,
402         &g12a_aoclk_32k_by_oscin_div,
403         &g12a_aoclk_32k_by_oscin_sel,
404         &g12a_aoclk_32k_by_oscin,
405         &g12a_aoclk_cec_pre,
406         &g12a_aoclk_cec_div,
407         &g12a_aoclk_cec_sel,
408         &g12a_aoclk_cec,
409         &g12a_aoclk_cts_rtc_oscin,
410         &g12a_aoclk_clk81,
411         &g12a_aoclk_saradc_mux,
412         &g12a_aoclk_saradc_div,
413         &g12a_aoclk_saradc_gate,
414 };
415
416 static struct clk_hw *g12a_aoclk_hw_clks[] = {
417         [CLKID_AO_AHB]          = &g12a_aoclk_ahb.hw,
418         [CLKID_AO_IR_IN]        = &g12a_aoclk_ir_in.hw,
419         [CLKID_AO_I2C_M0]       = &g12a_aoclk_i2c_m0.hw,
420         [CLKID_AO_I2C_S0]       = &g12a_aoclk_i2c_s0.hw,
421         [CLKID_AO_UART]         = &g12a_aoclk_uart.hw,
422         [CLKID_AO_PROD_I2C]     = &g12a_aoclk_prod_i2c.hw,
423         [CLKID_AO_UART2]        = &g12a_aoclk_uart2.hw,
424         [CLKID_AO_IR_OUT]       = &g12a_aoclk_ir_out.hw,
425         [CLKID_AO_SAR_ADC]      = &g12a_aoclk_saradc.hw,
426         [CLKID_AO_MAILBOX]      = &g12a_aoclk_mailbox.hw,
427         [CLKID_AO_M3]           = &g12a_aoclk_m3.hw,
428         [CLKID_AO_AHB_SRAM]     = &g12a_aoclk_ahb_sram.hw,
429         [CLKID_AO_RTI]          = &g12a_aoclk_rti.hw,
430         [CLKID_AO_M4_FCLK]      = &g12a_aoclk_m4_fclk.hw,
431         [CLKID_AO_M4_HCLK]      = &g12a_aoclk_m4_hclk.hw,
432         [CLKID_AO_CLK81]        = &g12a_aoclk_clk81.hw,
433         [CLKID_AO_SAR_ADC_SEL]  = &g12a_aoclk_saradc_mux.hw,
434         [CLKID_AO_SAR_ADC_DIV]  = &g12a_aoclk_saradc_div.hw,
435         [CLKID_AO_SAR_ADC_CLK]  = &g12a_aoclk_saradc_gate.hw,
436         [CLKID_AO_CTS_OSCIN]    = &g12a_aoclk_cts_oscin.hw,
437         [CLKID_AO_32K_PRE]      = &g12a_aoclk_32k_by_oscin_pre.hw,
438         [CLKID_AO_32K_DIV]      = &g12a_aoclk_32k_by_oscin_div.hw,
439         [CLKID_AO_32K_SEL]      = &g12a_aoclk_32k_by_oscin_sel.hw,
440         [CLKID_AO_32K]          = &g12a_aoclk_32k_by_oscin.hw,
441         [CLKID_AO_CEC_PRE]      = &g12a_aoclk_cec_pre.hw,
442         [CLKID_AO_CEC_DIV]      = &g12a_aoclk_cec_div.hw,
443         [CLKID_AO_CEC_SEL]      = &g12a_aoclk_cec_sel.hw,
444         [CLKID_AO_CEC]          = &g12a_aoclk_cec.hw,
445         [CLKID_AO_CTS_RTC_OSCIN] = &g12a_aoclk_cts_rtc_oscin.hw,
446 };
447
448 static const struct meson_aoclk_data g12a_aoclkc_data = {
449         .reset_reg      = AO_RTI_GEN_CNTL_REG0,
450         .num_reset      = ARRAY_SIZE(g12a_aoclk_reset),
451         .reset          = g12a_aoclk_reset,
452         .num_clks       = ARRAY_SIZE(g12a_aoclk_regmap),
453         .clks           = g12a_aoclk_regmap,
454         .hw_clks        = {
455                 .hws    = g12a_aoclk_hw_clks,
456                 .num    = ARRAY_SIZE(g12a_aoclk_hw_clks),
457         },
458 };
459
460 static const struct of_device_id g12a_aoclkc_match_table[] = {
461         {
462                 .compatible     = "amlogic,meson-g12a-aoclkc",
463                 .data           = &g12a_aoclkc_data,
464         },
465         { }
466 };
467 MODULE_DEVICE_TABLE(of, g12a_aoclkc_match_table);
468
469 static struct platform_driver g12a_aoclkc_driver = {
470         .probe          = meson_aoclkc_probe,
471         .driver         = {
472                 .name   = "g12a-aoclkc",
473                 .of_match_table = g12a_aoclkc_match_table,
474         },
475 };
476
477 module_platform_driver(g12a_aoclkc_driver);
478 MODULE_LICENSE("GPL v2");