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