GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / clk / meson / axg-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) 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>
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/axg-aoclkc.h>
22 #include <dt-bindings/reset/axg-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_PWR_CNTL_REG1    0x0C
29 #define AO_RTI_PWR_CNTL_REG0    0x10
30 #define AO_RTI_GEN_CNTL_REG0    0x40
31 #define AO_OSCIN_CNTL           0x58
32 #define AO_CRT_CLK_CNTL1        0x68
33 #define AO_SAR_CLK              0x90
34 #define AO_RTC_ALT_CLK_CNTL0    0x94
35 #define AO_RTC_ALT_CLK_CNTL1    0x98
36
37 #define AXG_AO_GATE(_name, _bit)                                        \
38 static struct clk_regmap axg_aoclk_##_name = {                          \
39         .data = &(struct clk_regmap_gate_data) {                        \
40                 .offset = (AO_RTI_GEN_CNTL_REG0),                       \
41                 .bit_idx = (_bit),                                      \
42         },                                                              \
43         .hw.init = &(struct clk_init_data) {                            \
44                 .name =  "axg_ao_" #_name,                              \
45                 .ops = &clk_regmap_gate_ops,                            \
46                 .parent_data = &(const struct clk_parent_data) {        \
47                         .fw_name = "mpeg-clk",                          \
48                 },                                                      \
49                 .num_parents = 1,                                       \
50                 .flags = CLK_IGNORE_UNUSED,                             \
51         },                                                              \
52 }
53
54 AXG_AO_GATE(remote, 0);
55 AXG_AO_GATE(i2c_master, 1);
56 AXG_AO_GATE(i2c_slave, 2);
57 AXG_AO_GATE(uart1, 3);
58 AXG_AO_GATE(uart2, 5);
59 AXG_AO_GATE(ir_blaster, 6);
60 AXG_AO_GATE(saradc, 7);
61
62 static struct clk_regmap axg_aoclk_cts_oscin = {
63         .data = &(struct clk_regmap_gate_data){
64                 .offset = AO_RTI_PWR_CNTL_REG0,
65                 .bit_idx = 14,
66         },
67         .hw.init = &(struct clk_init_data){
68                 .name = "cts_oscin",
69                 .ops = &clk_regmap_gate_ro_ops,
70                 .parent_data = &(const struct clk_parent_data) {
71                         .fw_name = "xtal",
72                 },
73                 .num_parents = 1,
74         },
75 };
76
77 static struct clk_regmap axg_aoclk_32k_pre = {
78         .data = &(struct clk_regmap_gate_data){
79                 .offset = AO_RTC_ALT_CLK_CNTL0,
80                 .bit_idx = 31,
81         },
82         .hw.init = &(struct clk_init_data){
83                 .name = "axg_ao_32k_pre",
84                 .ops = &clk_regmap_gate_ops,
85                 .parent_hws = (const struct clk_hw *[]) {
86                         &axg_aoclk_cts_oscin.hw
87                 },
88                 .num_parents = 1,
89         },
90 };
91
92 static const struct meson_clk_dualdiv_param axg_32k_div_table[] = {
93         {
94                 .dual   = 1,
95                 .n1     = 733,
96                 .m1     = 8,
97                 .n2     = 732,
98                 .m2     = 11,
99         }, {}
100 };
101
102 static struct clk_regmap axg_aoclk_32k_div = {
103         .data = &(struct meson_clk_dualdiv_data){
104                 .n1 = {
105                         .reg_off = AO_RTC_ALT_CLK_CNTL0,
106                         .shift   = 0,
107                         .width   = 12,
108                 },
109                 .n2 = {
110                         .reg_off = AO_RTC_ALT_CLK_CNTL0,
111                         .shift   = 12,
112                         .width   = 12,
113                 },
114                 .m1 = {
115                         .reg_off = AO_RTC_ALT_CLK_CNTL1,
116                         .shift   = 0,
117                         .width   = 12,
118                 },
119                 .m2 = {
120                         .reg_off = AO_RTC_ALT_CLK_CNTL1,
121                         .shift   = 12,
122                         .width   = 12,
123                 },
124                 .dual = {
125                         .reg_off = AO_RTC_ALT_CLK_CNTL0,
126                         .shift   = 28,
127                         .width   = 1,
128                 },
129                 .table = axg_32k_div_table,
130         },
131         .hw.init = &(struct clk_init_data){
132                 .name = "axg_ao_32k_div",
133                 .ops = &meson_clk_dualdiv_ops,
134                 .parent_hws = (const struct clk_hw *[]) {
135                         &axg_aoclk_32k_pre.hw
136                 },
137                 .num_parents = 1,
138         },
139 };
140
141 static struct clk_regmap axg_aoclk_32k_sel = {
142         .data = &(struct clk_regmap_mux_data) {
143                 .offset = AO_RTC_ALT_CLK_CNTL1,
144                 .mask = 0x1,
145                 .shift = 24,
146                 .flags = CLK_MUX_ROUND_CLOSEST,
147         },
148         .hw.init = &(struct clk_init_data){
149                 .name = "axg_ao_32k_sel",
150                 .ops = &clk_regmap_mux_ops,
151                 .parent_hws = (const struct clk_hw *[]) {
152                         &axg_aoclk_32k_div.hw,
153                         &axg_aoclk_32k_pre.hw,
154                 },
155                 .num_parents = 2,
156                 .flags = CLK_SET_RATE_PARENT,
157         },
158 };
159
160 static struct clk_regmap axg_aoclk_32k = {
161         .data = &(struct clk_regmap_gate_data){
162                 .offset = AO_RTC_ALT_CLK_CNTL0,
163                 .bit_idx = 30,
164         },
165         .hw.init = &(struct clk_init_data){
166                 .name = "axg_ao_32k",
167                 .ops = &clk_regmap_gate_ops,
168                 .parent_hws = (const struct clk_hw *[]) {
169                         &axg_aoclk_32k_sel.hw
170                 },
171                 .num_parents = 1,
172                 .flags = CLK_SET_RATE_PARENT,
173         },
174 };
175
176 static struct clk_regmap axg_aoclk_cts_rtc_oscin = {
177         .data = &(struct clk_regmap_mux_data) {
178                 .offset = AO_RTI_PWR_CNTL_REG0,
179                 .mask = 0x1,
180                 .shift = 10,
181                 .flags = CLK_MUX_ROUND_CLOSEST,
182         },
183         .hw.init = &(struct clk_init_data){
184                 .name = "axg_ao_cts_rtc_oscin",
185                 .ops = &clk_regmap_mux_ops,
186                 .parent_data = (const struct clk_parent_data []) {
187                         { .hw = &axg_aoclk_32k.hw },
188                         { .fw_name = "ext_32k-0", },
189                 },
190                 .num_parents = 2,
191                 .flags = CLK_SET_RATE_PARENT,
192         },
193 };
194
195 static struct clk_regmap axg_aoclk_clk81 = {
196         .data = &(struct clk_regmap_mux_data) {
197                 .offset = AO_RTI_PWR_CNTL_REG0,
198                 .mask = 0x1,
199                 .shift = 8,
200                 .flags = CLK_MUX_ROUND_CLOSEST,
201         },
202         .hw.init = &(struct clk_init_data){
203                 .name = "axg_ao_clk81",
204                 .ops = &clk_regmap_mux_ro_ops,
205                 .parent_data = (const struct clk_parent_data []) {
206                         { .fw_name = "mpeg-clk", },
207                         { .hw = &axg_aoclk_cts_rtc_oscin.hw },
208                 },
209                 .num_parents = 2,
210                 .flags = CLK_SET_RATE_PARENT,
211         },
212 };
213
214 static struct clk_regmap axg_aoclk_saradc_mux = {
215         .data = &(struct clk_regmap_mux_data) {
216                 .offset = AO_SAR_CLK,
217                 .mask = 0x3,
218                 .shift = 9,
219         },
220         .hw.init = &(struct clk_init_data){
221                 .name = "axg_ao_saradc_mux",
222                 .ops = &clk_regmap_mux_ops,
223                 .parent_data = (const struct clk_parent_data []) {
224                         { .fw_name = "xtal", },
225                         { .hw = &axg_aoclk_clk81.hw },
226                 },
227                 .num_parents = 2,
228         },
229 };
230
231 static struct clk_regmap axg_aoclk_saradc_div = {
232         .data = &(struct clk_regmap_div_data) {
233                 .offset = AO_SAR_CLK,
234                 .shift = 0,
235                 .width = 8,
236         },
237         .hw.init = &(struct clk_init_data){
238                 .name = "axg_ao_saradc_div",
239                 .ops = &clk_regmap_divider_ops,
240                 .parent_hws = (const struct clk_hw *[]) {
241                         &axg_aoclk_saradc_mux.hw
242                 },
243                 .num_parents = 1,
244                 .flags = CLK_SET_RATE_PARENT,
245         },
246 };
247
248 static struct clk_regmap axg_aoclk_saradc_gate = {
249         .data = &(struct clk_regmap_gate_data) {
250                 .offset = AO_SAR_CLK,
251                 .bit_idx = 8,
252         },
253         .hw.init = &(struct clk_init_data){
254                 .name = "axg_ao_saradc_gate",
255                 .ops = &clk_regmap_gate_ops,
256                 .parent_hws = (const struct clk_hw *[]) {
257                         &axg_aoclk_saradc_div.hw
258                 },
259                 .num_parents = 1,
260                 .flags = CLK_SET_RATE_PARENT,
261         },
262 };
263
264 static const unsigned int axg_aoclk_reset[] = {
265         [RESET_AO_REMOTE]       = 16,
266         [RESET_AO_I2C_MASTER]   = 18,
267         [RESET_AO_I2C_SLAVE]    = 19,
268         [RESET_AO_UART1]        = 17,
269         [RESET_AO_UART2]        = 22,
270         [RESET_AO_IR_BLASTER]   = 23,
271 };
272
273 static struct clk_regmap *axg_aoclk_regmap[] = {
274         &axg_aoclk_remote,
275         &axg_aoclk_i2c_master,
276         &axg_aoclk_i2c_slave,
277         &axg_aoclk_uart1,
278         &axg_aoclk_uart2,
279         &axg_aoclk_ir_blaster,
280         &axg_aoclk_saradc,
281         &axg_aoclk_cts_oscin,
282         &axg_aoclk_32k_pre,
283         &axg_aoclk_32k_div,
284         &axg_aoclk_32k_sel,
285         &axg_aoclk_32k,
286         &axg_aoclk_cts_rtc_oscin,
287         &axg_aoclk_clk81,
288         &axg_aoclk_saradc_mux,
289         &axg_aoclk_saradc_div,
290         &axg_aoclk_saradc_gate,
291 };
292
293 static struct clk_hw *axg_aoclk_hw_clks[] = {
294         [CLKID_AO_REMOTE]       = &axg_aoclk_remote.hw,
295         [CLKID_AO_I2C_MASTER]   = &axg_aoclk_i2c_master.hw,
296         [CLKID_AO_I2C_SLAVE]    = &axg_aoclk_i2c_slave.hw,
297         [CLKID_AO_UART1]        = &axg_aoclk_uart1.hw,
298         [CLKID_AO_UART2]        = &axg_aoclk_uart2.hw,
299         [CLKID_AO_IR_BLASTER]   = &axg_aoclk_ir_blaster.hw,
300         [CLKID_AO_SAR_ADC]      = &axg_aoclk_saradc.hw,
301         [CLKID_AO_CLK81]        = &axg_aoclk_clk81.hw,
302         [CLKID_AO_SAR_ADC_SEL]  = &axg_aoclk_saradc_mux.hw,
303         [CLKID_AO_SAR_ADC_DIV]  = &axg_aoclk_saradc_div.hw,
304         [CLKID_AO_SAR_ADC_CLK]  = &axg_aoclk_saradc_gate.hw,
305         [CLKID_AO_CTS_OSCIN]    = &axg_aoclk_cts_oscin.hw,
306         [CLKID_AO_32K_PRE]      = &axg_aoclk_32k_pre.hw,
307         [CLKID_AO_32K_DIV]      = &axg_aoclk_32k_div.hw,
308         [CLKID_AO_32K_SEL]      = &axg_aoclk_32k_sel.hw,
309         [CLKID_AO_32K]          = &axg_aoclk_32k.hw,
310         [CLKID_AO_CTS_RTC_OSCIN] = &axg_aoclk_cts_rtc_oscin.hw,
311 };
312
313 static const struct meson_aoclk_data axg_aoclkc_data = {
314         .reset_reg      = AO_RTI_GEN_CNTL_REG0,
315         .num_reset      = ARRAY_SIZE(axg_aoclk_reset),
316         .reset          = axg_aoclk_reset,
317         .num_clks       = ARRAY_SIZE(axg_aoclk_regmap),
318         .clks           = axg_aoclk_regmap,
319         .hw_clks        = {
320                 .hws    = axg_aoclk_hw_clks,
321                 .num    = ARRAY_SIZE(axg_aoclk_hw_clks),
322         },
323 };
324
325 static const struct of_device_id axg_aoclkc_match_table[] = {
326         {
327                 .compatible     = "amlogic,meson-axg-aoclkc",
328                 .data           = &axg_aoclkc_data,
329         },
330         { }
331 };
332 MODULE_DEVICE_TABLE(of, axg_aoclkc_match_table);
333
334 static struct platform_driver axg_aoclkc_driver = {
335         .probe          = meson_aoclkc_probe,
336         .driver         = {
337                 .name   = "axg-aoclkc",
338                 .of_match_table = axg_aoclkc_match_table,
339         },
340 };
341
342 module_platform_driver(axg_aoclkc_driver);
343 MODULE_LICENSE("GPL v2");