1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
3 * Copyright (c) 2016 BayLibre, SAS.
4 * Author: Neil Armstrong <narmstrong@baylibre.com>
6 #include <linux/platform_device.h>
7 #include <linux/mfd/syscon.h>
8 #include "meson-aoclk.h"
9 #include "gxbb-aoclk.h"
11 #include "clk-regmap.h"
12 #include "clk-dualdiv.h"
14 /* AO Configuration Clock registers offsets */
15 #define AO_RTI_PWR_CNTL_REG1 0x0c
16 #define AO_RTI_PWR_CNTL_REG0 0x10
17 #define AO_RTI_GEN_CNTL_REG0 0x40
18 #define AO_OSCIN_CNTL 0x58
19 #define AO_CRT_CLK_CNTL1 0x68
20 #define AO_RTC_ALT_CLK_CNTL0 0x94
21 #define AO_RTC_ALT_CLK_CNTL1 0x98
23 #define GXBB_AO_GATE(_name, _bit) \
24 static struct clk_regmap _name##_ao = { \
25 .data = &(struct clk_regmap_gate_data) { \
26 .offset = AO_RTI_GEN_CNTL_REG0, \
29 .hw.init = &(struct clk_init_data) { \
30 .name = #_name "_ao", \
31 .ops = &clk_regmap_gate_ops, \
32 .parent_data = &(const struct clk_parent_data) { \
33 .fw_name = "mpeg-clk", \
36 .flags = CLK_IGNORE_UNUSED, \
40 GXBB_AO_GATE(remote
, 0);
41 GXBB_AO_GATE(i2c_master
, 1);
42 GXBB_AO_GATE(i2c_slave
, 2);
43 GXBB_AO_GATE(uart1
, 3);
44 GXBB_AO_GATE(uart2
, 5);
45 GXBB_AO_GATE(ir_blaster
, 6);
47 static struct clk_regmap ao_cts_oscin
= {
48 .data
= &(struct clk_regmap_gate_data
){
49 .offset
= AO_RTI_PWR_CNTL_REG0
,
52 .hw
.init
= &(struct clk_init_data
){
53 .name
= "ao_cts_oscin",
54 .ops
= &clk_regmap_gate_ro_ops
,
55 .parent_data
= &(const struct clk_parent_data
) {
62 static struct clk_regmap ao_32k_pre
= {
63 .data
= &(struct clk_regmap_gate_data
){
64 .offset
= AO_RTC_ALT_CLK_CNTL0
,
67 .hw
.init
= &(struct clk_init_data
){
69 .ops
= &clk_regmap_gate_ops
,
70 .parent_hws
= (const struct clk_hw
*[]) { &ao_cts_oscin
.hw
},
75 static const struct meson_clk_dualdiv_param gxbb_32k_div_table
[] = {
85 static struct clk_regmap ao_32k_div
= {
86 .data
= &(struct meson_clk_dualdiv_data
){
88 .reg_off
= AO_RTC_ALT_CLK_CNTL0
,
93 .reg_off
= AO_RTC_ALT_CLK_CNTL0
,
98 .reg_off
= AO_RTC_ALT_CLK_CNTL1
,
103 .reg_off
= AO_RTC_ALT_CLK_CNTL1
,
108 .reg_off
= AO_RTC_ALT_CLK_CNTL0
,
112 .table
= gxbb_32k_div_table
,
114 .hw
.init
= &(struct clk_init_data
){
115 .name
= "ao_32k_div",
116 .ops
= &meson_clk_dualdiv_ops
,
117 .parent_hws
= (const struct clk_hw
*[]) { &ao_32k_pre
.hw
},
122 static struct clk_regmap ao_32k_sel
= {
123 .data
= &(struct clk_regmap_mux_data
) {
124 .offset
= AO_RTC_ALT_CLK_CNTL1
,
127 .flags
= CLK_MUX_ROUND_CLOSEST
,
129 .hw
.init
= &(struct clk_init_data
){
130 .name
= "ao_32k_sel",
131 .ops
= &clk_regmap_mux_ops
,
132 .parent_hws
= (const struct clk_hw
*[]) {
137 .flags
= CLK_SET_RATE_PARENT
,
141 static struct clk_regmap ao_32k
= {
142 .data
= &(struct clk_regmap_gate_data
){
143 .offset
= AO_RTC_ALT_CLK_CNTL0
,
146 .hw
.init
= &(struct clk_init_data
){
148 .ops
= &clk_regmap_gate_ops
,
149 .parent_hws
= (const struct clk_hw
*[]) { &ao_32k_sel
.hw
},
151 .flags
= CLK_SET_RATE_PARENT
,
155 static struct clk_regmap ao_cts_rtc_oscin
= {
156 .data
= &(struct clk_regmap_mux_data
) {
157 .offset
= AO_RTI_PWR_CNTL_REG0
,
160 .table
= (u32
[]){ 1, 2, 3, 4 },
161 .flags
= CLK_MUX_ROUND_CLOSEST
,
163 .hw
.init
= &(struct clk_init_data
){
164 .name
= "ao_cts_rtc_oscin",
165 .ops
= &clk_regmap_mux_ops
,
166 .parent_data
= (const struct clk_parent_data
[]) {
167 { .fw_name
= "ext-32k-0", },
168 { .fw_name
= "ext-32k-1", },
169 { .fw_name
= "ext-32k-2", },
170 { .hw
= &ao_32k
.hw
},
173 .flags
= CLK_SET_RATE_PARENT
,
177 static struct clk_regmap ao_clk81
= {
178 .data
= &(struct clk_regmap_mux_data
) {
179 .offset
= AO_RTI_PWR_CNTL_REG0
,
182 .flags
= CLK_MUX_ROUND_CLOSEST
,
184 .hw
.init
= &(struct clk_init_data
){
186 .ops
= &clk_regmap_mux_ro_ops
,
187 .parent_data
= (const struct clk_parent_data
[]) {
188 { .fw_name
= "mpeg-clk", },
189 { .hw
= &ao_cts_rtc_oscin
.hw
},
192 .flags
= CLK_SET_RATE_PARENT
,
196 static struct clk_regmap ao_cts_cec
= {
197 .data
= &(struct clk_regmap_mux_data
) {
198 .offset
= AO_CRT_CLK_CNTL1
,
201 .flags
= CLK_MUX_ROUND_CLOSEST
,
203 .hw
.init
= &(struct clk_init_data
){
204 .name
= "ao_cts_cec",
205 .ops
= &clk_regmap_mux_ops
,
207 * FIXME: The 'fixme' parent obviously does not exist.
209 * ATM, CCF won't call get_parent() if num_parents is 1. It
210 * does not allow NULL as a parent name either.
212 * On this particular mux, we only know the input #1 parent
213 * but, on boot, unknown input #0 is set, so it is critical
214 * to call .get_parent() on it
216 * Until CCF gets fixed, adding this fake parent that won't
217 * ever be registered should work around the problem
219 .parent_data
= (const struct clk_parent_data
[]) {
220 { .name
= "fixme", .index
= -1, },
221 { .hw
= &ao_cts_rtc_oscin
.hw
},
224 .flags
= CLK_SET_RATE_PARENT
,
228 static const unsigned int gxbb_aoclk_reset
[] = {
229 [RESET_AO_REMOTE
] = 16,
230 [RESET_AO_I2C_MASTER
] = 18,
231 [RESET_AO_I2C_SLAVE
] = 19,
232 [RESET_AO_UART1
] = 17,
233 [RESET_AO_UART2
] = 22,
234 [RESET_AO_IR_BLASTER
] = 23,
237 static struct clk_regmap
*gxbb_aoclk
[] = {
254 static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data
= {
256 [CLKID_AO_REMOTE
] = &remote_ao
.hw
,
257 [CLKID_AO_I2C_MASTER
] = &i2c_master_ao
.hw
,
258 [CLKID_AO_I2C_SLAVE
] = &i2c_slave_ao
.hw
,
259 [CLKID_AO_UART1
] = &uart1_ao
.hw
,
260 [CLKID_AO_UART2
] = &uart2_ao
.hw
,
261 [CLKID_AO_IR_BLASTER
] = &ir_blaster_ao
.hw
,
262 [CLKID_AO_CEC_32K
] = &ao_cts_cec
.hw
,
263 [CLKID_AO_CTS_OSCIN
] = &ao_cts_oscin
.hw
,
264 [CLKID_AO_32K_PRE
] = &ao_32k_pre
.hw
,
265 [CLKID_AO_32K_DIV
] = &ao_32k_div
.hw
,
266 [CLKID_AO_32K_SEL
] = &ao_32k_sel
.hw
,
267 [CLKID_AO_32K
] = &ao_32k
.hw
,
268 [CLKID_AO_CTS_RTC_OSCIN
] = &ao_cts_rtc_oscin
.hw
,
269 [CLKID_AO_CLK81
] = &ao_clk81
.hw
,
274 static const struct meson_aoclk_data gxbb_aoclkc_data
= {
275 .reset_reg
= AO_RTI_GEN_CNTL_REG0
,
276 .num_reset
= ARRAY_SIZE(gxbb_aoclk_reset
),
277 .reset
= gxbb_aoclk_reset
,
278 .num_clks
= ARRAY_SIZE(gxbb_aoclk
),
280 .hw_data
= &gxbb_aoclk_onecell_data
,
283 static const struct of_device_id gxbb_aoclkc_match_table
[] = {
285 .compatible
= "amlogic,meson-gx-aoclkc",
286 .data
= &gxbb_aoclkc_data
,
291 static struct platform_driver gxbb_aoclkc_driver
= {
292 .probe
= meson_aoclkc_probe
,
294 .name
= "gxbb-aoclkc",
295 .of_match_table
= gxbb_aoclkc_match_table
,
298 builtin_platform_driver(gxbb_aoclkc_driver
);