Linux Audio

Check our new training course

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