File Index
Files and directories
Sign in
FILE

axg-aoclk.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/meson/axg-aoclk.c C
  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
 37static 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
 43static AXG_AO_GATE(remote,	0, CLK_IGNORE_UNUSED);
 44static AXG_AO_GATE(i2c_master,	1, CLK_IGNORE_UNUSED);
 45static AXG_AO_GATE(i2c_slave,	2, CLK_IGNORE_UNUSED);
 46static AXG_AO_GATE(uart1,	3, CLK_IGNORE_UNUSED);
 47static AXG_AO_GATE(uart2,	5, CLK_IGNORE_UNUSED);
 48static AXG_AO_GATE(ir_blaster,	6, CLK_IGNORE_UNUSED);
 49static AXG_AO_GATE(saradc,	7, CLK_IGNORE_UNUSED);
 50
 51static 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
 66static 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
 81static 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
 91static 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
130static 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
149static 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
165static 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
184static 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
209static 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
226static 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
243static 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
259static 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
268static 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
288static 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
300static 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};
307MODULE_DEVICE_TABLE(of, axg_ao_clkc_match_table);
308
309static 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};
316module_platform_driver(axg_ao_clkc_driver);
317
318MODULE_DESCRIPTION("Amlogic AXG Always-ON Clock Controller driver");
319MODULE_LICENSE("GPL");
320MODULE_IMPORT_NS("CLK_MESON");
~/ Read-only file preview.