xref: /linux/drivers/clk/meson/axg-aoclk.c (revision e3966940559d52aa1800a008dcfeec218dd31f88)
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 static const struct clk_parent_data axg_ao_pclk_parents = { .fw_name = "mpeg-clk" };
38 
39 #define AXG_AO_GATE(_name, _bit, _flags)		       \
40 	MESON_PCLK(axg_ao_##_name, AO_RTI_GEN_CNTL_REG0, _bit, \
41 		   &axg_ao_pclk_parents, _flags)
42 
43 static AXG_AO_GATE(remote,	0, CLK_IGNORE_UNUSED);
44 static AXG_AO_GATE(i2c_master,	1, CLK_IGNORE_UNUSED);
45 static AXG_AO_GATE(i2c_slave,	2, CLK_IGNORE_UNUSED);
46 static AXG_AO_GATE(uart1,	3, CLK_IGNORE_UNUSED);
47 static AXG_AO_GATE(uart2,	5, CLK_IGNORE_UNUSED);
48 static AXG_AO_GATE(ir_blaster,	6, CLK_IGNORE_UNUSED);
49 static AXG_AO_GATE(saradc,	7, CLK_IGNORE_UNUSED);
50 
51 static struct clk_regmap axg_ao_cts_oscin = {
52 	.data = &(struct clk_regmap_gate_data){
53 		.offset = AO_RTI_PWR_CNTL_REG0,
54 		.bit_idx = 14,
55 	},
56 	.hw.init = &(struct clk_init_data){
57 		.name = "cts_oscin",
58 		.ops = &clk_regmap_gate_ro_ops,
59 		.parent_data = &(const struct clk_parent_data) {
60 			.fw_name = "xtal",
61 		},
62 		.num_parents = 1,
63 	},
64 };
65 
66 static struct clk_regmap axg_ao_32k_pre = {
67 	.data = &(struct clk_regmap_gate_data){
68 		.offset = AO_RTC_ALT_CLK_CNTL0,
69 		.bit_idx = 31,
70 	},
71 	.hw.init = &(struct clk_init_data){
72 		.name = "axg_ao_32k_pre",
73 		.ops = &clk_regmap_gate_ops,
74 		.parent_hws = (const struct clk_hw *[]) {
75 			&axg_ao_cts_oscin.hw
76 		},
77 		.num_parents = 1,
78 	},
79 };
80 
81 static const struct meson_clk_dualdiv_param axg_32k_div_table[] = {
82 	{
83 		.dual	= 1,
84 		.n1	= 733,
85 		.m1	= 8,
86 		.n2	= 732,
87 		.m2	= 11,
88 	}, {}
89 };
90 
91 static struct clk_regmap axg_ao_32k_div = {
92 	.data = &(struct meson_clk_dualdiv_data){
93 		.n1 = {
94 			.reg_off = AO_RTC_ALT_CLK_CNTL0,
95 			.shift   = 0,
96 			.width   = 12,
97 		},
98 		.n2 = {
99 			.reg_off = AO_RTC_ALT_CLK_CNTL0,
100 			.shift   = 12,
101 			.width   = 12,
102 		},
103 		.m1 = {
104 			.reg_off = AO_RTC_ALT_CLK_CNTL1,
105 			.shift   = 0,
106 			.width   = 12,
107 		},
108 		.m2 = {
109 			.reg_off = AO_RTC_ALT_CLK_CNTL1,
110 			.shift   = 12,
111 			.width   = 12,
112 		},
113 		.dual = {
114 			.reg_off = AO_RTC_ALT_CLK_CNTL0,
115 			.shift   = 28,
116 			.width   = 1,
117 		},
118 		.table = axg_32k_div_table,
119 	},
120 	.hw.init = &(struct clk_init_data){
121 		.name = "axg_ao_32k_div",
122 		.ops = &meson_clk_dualdiv_ops,
123 		.parent_hws = (const struct clk_hw *[]) {
124 			&axg_ao_32k_pre.hw
125 		},
126 		.num_parents = 1,
127 	},
128 };
129 
130 static struct clk_regmap axg_ao_32k_sel = {
131 	.data = &(struct clk_regmap_mux_data) {
132 		.offset = AO_RTC_ALT_CLK_CNTL1,
133 		.mask = 0x1,
134 		.shift = 24,
135 		.flags = CLK_MUX_ROUND_CLOSEST,
136 	},
137 	.hw.init = &(struct clk_init_data){
138 		.name = "axg_ao_32k_sel",
139 		.ops = &clk_regmap_mux_ops,
140 		.parent_hws = (const struct clk_hw *[]) {
141 			&axg_ao_32k_div.hw,
142 			&axg_ao_32k_pre.hw,
143 		},
144 		.num_parents = 2,
145 		.flags = CLK_SET_RATE_PARENT,
146 	},
147 };
148 
149 static struct clk_regmap axg_ao_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_hws = (const struct clk_hw *[]) {
158 			&axg_ao_32k_sel.hw
159 		},
160 		.num_parents = 1,
161 		.flags = CLK_SET_RATE_PARENT,
162 	},
163 };
164 
165 static struct clk_regmap axg_ao_cts_rtc_oscin = {
166 	.data = &(struct clk_regmap_mux_data) {
167 		.offset = AO_RTI_PWR_CNTL_REG0,
168 		.mask = 0x1,
169 		.shift = 10,
170 		.flags = CLK_MUX_ROUND_CLOSEST,
171 	},
172 	.hw.init = &(struct clk_init_data){
173 		.name = "axg_ao_cts_rtc_oscin",
174 		.ops = &clk_regmap_mux_ops,
175 		.parent_data = (const struct clk_parent_data []) {
176 			{ .hw = &axg_ao_32k.hw },
177 			{ .fw_name = "ext_32k-0", },
178 		},
179 		.num_parents = 2,
180 		.flags = CLK_SET_RATE_PARENT,
181 	},
182 };
183 
184 static struct clk_regmap axg_ao_clk81 = {
185 	.data = &(struct clk_regmap_mux_data) {
186 		.offset = AO_RTI_PWR_CNTL_REG0,
187 		.mask = 0x1,
188 		.shift = 8,
189 		.flags = CLK_MUX_ROUND_CLOSEST,
190 	},
191 	.hw.init = &(struct clk_init_data){
192 		/*
193 		 * NOTE: this is one of the infamous clock the pwm driver
194 		 * can request directly by its global name. It's wrong but
195 		 * there is not much we can do about it until the support
196 		 * for the old pwm bindings is dropped
197 		 */
198 		.name = "axg_ao_clk81",
199 		.ops = &clk_regmap_mux_ro_ops,
200 		.parent_data = (const struct clk_parent_data []) {
201 			{ .fw_name = "mpeg-clk", },
202 			{ .hw = &axg_ao_cts_rtc_oscin.hw },
203 		},
204 		.num_parents = 2,
205 		.flags = CLK_SET_RATE_PARENT,
206 	},
207 };
208 
209 static struct clk_regmap axg_ao_saradc_mux = {
210 	.data = &(struct clk_regmap_mux_data) {
211 		.offset = AO_SAR_CLK,
212 		.mask = 0x3,
213 		.shift = 9,
214 	},
215 	.hw.init = &(struct clk_init_data){
216 		.name = "ao_saradc_mux",
217 		.ops = &clk_regmap_mux_ops,
218 		.parent_data = (const struct clk_parent_data []) {
219 			{ .fw_name = "xtal", },
220 			{ .hw = &axg_ao_clk81.hw },
221 		},
222 		.num_parents = 2,
223 	},
224 };
225 
226 static struct clk_regmap axg_ao_saradc_div = {
227 	.data = &(struct clk_regmap_div_data) {
228 		.offset = AO_SAR_CLK,
229 		.shift = 0,
230 		.width = 8,
231 	},
232 	.hw.init = &(struct clk_init_data){
233 		.name = "ao_saradc_div",
234 		.ops = &clk_regmap_divider_ops,
235 		.parent_hws = (const struct clk_hw *[]) {
236 			&axg_ao_saradc_mux.hw
237 		},
238 		.num_parents = 1,
239 		.flags = CLK_SET_RATE_PARENT,
240 	},
241 };
242 
243 static struct clk_regmap axg_ao_saradc_gate = {
244 	.data = &(struct clk_regmap_gate_data) {
245 		.offset = AO_SAR_CLK,
246 		.bit_idx = 8,
247 	},
248 	.hw.init = &(struct clk_init_data){
249 		.name = "ao_saradc_gate",
250 		.ops = &clk_regmap_gate_ops,
251 		.parent_hws = (const struct clk_hw *[]) {
252 			&axg_ao_saradc_div.hw
253 		},
254 		.num_parents = 1,
255 		.flags = CLK_SET_RATE_PARENT,
256 	},
257 };
258 
259 static const unsigned int axg_ao_reset[] = {
260 	[RESET_AO_REMOTE]	= 16,
261 	[RESET_AO_I2C_MASTER]	= 18,
262 	[RESET_AO_I2C_SLAVE]	= 19,
263 	[RESET_AO_UART1]	= 17,
264 	[RESET_AO_UART2]	= 22,
265 	[RESET_AO_IR_BLASTER]	= 23,
266 };
267 
268 static struct clk_hw *axg_ao_hw_clks[] = {
269 	[CLKID_AO_REMOTE]	= &axg_ao_remote.hw,
270 	[CLKID_AO_I2C_MASTER]	= &axg_ao_i2c_master.hw,
271 	[CLKID_AO_I2C_SLAVE]	= &axg_ao_i2c_slave.hw,
272 	[CLKID_AO_UART1]	= &axg_ao_uart1.hw,
273 	[CLKID_AO_UART2]	= &axg_ao_uart2.hw,
274 	[CLKID_AO_IR_BLASTER]	= &axg_ao_ir_blaster.hw,
275 	[CLKID_AO_SAR_ADC]	= &axg_ao_saradc.hw,
276 	[CLKID_AO_CLK81]	= &axg_ao_clk81.hw,
277 	[CLKID_AO_SAR_ADC_SEL]	= &axg_ao_saradc_mux.hw,
278 	[CLKID_AO_SAR_ADC_DIV]	= &axg_ao_saradc_div.hw,
279 	[CLKID_AO_SAR_ADC_CLK]	= &axg_ao_saradc_gate.hw,
280 	[CLKID_AO_CTS_OSCIN]	= &axg_ao_cts_oscin.hw,
281 	[CLKID_AO_32K_PRE]	= &axg_ao_32k_pre.hw,
282 	[CLKID_AO_32K_DIV]	= &axg_ao_32k_div.hw,
283 	[CLKID_AO_32K_SEL]	= &axg_ao_32k_sel.hw,
284 	[CLKID_AO_32K]		= &axg_ao_32k.hw,
285 	[CLKID_AO_CTS_RTC_OSCIN] = &axg_ao_cts_rtc_oscin.hw,
286 };
287 
288 static const struct meson_aoclk_data axg_ao_clkc_data = {
289 	.reset_reg	= AO_RTI_GEN_CNTL_REG0,
290 	.num_reset	= ARRAY_SIZE(axg_ao_reset),
291 	.reset		= axg_ao_reset,
292 	.clkc_data	= {
293 		.hw_clks = {
294 			.hws	= axg_ao_hw_clks,
295 			.num	= ARRAY_SIZE(axg_ao_hw_clks),
296 		},
297 	},
298 };
299 
300 static const struct of_device_id axg_ao_clkc_match_table[] = {
301 	{
302 		.compatible	= "amlogic,meson-axg-aoclkc",
303 		.data		= &axg_ao_clkc_data.clkc_data,
304 	},
305 	{ }
306 };
307 MODULE_DEVICE_TABLE(of, axg_ao_clkc_match_table);
308 
309 static struct platform_driver axg_ao_clkc_driver = {
310 	.probe		= meson_aoclkc_probe,
311 	.driver		= {
312 		.name	= "axg-ao-clkc",
313 		.of_match_table = axg_ao_clkc_match_table,
314 	},
315 };
316 module_platform_driver(axg_ao_clkc_driver);
317 
318 MODULE_DESCRIPTION("Amlogic AXG Always-ON Clock Controller driver");
319 MODULE_LICENSE("GPL");
320 MODULE_IMPORT_NS("CLK_MESON");
321