0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/clk-provider.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/reset-controller.h>
0014 #include <linux/mfd/syscon.h>
0015 #include <linux/module.h>
0016 #include "meson-aoclk.h"
0017 #include "g12a-aoclk.h"
0018
0019 #include "clk-regmap.h"
0020 #include "clk-dualdiv.h"
0021
0022
0023
0024
0025
0026 #define AO_RTI_STATUS_REG3 0x0C
0027 #define AO_RTI_PWR_CNTL_REG0 0x10
0028 #define AO_RTI_GEN_CNTL_REG0 0x40
0029 #define AO_CLK_GATE0 0x4c
0030 #define AO_CLK_GATE0_SP 0x50
0031 #define AO_OSCIN_CNTL 0x58
0032 #define AO_CEC_CLK_CNTL_REG0 0x74
0033 #define AO_CEC_CLK_CNTL_REG1 0x78
0034 #define AO_SAR_CLK 0x90
0035 #define AO_RTC_ALT_CLK_CNTL0 0x94
0036 #define AO_RTC_ALT_CLK_CNTL1 0x98
0037
0038
0039
0040
0041
0042
0043
0044 #define AXG_AO_GATE(_name, _reg, _bit) \
0045 static struct clk_regmap g12a_aoclk_##_name = { \
0046 .data = &(struct clk_regmap_gate_data) { \
0047 .offset = (_reg), \
0048 .bit_idx = (_bit), \
0049 }, \
0050 .hw.init = &(struct clk_init_data) { \
0051 .name = "g12a_ao_" #_name, \
0052 .ops = &clk_regmap_gate_ops, \
0053 .parent_data = &(const struct clk_parent_data) { \
0054 .fw_name = "mpeg-clk", \
0055 }, \
0056 .num_parents = 1, \
0057 .flags = CLK_IGNORE_UNUSED, \
0058 }, \
0059 }
0060
0061 AXG_AO_GATE(ahb, AO_CLK_GATE0, 0);
0062 AXG_AO_GATE(ir_in, AO_CLK_GATE0, 1);
0063 AXG_AO_GATE(i2c_m0, AO_CLK_GATE0, 2);
0064 AXG_AO_GATE(i2c_s0, AO_CLK_GATE0, 3);
0065 AXG_AO_GATE(uart, AO_CLK_GATE0, 4);
0066 AXG_AO_GATE(prod_i2c, AO_CLK_GATE0, 5);
0067 AXG_AO_GATE(uart2, AO_CLK_GATE0, 6);
0068 AXG_AO_GATE(ir_out, AO_CLK_GATE0, 7);
0069 AXG_AO_GATE(saradc, AO_CLK_GATE0, 8);
0070 AXG_AO_GATE(mailbox, AO_CLK_GATE0_SP, 0);
0071 AXG_AO_GATE(m3, AO_CLK_GATE0_SP, 1);
0072 AXG_AO_GATE(ahb_sram, AO_CLK_GATE0_SP, 2);
0073 AXG_AO_GATE(rti, AO_CLK_GATE0_SP, 3);
0074 AXG_AO_GATE(m4_fclk, AO_CLK_GATE0_SP, 4);
0075 AXG_AO_GATE(m4_hclk, AO_CLK_GATE0_SP, 5);
0076
0077 static struct clk_regmap g12a_aoclk_cts_oscin = {
0078 .data = &(struct clk_regmap_gate_data){
0079 .offset = AO_RTI_PWR_CNTL_REG0,
0080 .bit_idx = 14,
0081 },
0082 .hw.init = &(struct clk_init_data){
0083 .name = "cts_oscin",
0084 .ops = &clk_regmap_gate_ro_ops,
0085 .parent_data = &(const struct clk_parent_data) {
0086 .fw_name = "xtal",
0087 },
0088 .num_parents = 1,
0089 },
0090 };
0091
0092 static const struct meson_clk_dualdiv_param g12a_32k_div_table[] = {
0093 {
0094 .dual = 1,
0095 .n1 = 733,
0096 .m1 = 8,
0097 .n2 = 732,
0098 .m2 = 11,
0099 }, {}
0100 };
0101
0102
0103
0104 static struct clk_regmap g12a_aoclk_32k_by_oscin_pre = {
0105 .data = &(struct clk_regmap_gate_data){
0106 .offset = AO_RTC_ALT_CLK_CNTL0,
0107 .bit_idx = 31,
0108 },
0109 .hw.init = &(struct clk_init_data){
0110 .name = "g12a_ao_32k_by_oscin_pre",
0111 .ops = &clk_regmap_gate_ops,
0112 .parent_hws = (const struct clk_hw *[]) {
0113 &g12a_aoclk_cts_oscin.hw
0114 },
0115 .num_parents = 1,
0116 },
0117 };
0118
0119 static struct clk_regmap g12a_aoclk_32k_by_oscin_div = {
0120 .data = &(struct meson_clk_dualdiv_data){
0121 .n1 = {
0122 .reg_off = AO_RTC_ALT_CLK_CNTL0,
0123 .shift = 0,
0124 .width = 12,
0125 },
0126 .n2 = {
0127 .reg_off = AO_RTC_ALT_CLK_CNTL0,
0128 .shift = 12,
0129 .width = 12,
0130 },
0131 .m1 = {
0132 .reg_off = AO_RTC_ALT_CLK_CNTL1,
0133 .shift = 0,
0134 .width = 12,
0135 },
0136 .m2 = {
0137 .reg_off = AO_RTC_ALT_CLK_CNTL1,
0138 .shift = 12,
0139 .width = 12,
0140 },
0141 .dual = {
0142 .reg_off = AO_RTC_ALT_CLK_CNTL0,
0143 .shift = 28,
0144 .width = 1,
0145 },
0146 .table = g12a_32k_div_table,
0147 },
0148 .hw.init = &(struct clk_init_data){
0149 .name = "g12a_ao_32k_by_oscin_div",
0150 .ops = &meson_clk_dualdiv_ops,
0151 .parent_hws = (const struct clk_hw *[]) {
0152 &g12a_aoclk_32k_by_oscin_pre.hw
0153 },
0154 .num_parents = 1,
0155 },
0156 };
0157
0158 static struct clk_regmap g12a_aoclk_32k_by_oscin_sel = {
0159 .data = &(struct clk_regmap_mux_data) {
0160 .offset = AO_RTC_ALT_CLK_CNTL1,
0161 .mask = 0x1,
0162 .shift = 24,
0163 .flags = CLK_MUX_ROUND_CLOSEST,
0164 },
0165 .hw.init = &(struct clk_init_data){
0166 .name = "g12a_ao_32k_by_oscin_sel",
0167 .ops = &clk_regmap_mux_ops,
0168 .parent_hws = (const struct clk_hw *[]) {
0169 &g12a_aoclk_32k_by_oscin_div.hw,
0170 &g12a_aoclk_32k_by_oscin_pre.hw,
0171 },
0172 .num_parents = 2,
0173 .flags = CLK_SET_RATE_PARENT,
0174 },
0175 };
0176
0177 static struct clk_regmap g12a_aoclk_32k_by_oscin = {
0178 .data = &(struct clk_regmap_gate_data){
0179 .offset = AO_RTC_ALT_CLK_CNTL0,
0180 .bit_idx = 30,
0181 },
0182 .hw.init = &(struct clk_init_data){
0183 .name = "g12a_ao_32k_by_oscin",
0184 .ops = &clk_regmap_gate_ops,
0185 .parent_hws = (const struct clk_hw *[]) {
0186 &g12a_aoclk_32k_by_oscin_sel.hw
0187 },
0188 .num_parents = 1,
0189 .flags = CLK_SET_RATE_PARENT,
0190 },
0191 };
0192
0193
0194
0195 static struct clk_regmap g12a_aoclk_cec_pre = {
0196 .data = &(struct clk_regmap_gate_data){
0197 .offset = AO_CEC_CLK_CNTL_REG0,
0198 .bit_idx = 31,
0199 },
0200 .hw.init = &(struct clk_init_data){
0201 .name = "g12a_ao_cec_pre",
0202 .ops = &clk_regmap_gate_ops,
0203 .parent_hws = (const struct clk_hw *[]) {
0204 &g12a_aoclk_cts_oscin.hw
0205 },
0206 .num_parents = 1,
0207 },
0208 };
0209
0210 static struct clk_regmap g12a_aoclk_cec_div = {
0211 .data = &(struct meson_clk_dualdiv_data){
0212 .n1 = {
0213 .reg_off = AO_CEC_CLK_CNTL_REG0,
0214 .shift = 0,
0215 .width = 12,
0216 },
0217 .n2 = {
0218 .reg_off = AO_CEC_CLK_CNTL_REG0,
0219 .shift = 12,
0220 .width = 12,
0221 },
0222 .m1 = {
0223 .reg_off = AO_CEC_CLK_CNTL_REG1,
0224 .shift = 0,
0225 .width = 12,
0226 },
0227 .m2 = {
0228 .reg_off = AO_CEC_CLK_CNTL_REG1,
0229 .shift = 12,
0230 .width = 12,
0231 },
0232 .dual = {
0233 .reg_off = AO_CEC_CLK_CNTL_REG0,
0234 .shift = 28,
0235 .width = 1,
0236 },
0237 .table = g12a_32k_div_table,
0238 },
0239 .hw.init = &(struct clk_init_data){
0240 .name = "g12a_ao_cec_div",
0241 .ops = &meson_clk_dualdiv_ops,
0242 .parent_hws = (const struct clk_hw *[]) {
0243 &g12a_aoclk_cec_pre.hw
0244 },
0245 .num_parents = 1,
0246 },
0247 };
0248
0249 static struct clk_regmap g12a_aoclk_cec_sel = {
0250 .data = &(struct clk_regmap_mux_data) {
0251 .offset = AO_CEC_CLK_CNTL_REG1,
0252 .mask = 0x1,
0253 .shift = 24,
0254 .flags = CLK_MUX_ROUND_CLOSEST,
0255 },
0256 .hw.init = &(struct clk_init_data){
0257 .name = "g12a_ao_cec_sel",
0258 .ops = &clk_regmap_mux_ops,
0259 .parent_hws = (const struct clk_hw *[]) {
0260 &g12a_aoclk_cec_div.hw,
0261 &g12a_aoclk_cec_pre.hw,
0262 },
0263 .num_parents = 2,
0264 .flags = CLK_SET_RATE_PARENT,
0265 },
0266 };
0267
0268 static struct clk_regmap g12a_aoclk_cec = {
0269 .data = &(struct clk_regmap_gate_data){
0270 .offset = AO_CEC_CLK_CNTL_REG0,
0271 .bit_idx = 30,
0272 },
0273 .hw.init = &(struct clk_init_data){
0274 .name = "g12a_ao_cec",
0275 .ops = &clk_regmap_gate_ops,
0276 .parent_hws = (const struct clk_hw *[]) {
0277 &g12a_aoclk_cec_sel.hw
0278 },
0279 .num_parents = 1,
0280 .flags = CLK_SET_RATE_PARENT,
0281 },
0282 };
0283
0284 static struct clk_regmap g12a_aoclk_cts_rtc_oscin = {
0285 .data = &(struct clk_regmap_mux_data) {
0286 .offset = AO_RTI_PWR_CNTL_REG0,
0287 .mask = 0x1,
0288 .shift = 10,
0289 .flags = CLK_MUX_ROUND_CLOSEST,
0290 },
0291 .hw.init = &(struct clk_init_data){
0292 .name = "g12a_ao_cts_rtc_oscin",
0293 .ops = &clk_regmap_mux_ops,
0294 .parent_data = (const struct clk_parent_data []) {
0295 { .hw = &g12a_aoclk_32k_by_oscin.hw },
0296 { .fw_name = "ext-32k-0", },
0297 },
0298 .num_parents = 2,
0299 .flags = CLK_SET_RATE_PARENT,
0300 },
0301 };
0302
0303 static struct clk_regmap g12a_aoclk_clk81 = {
0304 .data = &(struct clk_regmap_mux_data) {
0305 .offset = AO_RTI_PWR_CNTL_REG0,
0306 .mask = 0x1,
0307 .shift = 8,
0308 .flags = CLK_MUX_ROUND_CLOSEST,
0309 },
0310 .hw.init = &(struct clk_init_data){
0311 .name = "g12a_ao_clk81",
0312 .ops = &clk_regmap_mux_ro_ops,
0313 .parent_data = (const struct clk_parent_data []) {
0314 { .fw_name = "mpeg-clk", },
0315 { .hw = &g12a_aoclk_cts_rtc_oscin.hw },
0316 },
0317 .num_parents = 2,
0318 .flags = CLK_SET_RATE_PARENT,
0319 },
0320 };
0321
0322 static struct clk_regmap g12a_aoclk_saradc_mux = {
0323 .data = &(struct clk_regmap_mux_data) {
0324 .offset = AO_SAR_CLK,
0325 .mask = 0x3,
0326 .shift = 9,
0327 },
0328 .hw.init = &(struct clk_init_data){
0329 .name = "g12a_ao_saradc_mux",
0330 .ops = &clk_regmap_mux_ops,
0331 .parent_data = (const struct clk_parent_data []) {
0332 { .fw_name = "xtal", },
0333 { .hw = &g12a_aoclk_clk81.hw },
0334 },
0335 .num_parents = 2,
0336 },
0337 };
0338
0339 static struct clk_regmap g12a_aoclk_saradc_div = {
0340 .data = &(struct clk_regmap_div_data) {
0341 .offset = AO_SAR_CLK,
0342 .shift = 0,
0343 .width = 8,
0344 },
0345 .hw.init = &(struct clk_init_data){
0346 .name = "g12a_ao_saradc_div",
0347 .ops = &clk_regmap_divider_ops,
0348 .parent_hws = (const struct clk_hw *[]) {
0349 &g12a_aoclk_saradc_mux.hw
0350 },
0351 .num_parents = 1,
0352 .flags = CLK_SET_RATE_PARENT,
0353 },
0354 };
0355
0356 static struct clk_regmap g12a_aoclk_saradc_gate = {
0357 .data = &(struct clk_regmap_gate_data) {
0358 .offset = AO_SAR_CLK,
0359 .bit_idx = 8,
0360 },
0361 .hw.init = &(struct clk_init_data){
0362 .name = "g12a_ao_saradc_gate",
0363 .ops = &clk_regmap_gate_ops,
0364 .parent_hws = (const struct clk_hw *[]) {
0365 &g12a_aoclk_saradc_div.hw
0366 },
0367 .num_parents = 1,
0368 .flags = CLK_SET_RATE_PARENT,
0369 },
0370 };
0371
0372 static const unsigned int g12a_aoclk_reset[] = {
0373 [RESET_AO_IR_IN] = 16,
0374 [RESET_AO_UART] = 17,
0375 [RESET_AO_I2C_M] = 18,
0376 [RESET_AO_I2C_S] = 19,
0377 [RESET_AO_SAR_ADC] = 20,
0378 [RESET_AO_UART2] = 22,
0379 [RESET_AO_IR_OUT] = 23,
0380 };
0381
0382 static struct clk_regmap *g12a_aoclk_regmap[] = {
0383 &g12a_aoclk_ahb,
0384 &g12a_aoclk_ir_in,
0385 &g12a_aoclk_i2c_m0,
0386 &g12a_aoclk_i2c_s0,
0387 &g12a_aoclk_uart,
0388 &g12a_aoclk_prod_i2c,
0389 &g12a_aoclk_uart2,
0390 &g12a_aoclk_ir_out,
0391 &g12a_aoclk_saradc,
0392 &g12a_aoclk_mailbox,
0393 &g12a_aoclk_m3,
0394 &g12a_aoclk_ahb_sram,
0395 &g12a_aoclk_rti,
0396 &g12a_aoclk_m4_fclk,
0397 &g12a_aoclk_m4_hclk,
0398 &g12a_aoclk_cts_oscin,
0399 &g12a_aoclk_32k_by_oscin_pre,
0400 &g12a_aoclk_32k_by_oscin_div,
0401 &g12a_aoclk_32k_by_oscin_sel,
0402 &g12a_aoclk_32k_by_oscin,
0403 &g12a_aoclk_cec_pre,
0404 &g12a_aoclk_cec_div,
0405 &g12a_aoclk_cec_sel,
0406 &g12a_aoclk_cec,
0407 &g12a_aoclk_cts_rtc_oscin,
0408 &g12a_aoclk_clk81,
0409 &g12a_aoclk_saradc_mux,
0410 &g12a_aoclk_saradc_div,
0411 &g12a_aoclk_saradc_gate,
0412 };
0413
0414 static const struct clk_hw_onecell_data g12a_aoclk_onecell_data = {
0415 .hws = {
0416 [CLKID_AO_AHB] = &g12a_aoclk_ahb.hw,
0417 [CLKID_AO_IR_IN] = &g12a_aoclk_ir_in.hw,
0418 [CLKID_AO_I2C_M0] = &g12a_aoclk_i2c_m0.hw,
0419 [CLKID_AO_I2C_S0] = &g12a_aoclk_i2c_s0.hw,
0420 [CLKID_AO_UART] = &g12a_aoclk_uart.hw,
0421 [CLKID_AO_PROD_I2C] = &g12a_aoclk_prod_i2c.hw,
0422 [CLKID_AO_UART2] = &g12a_aoclk_uart2.hw,
0423 [CLKID_AO_IR_OUT] = &g12a_aoclk_ir_out.hw,
0424 [CLKID_AO_SAR_ADC] = &g12a_aoclk_saradc.hw,
0425 [CLKID_AO_MAILBOX] = &g12a_aoclk_mailbox.hw,
0426 [CLKID_AO_M3] = &g12a_aoclk_m3.hw,
0427 [CLKID_AO_AHB_SRAM] = &g12a_aoclk_ahb_sram.hw,
0428 [CLKID_AO_RTI] = &g12a_aoclk_rti.hw,
0429 [CLKID_AO_M4_FCLK] = &g12a_aoclk_m4_fclk.hw,
0430 [CLKID_AO_M4_HCLK] = &g12a_aoclk_m4_hclk.hw,
0431 [CLKID_AO_CLK81] = &g12a_aoclk_clk81.hw,
0432 [CLKID_AO_SAR_ADC_SEL] = &g12a_aoclk_saradc_mux.hw,
0433 [CLKID_AO_SAR_ADC_DIV] = &g12a_aoclk_saradc_div.hw,
0434 [CLKID_AO_SAR_ADC_CLK] = &g12a_aoclk_saradc_gate.hw,
0435 [CLKID_AO_CTS_OSCIN] = &g12a_aoclk_cts_oscin.hw,
0436 [CLKID_AO_32K_PRE] = &g12a_aoclk_32k_by_oscin_pre.hw,
0437 [CLKID_AO_32K_DIV] = &g12a_aoclk_32k_by_oscin_div.hw,
0438 [CLKID_AO_32K_SEL] = &g12a_aoclk_32k_by_oscin_sel.hw,
0439 [CLKID_AO_32K] = &g12a_aoclk_32k_by_oscin.hw,
0440 [CLKID_AO_CEC_PRE] = &g12a_aoclk_cec_pre.hw,
0441 [CLKID_AO_CEC_DIV] = &g12a_aoclk_cec_div.hw,
0442 [CLKID_AO_CEC_SEL] = &g12a_aoclk_cec_sel.hw,
0443 [CLKID_AO_CEC] = &g12a_aoclk_cec.hw,
0444 [CLKID_AO_CTS_RTC_OSCIN] = &g12a_aoclk_cts_rtc_oscin.hw,
0445 },
0446 .num = NR_CLKS,
0447 };
0448
0449 static const struct meson_aoclk_data g12a_aoclkc_data = {
0450 .reset_reg = AO_RTI_GEN_CNTL_REG0,
0451 .num_reset = ARRAY_SIZE(g12a_aoclk_reset),
0452 .reset = g12a_aoclk_reset,
0453 .num_clks = ARRAY_SIZE(g12a_aoclk_regmap),
0454 .clks = g12a_aoclk_regmap,
0455 .hw_data = &g12a_aoclk_onecell_data,
0456 };
0457
0458 static const struct of_device_id g12a_aoclkc_match_table[] = {
0459 {
0460 .compatible = "amlogic,meson-g12a-aoclkc",
0461 .data = &g12a_aoclkc_data,
0462 },
0463 { }
0464 };
0465 MODULE_DEVICE_TABLE(of, g12a_aoclkc_match_table);
0466
0467 static struct platform_driver g12a_aoclkc_driver = {
0468 .probe = meson_aoclkc_probe,
0469 .driver = {
0470 .name = "g12a-aoclkc",
0471 .of_match_table = g12a_aoclkc_match_table,
0472 },
0473 };
0474
0475 module_platform_driver(g12a_aoclkc_driver);
0476 MODULE_LICENSE("GPL v2");