1 // SPDX-License-Identifier: GPL-2.0+
3 * Amlogic Meson-AXG Clock Controller Driver
5 * Copyright (c) 2016 Baylibre SAS.
6 * Author: Michael Turquette <mturquette@baylibre.com>
8 * Copyright (c) 2018 Amlogic, inc.
9 * Author: Qiufang Dai <qiufang.dai@amlogic.com>
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"
18 #include "clk-regmap.h"
19 #include "clk-dualdiv.h"
21 #include <dt-bindings/clock/axg-aoclkc.h>
22 #include <dt-bindings/reset/axg-aoclkc.h>
25 * AO Configuration Clock registers offsets
26 * Register offsets from the data sheet must be multiplied by 4.
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
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), \
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", \
50 .flags = CLK_IGNORE_UNUSED, \
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);
62 static struct clk_regmap axg_aoclk_cts_oscin
= {
63 .data
= &(struct clk_regmap_gate_data
){
64 .offset
= AO_RTI_PWR_CNTL_REG0
,
67 .hw
.init
= &(struct clk_init_data
){
69 .ops
= &clk_regmap_gate_ro_ops
,
70 .parent_data
= &(const struct clk_parent_data
) {
77 static struct clk_regmap axg_aoclk_32k_pre
= {
78 .data
= &(struct clk_regmap_gate_data
){
79 .offset
= AO_RTC_ALT_CLK_CNTL0
,
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
92 static const struct meson_clk_dualdiv_param axg_32k_div_table
[] = {
102 static struct clk_regmap axg_aoclk_32k_div
= {
103 .data
= &(struct meson_clk_dualdiv_data
){
105 .reg_off
= AO_RTC_ALT_CLK_CNTL0
,
110 .reg_off
= AO_RTC_ALT_CLK_CNTL0
,
115 .reg_off
= AO_RTC_ALT_CLK_CNTL1
,
120 .reg_off
= AO_RTC_ALT_CLK_CNTL1
,
125 .reg_off
= AO_RTC_ALT_CLK_CNTL0
,
129 .table
= axg_32k_div_table
,
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
141 static struct clk_regmap axg_aoclk_32k_sel
= {
142 .data
= &(struct clk_regmap_mux_data
) {
143 .offset
= AO_RTC_ALT_CLK_CNTL1
,
146 .flags
= CLK_MUX_ROUND_CLOSEST
,
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
,
156 .flags
= CLK_SET_RATE_PARENT
,
160 static struct clk_regmap axg_aoclk_32k
= {
161 .data
= &(struct clk_regmap_gate_data
){
162 .offset
= AO_RTC_ALT_CLK_CNTL0
,
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
172 .flags
= CLK_SET_RATE_PARENT
,
176 static struct clk_regmap axg_aoclk_cts_rtc_oscin
= {
177 .data
= &(struct clk_regmap_mux_data
) {
178 .offset
= AO_RTI_PWR_CNTL_REG0
,
181 .flags
= CLK_MUX_ROUND_CLOSEST
,
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", },
191 .flags
= CLK_SET_RATE_PARENT
,
195 static struct clk_regmap axg_aoclk_clk81
= {
196 .data
= &(struct clk_regmap_mux_data
) {
197 .offset
= AO_RTI_PWR_CNTL_REG0
,
200 .flags
= CLK_MUX_ROUND_CLOSEST
,
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
},
210 .flags
= CLK_SET_RATE_PARENT
,
214 static struct clk_regmap axg_aoclk_saradc_mux
= {
215 .data
= &(struct clk_regmap_mux_data
) {
216 .offset
= AO_SAR_CLK
,
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
},
231 static struct clk_regmap axg_aoclk_saradc_div
= {
232 .data
= &(struct clk_regmap_div_data
) {
233 .offset
= AO_SAR_CLK
,
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
244 .flags
= CLK_SET_RATE_PARENT
,
248 static struct clk_regmap axg_aoclk_saradc_gate
= {
249 .data
= &(struct clk_regmap_gate_data
) {
250 .offset
= AO_SAR_CLK
,
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
260 .flags
= CLK_SET_RATE_PARENT
,
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,
273 static struct clk_regmap
*axg_aoclk_regmap
[] = {
275 &axg_aoclk_i2c_master
,
276 &axg_aoclk_i2c_slave
,
279 &axg_aoclk_ir_blaster
,
281 &axg_aoclk_cts_oscin
,
286 &axg_aoclk_cts_rtc_oscin
,
288 &axg_aoclk_saradc_mux
,
289 &axg_aoclk_saradc_div
,
290 &axg_aoclk_saradc_gate
,
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
,
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
,
320 .hws
= axg_aoclk_hw_clks
,
321 .num
= ARRAY_SIZE(axg_aoclk_hw_clks
),
325 static const struct of_device_id axg_aoclkc_match_table
[] = {
327 .compatible
= "amlogic,meson-axg-aoclkc",
328 .data
= &axg_aoclkc_data
,
332 MODULE_DEVICE_TABLE(of
, axg_aoclkc_match_table
);
334 static struct platform_driver axg_aoclkc_driver
= {
335 .probe
= meson_aoclkc_probe
,
337 .name
= "axg-aoclkc",
338 .of_match_table
= axg_aoclkc_match_table
,
341 module_platform_driver(axg_aoclkc_driver
);
343 MODULE_DESCRIPTION("Amlogic AXG Always-ON Clock Controller driver");
344 MODULE_LICENSE("GPL");
345 MODULE_IMPORT_NS(CLK_MESON
);