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) 2019 Baylibre SAS. 9 * Author: Neil Armstrong <narmstrong@baylibre.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/g12a-aoclkc.h> 22 #include <dt-bindings/reset/g12a-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_STATUS_REG3 0x0C 29 #define AO_RTI_PWR_CNTL_REG0 0x10 30 #define AO_RTI_GEN_CNTL_REG0 0x40 31 #define AO_CLK_GATE0 0x4c 32 #define AO_CLK_GATE0_SP 0x50 33 #define AO_OSCIN_CNTL 0x58 34 #define AO_CEC_CLK_CNTL_REG0 0x74 35 #define AO_CEC_CLK_CNTL_REG1 0x78 36 #define AO_SAR_CLK 0x90 37 #define AO_RTC_ALT_CLK_CNTL0 0x94 38 #define AO_RTC_ALT_CLK_CNTL1 0x98 39 40 static const struct clk_parent_data g12a_ao_pclk_parents = { .fw_name = "mpeg-clk" }; 41 42 #define G12A_AO_PCLK(_name, _reg, _bit, _flags) \ 43 MESON_PCLK(g12a_ao_##_name, _reg, _bit, &g12a_ao_pclk_parents, _flags) 44 45 /* 46 * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons 47 * Users are encouraged to test without it and submit changes to: 48 * - remove the flag if not necessary 49 * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, 50 * if appropriate. 51 * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable 52 * for a particular clock. 53 */ 54 static G12A_AO_PCLK(ahb, AO_CLK_GATE0, 0, CLK_IGNORE_UNUSED); 55 static G12A_AO_PCLK(ir_in, AO_CLK_GATE0, 1, CLK_IGNORE_UNUSED); 56 static G12A_AO_PCLK(i2c_m0, AO_CLK_GATE0, 2, CLK_IGNORE_UNUSED); 57 static G12A_AO_PCLK(i2c_s0, AO_CLK_GATE0, 3, CLK_IGNORE_UNUSED); 58 static G12A_AO_PCLK(uart, AO_CLK_GATE0, 4, CLK_IGNORE_UNUSED); 59 static G12A_AO_PCLK(prod_i2c, AO_CLK_GATE0, 5, CLK_IGNORE_UNUSED); 60 static G12A_AO_PCLK(uart2, AO_CLK_GATE0, 6, CLK_IGNORE_UNUSED); 61 static G12A_AO_PCLK(ir_out, AO_CLK_GATE0, 7, CLK_IGNORE_UNUSED); 62 static G12A_AO_PCLK(saradc, AO_CLK_GATE0, 8, CLK_IGNORE_UNUSED); 63 64 static G12A_AO_PCLK(mailbox, AO_CLK_GATE0_SP, 0, CLK_IGNORE_UNUSED); 65 static G12A_AO_PCLK(m3, AO_CLK_GATE0_SP, 1, CLK_IGNORE_UNUSED); 66 static G12A_AO_PCLK(ahb_sram, AO_CLK_GATE0_SP, 2, CLK_IGNORE_UNUSED); 67 static G12A_AO_PCLK(rti, AO_CLK_GATE0_SP, 3, CLK_IGNORE_UNUSED); 68 static G12A_AO_PCLK(m4_fclk, AO_CLK_GATE0_SP, 4, CLK_IGNORE_UNUSED); 69 static G12A_AO_PCLK(m4_hclk, AO_CLK_GATE0_SP, 5, CLK_IGNORE_UNUSED); 70 71 static struct clk_regmap g12a_ao_cts_oscin = { 72 .data = &(struct clk_regmap_gate_data){ 73 .offset = AO_RTI_PWR_CNTL_REG0, 74 .bit_idx = 14, 75 }, 76 .hw.init = &(struct clk_init_data){ 77 .name = "cts_oscin", 78 .ops = &clk_regmap_gate_ro_ops, 79 .parent_data = &(const struct clk_parent_data) { 80 .fw_name = "xtal", 81 }, 82 .num_parents = 1, 83 }, 84 }; 85 86 static const struct meson_clk_dualdiv_param g12a_32k_div_table[] = { 87 { 88 .dual = 1, 89 .n1 = 733, 90 .m1 = 8, 91 .n2 = 732, 92 .m2 = 11, 93 }, {} 94 }; 95 96 /* 32k_by_oscin clock */ 97 98 static struct clk_regmap g12a_ao_32k_by_oscin_pre = { 99 .data = &(struct clk_regmap_gate_data){ 100 .offset = AO_RTC_ALT_CLK_CNTL0, 101 .bit_idx = 31, 102 }, 103 .hw.init = &(struct clk_init_data){ 104 .name = "ao_32k_by_oscin_pre", 105 .ops = &clk_regmap_gate_ops, 106 .parent_hws = (const struct clk_hw *[]) { 107 &g12a_ao_cts_oscin.hw 108 }, 109 .num_parents = 1, 110 }, 111 }; 112 113 static struct clk_regmap g12a_ao_32k_by_oscin_div = { 114 .data = &(struct meson_clk_dualdiv_data){ 115 .n1 = { 116 .reg_off = AO_RTC_ALT_CLK_CNTL0, 117 .shift = 0, 118 .width = 12, 119 }, 120 .n2 = { 121 .reg_off = AO_RTC_ALT_CLK_CNTL0, 122 .shift = 12, 123 .width = 12, 124 }, 125 .m1 = { 126 .reg_off = AO_RTC_ALT_CLK_CNTL1, 127 .shift = 0, 128 .width = 12, 129 }, 130 .m2 = { 131 .reg_off = AO_RTC_ALT_CLK_CNTL1, 132 .shift = 12, 133 .width = 12, 134 }, 135 .dual = { 136 .reg_off = AO_RTC_ALT_CLK_CNTL0, 137 .shift = 28, 138 .width = 1, 139 }, 140 .table = g12a_32k_div_table, 141 }, 142 .hw.init = &(struct clk_init_data){ 143 .name = "ao_32k_by_oscin_div", 144 .ops = &meson_clk_dualdiv_ops, 145 .parent_hws = (const struct clk_hw *[]) { 146 &g12a_ao_32k_by_oscin_pre.hw 147 }, 148 .num_parents = 1, 149 }, 150 }; 151 152 static struct clk_regmap g12a_ao_32k_by_oscin_sel = { 153 .data = &(struct clk_regmap_mux_data) { 154 .offset = AO_RTC_ALT_CLK_CNTL1, 155 .mask = 0x1, 156 .shift = 24, 157 .flags = CLK_MUX_ROUND_CLOSEST, 158 }, 159 .hw.init = &(struct clk_init_data){ 160 .name = "ao_32k_by_oscin_sel", 161 .ops = &clk_regmap_mux_ops, 162 .parent_hws = (const struct clk_hw *[]) { 163 &g12a_ao_32k_by_oscin_div.hw, 164 &g12a_ao_32k_by_oscin_pre.hw, 165 }, 166 .num_parents = 2, 167 .flags = CLK_SET_RATE_PARENT, 168 }, 169 }; 170 171 static struct clk_regmap g12a_ao_32k_by_oscin = { 172 .data = &(struct clk_regmap_gate_data){ 173 .offset = AO_RTC_ALT_CLK_CNTL0, 174 .bit_idx = 30, 175 }, 176 .hw.init = &(struct clk_init_data){ 177 .name = "ao_32k_by_oscin", 178 .ops = &clk_regmap_gate_ops, 179 .parent_hws = (const struct clk_hw *[]) { 180 &g12a_ao_32k_by_oscin_sel.hw 181 }, 182 .num_parents = 1, 183 .flags = CLK_SET_RATE_PARENT, 184 }, 185 }; 186 187 /* cec clock */ 188 189 static struct clk_regmap g12a_ao_cec_pre = { 190 .data = &(struct clk_regmap_gate_data){ 191 .offset = AO_CEC_CLK_CNTL_REG0, 192 .bit_idx = 31, 193 }, 194 .hw.init = &(struct clk_init_data){ 195 .name = "ao_cec_pre", 196 .ops = &clk_regmap_gate_ops, 197 .parent_hws = (const struct clk_hw *[]) { 198 &g12a_ao_cts_oscin.hw 199 }, 200 .num_parents = 1, 201 }, 202 }; 203 204 static struct clk_regmap g12a_ao_cec_div = { 205 .data = &(struct meson_clk_dualdiv_data){ 206 .n1 = { 207 .reg_off = AO_CEC_CLK_CNTL_REG0, 208 .shift = 0, 209 .width = 12, 210 }, 211 .n2 = { 212 .reg_off = AO_CEC_CLK_CNTL_REG0, 213 .shift = 12, 214 .width = 12, 215 }, 216 .m1 = { 217 .reg_off = AO_CEC_CLK_CNTL_REG1, 218 .shift = 0, 219 .width = 12, 220 }, 221 .m2 = { 222 .reg_off = AO_CEC_CLK_CNTL_REG1, 223 .shift = 12, 224 .width = 12, 225 }, 226 .dual = { 227 .reg_off = AO_CEC_CLK_CNTL_REG0, 228 .shift = 28, 229 .width = 1, 230 }, 231 .table = g12a_32k_div_table, 232 }, 233 .hw.init = &(struct clk_init_data){ 234 .name = "ao_cec_div", 235 .ops = &meson_clk_dualdiv_ops, 236 .parent_hws = (const struct clk_hw *[]) { 237 &g12a_ao_cec_pre.hw 238 }, 239 .num_parents = 1, 240 }, 241 }; 242 243 static struct clk_regmap g12a_ao_cec_sel = { 244 .data = &(struct clk_regmap_mux_data) { 245 .offset = AO_CEC_CLK_CNTL_REG1, 246 .mask = 0x1, 247 .shift = 24, 248 .flags = CLK_MUX_ROUND_CLOSEST, 249 }, 250 .hw.init = &(struct clk_init_data){ 251 .name = "ao_cec_sel", 252 .ops = &clk_regmap_mux_ops, 253 .parent_hws = (const struct clk_hw *[]) { 254 &g12a_ao_cec_div.hw, 255 &g12a_ao_cec_pre.hw, 256 }, 257 .num_parents = 2, 258 .flags = CLK_SET_RATE_PARENT, 259 }, 260 }; 261 262 static struct clk_regmap g12a_ao_cec = { 263 .data = &(struct clk_regmap_gate_data){ 264 .offset = AO_CEC_CLK_CNTL_REG0, 265 .bit_idx = 30, 266 }, 267 .hw.init = &(struct clk_init_data){ 268 .name = "ao_cec", 269 .ops = &clk_regmap_gate_ops, 270 .parent_hws = (const struct clk_hw *[]) { 271 &g12a_ao_cec_sel.hw 272 }, 273 .num_parents = 1, 274 .flags = CLK_SET_RATE_PARENT, 275 }, 276 }; 277 278 static struct clk_regmap g12a_ao_cts_rtc_oscin = { 279 .data = &(struct clk_regmap_mux_data) { 280 .offset = AO_RTI_PWR_CNTL_REG0, 281 .mask = 0x1, 282 .shift = 10, 283 .flags = CLK_MUX_ROUND_CLOSEST, 284 }, 285 .hw.init = &(struct clk_init_data){ 286 .name = "ao_cts_rtc_oscin", 287 .ops = &clk_regmap_mux_ops, 288 .parent_data = (const struct clk_parent_data []) { 289 { .hw = &g12a_ao_32k_by_oscin.hw }, 290 { .fw_name = "ext-32k-0", }, 291 }, 292 .num_parents = 2, 293 .flags = CLK_SET_RATE_PARENT, 294 }, 295 }; 296 297 static struct clk_regmap g12a_ao_clk81 = { 298 .data = &(struct clk_regmap_mux_data) { 299 .offset = AO_RTI_PWR_CNTL_REG0, 300 .mask = 0x1, 301 .shift = 8, 302 .flags = CLK_MUX_ROUND_CLOSEST, 303 }, 304 .hw.init = &(struct clk_init_data){ 305 /* 306 * NOTE: this is one of the infamous clock the pwm driver 307 * can request directly by its global name. It's wrong but 308 * there is not much we can do about it until the support 309 * for the old pwm bindings is dropped 310 */ 311 .name = "g12a_ao_clk81", 312 .ops = &clk_regmap_mux_ro_ops, 313 .parent_data = (const struct clk_parent_data []) { 314 { .fw_name = "mpeg-clk", }, 315 { .hw = &g12a_ao_cts_rtc_oscin.hw }, 316 }, 317 .num_parents = 2, 318 .flags = CLK_SET_RATE_PARENT, 319 }, 320 }; 321 322 static struct clk_regmap g12a_ao_saradc_mux = { 323 .data = &(struct clk_regmap_mux_data) { 324 .offset = AO_SAR_CLK, 325 .mask = 0x3, 326 .shift = 9, 327 }, 328 .hw.init = &(struct clk_init_data){ 329 .name = "ao_saradc_mux", 330 .ops = &clk_regmap_mux_ops, 331 .parent_data = (const struct clk_parent_data []) { 332 { .fw_name = "xtal", }, 333 { .hw = &g12a_ao_clk81.hw }, 334 }, 335 .num_parents = 2, 336 }, 337 }; 338 339 static struct clk_regmap g12a_ao_saradc_div = { 340 .data = &(struct clk_regmap_div_data) { 341 .offset = AO_SAR_CLK, 342 .shift = 0, 343 .width = 8, 344 }, 345 .hw.init = &(struct clk_init_data){ 346 .name = "ao_saradc_div", 347 .ops = &clk_regmap_divider_ops, 348 .parent_hws = (const struct clk_hw *[]) { 349 &g12a_ao_saradc_mux.hw 350 }, 351 .num_parents = 1, 352 .flags = CLK_SET_RATE_PARENT, 353 }, 354 }; 355 356 static struct clk_regmap g12a_ao_saradc_gate = { 357 .data = &(struct clk_regmap_gate_data) { 358 .offset = AO_SAR_CLK, 359 .bit_idx = 8, 360 }, 361 .hw.init = &(struct clk_init_data){ 362 .name = "ao_saradc_gate", 363 .ops = &clk_regmap_gate_ops, 364 .parent_hws = (const struct clk_hw *[]) { 365 &g12a_ao_saradc_div.hw 366 }, 367 .num_parents = 1, 368 .flags = CLK_SET_RATE_PARENT, 369 }, 370 }; 371 372 static const unsigned int g12a_ao_reset[] = { 373 [RESET_AO_IR_IN] = 16, 374 [RESET_AO_UART] = 17, 375 [RESET_AO_I2C_M] = 18, 376 [RESET_AO_I2C_S] = 19, 377 [RESET_AO_SAR_ADC] = 20, 378 [RESET_AO_UART2] = 22, 379 [RESET_AO_IR_OUT] = 23, 380 }; 381 382 static struct clk_hw *g12a_ao_hw_clks[] = { 383 [CLKID_AO_AHB] = &g12a_ao_ahb.hw, 384 [CLKID_AO_IR_IN] = &g12a_ao_ir_in.hw, 385 [CLKID_AO_I2C_M0] = &g12a_ao_i2c_m0.hw, 386 [CLKID_AO_I2C_S0] = &g12a_ao_i2c_s0.hw, 387 [CLKID_AO_UART] = &g12a_ao_uart.hw, 388 [CLKID_AO_PROD_I2C] = &g12a_ao_prod_i2c.hw, 389 [CLKID_AO_UART2] = &g12a_ao_uart2.hw, 390 [CLKID_AO_IR_OUT] = &g12a_ao_ir_out.hw, 391 [CLKID_AO_SAR_ADC] = &g12a_ao_saradc.hw, 392 [CLKID_AO_MAILBOX] = &g12a_ao_mailbox.hw, 393 [CLKID_AO_M3] = &g12a_ao_m3.hw, 394 [CLKID_AO_AHB_SRAM] = &g12a_ao_ahb_sram.hw, 395 [CLKID_AO_RTI] = &g12a_ao_rti.hw, 396 [CLKID_AO_M4_FCLK] = &g12a_ao_m4_fclk.hw, 397 [CLKID_AO_M4_HCLK] = &g12a_ao_m4_hclk.hw, 398 [CLKID_AO_CLK81] = &g12a_ao_clk81.hw, 399 [CLKID_AO_SAR_ADC_SEL] = &g12a_ao_saradc_mux.hw, 400 [CLKID_AO_SAR_ADC_DIV] = &g12a_ao_saradc_div.hw, 401 [CLKID_AO_SAR_ADC_CLK] = &g12a_ao_saradc_gate.hw, 402 [CLKID_AO_CTS_OSCIN] = &g12a_ao_cts_oscin.hw, 403 [CLKID_AO_32K_PRE] = &g12a_ao_32k_by_oscin_pre.hw, 404 [CLKID_AO_32K_DIV] = &g12a_ao_32k_by_oscin_div.hw, 405 [CLKID_AO_32K_SEL] = &g12a_ao_32k_by_oscin_sel.hw, 406 [CLKID_AO_32K] = &g12a_ao_32k_by_oscin.hw, 407 [CLKID_AO_CEC_PRE] = &g12a_ao_cec_pre.hw, 408 [CLKID_AO_CEC_DIV] = &g12a_ao_cec_div.hw, 409 [CLKID_AO_CEC_SEL] = &g12a_ao_cec_sel.hw, 410 [CLKID_AO_CEC] = &g12a_ao_cec.hw, 411 [CLKID_AO_CTS_RTC_OSCIN] = &g12a_ao_cts_rtc_oscin.hw, 412 }; 413 414 static const struct meson_aoclk_data g12a_ao_clkc_data = { 415 .reset_reg = AO_RTI_GEN_CNTL_REG0, 416 .num_reset = ARRAY_SIZE(g12a_ao_reset), 417 .reset = g12a_ao_reset, 418 .clkc_data = { 419 .hw_clks = { 420 .hws = g12a_ao_hw_clks, 421 .num = ARRAY_SIZE(g12a_ao_hw_clks), 422 }, 423 }, 424 }; 425 426 static const struct of_device_id g12a_ao_clkc_match_table[] = { 427 { 428 .compatible = "amlogic,meson-g12a-aoclkc", 429 .data = &g12a_ao_clkc_data.clkc_data, 430 }, 431 { } 432 }; 433 MODULE_DEVICE_TABLE(of, g12a_ao_clkc_match_table); 434 435 static struct platform_driver g12a_ao_clkc_driver = { 436 .probe = meson_aoclkc_probe, 437 .driver = { 438 .name = "g12a-aoclkc", 439 .of_match_table = g12a_ao_clkc_match_table, 440 }, 441 }; 442 module_platform_driver(g12a_ao_clkc_driver); 443 444 MODULE_DESCRIPTION("Amlogic G12A Always-ON Clock Controller driver"); 445 MODULE_LICENSE("GPL"); 446 MODULE_IMPORT_NS("CLK_MESON"); 447