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");
344