xref: /openbmc/linux/drivers/clk/meson/axg-aoclk.c (revision ae40e94f)
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 "meson-aoclk.h"
16 #include "axg-aoclk.h"
17 
18 #include "clk-regmap.h"
19 #include "clk-dualdiv.h"
20 
21 #define IN_PREFIX "ao-in-"
22 
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 
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,				\
45 		.parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \
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 
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,
67 		.parent_names = (const char *[]){ IN_PREFIX "xtal" },
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",
174 						  IN_PREFIX "ext_32k-0" },
175 		.num_parents = 2,
176 		.flags = CLK_SET_RATE_PARENT,
177 	},
178 };
179 
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,
185 		.flags = CLK_MUX_ROUND_CLOSEST,
186 	},
187 	.hw.init = &(struct clk_init_data){
188 		.name = "axg_ao_clk81",
189 		.ops = &clk_regmap_mux_ro_ops,
190 		.parent_names = (const char *[]){ IN_PREFIX "mpeg-clk",
191 						  "axg_ao_cts_rtc_oscin"},
192 		.num_parents = 2,
193 		.flags = CLK_SET_RATE_PARENT,
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,
206 		.parent_names = (const char *[]){ IN_PREFIX "xtal",
207 						  "axg_ao_clk81" },
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[] = {
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,
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,
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,
289 	},
290 	.num = NR_CLKS,
291 };
292 
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 
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,
306 	.inputs		= axg_aoclk_inputs,
307 	.num_inputs	= ARRAY_SIZE(axg_aoclk_inputs),
308 	.input_prefix	= IN_PREFIX,
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);
328