root/drivers/clk/meson/g12a-aoclk.c

/* [<][>][^][v][top][bottom][index][help] */
   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 "meson-aoclk.h"
  16 #include "g12a-aoclk.h"
  17 
  18 #include "clk-regmap.h"
  19 #include "clk-dualdiv.h"
  20 
  21 /*
  22  * AO Configuration Clock registers offsets
  23  * Register offsets from the data sheet must be multiplied by 4.
  24  */
  25 #define AO_RTI_STATUS_REG3      0x0C
  26 #define AO_RTI_PWR_CNTL_REG0    0x10
  27 #define AO_RTI_GEN_CNTL_REG0    0x40
  28 #define AO_CLK_GATE0            0x4c
  29 #define AO_CLK_GATE0_SP         0x50
  30 #define AO_OSCIN_CNTL           0x58
  31 #define AO_CEC_CLK_CNTL_REG0    0x74
  32 #define AO_CEC_CLK_CNTL_REG1    0x78
  33 #define AO_SAR_CLK              0x90
  34 #define AO_RTC_ALT_CLK_CNTL0    0x94
  35 #define AO_RTC_ALT_CLK_CNTL1    0x98
  36 
  37 /*
  38  * Like every other peripheral clock gate in Amlogic Clock drivers,
  39  * we are using CLK_IGNORE_UNUSED here, so we keep the state of the
  40  * bootloader. The goal is to remove this flag at some point.
  41  * Actually removing it will require some extensive test to be done safely.
  42  */
  43 #define AXG_AO_GATE(_name, _reg, _bit)                                  \
  44 static struct clk_regmap g12a_aoclk_##_name = {                         \
  45         .data = &(struct clk_regmap_gate_data) {                        \
  46                 .offset = (_reg),                                       \
  47                 .bit_idx = (_bit),                                      \
  48         },                                                              \
  49         .hw.init = &(struct clk_init_data) {                            \
  50                 .name =  "g12a_ao_" #_name,                             \
  51                 .ops = &clk_regmap_gate_ops,                            \
  52                 .parent_data = &(const struct clk_parent_data) {        \
  53                         .fw_name = "mpeg-clk",                          \
  54                 },                                                      \
  55                 .num_parents = 1,                                       \
  56                 .flags = CLK_IGNORE_UNUSED,                             \
  57         },                                                              \
  58 }
  59 
  60 AXG_AO_GATE(ahb, AO_CLK_GATE0, 0);
  61 AXG_AO_GATE(ir_in, AO_CLK_GATE0, 1);
  62 AXG_AO_GATE(i2c_m0, AO_CLK_GATE0, 2);
  63 AXG_AO_GATE(i2c_s0, AO_CLK_GATE0, 3);
  64 AXG_AO_GATE(uart, AO_CLK_GATE0, 4);
  65 AXG_AO_GATE(prod_i2c, AO_CLK_GATE0, 5);
  66 AXG_AO_GATE(uart2, AO_CLK_GATE0, 6);
  67 AXG_AO_GATE(ir_out, AO_CLK_GATE0, 7);
  68 AXG_AO_GATE(saradc, AO_CLK_GATE0, 8);
  69 AXG_AO_GATE(mailbox, AO_CLK_GATE0_SP, 0);
  70 AXG_AO_GATE(m3, AO_CLK_GATE0_SP, 1);
  71 AXG_AO_GATE(ahb_sram, AO_CLK_GATE0_SP, 2);
  72 AXG_AO_GATE(rti, AO_CLK_GATE0_SP, 3);
  73 AXG_AO_GATE(m4_fclk, AO_CLK_GATE0_SP, 4);
  74 AXG_AO_GATE(m4_hclk, AO_CLK_GATE0_SP, 5);
  75 
  76 static struct clk_regmap g12a_aoclk_cts_oscin = {
  77         .data = &(struct clk_regmap_gate_data){
  78                 .offset = AO_RTI_PWR_CNTL_REG0,
  79                 .bit_idx = 14,
  80         },
  81         .hw.init = &(struct clk_init_data){
  82                 .name = "cts_oscin",
  83                 .ops = &clk_regmap_gate_ro_ops,
  84                 .parent_data = &(const struct clk_parent_data) {
  85                         .fw_name = "xtal",
  86                 },
  87                 .num_parents = 1,
  88         },
  89 };
  90 
  91 static const struct meson_clk_dualdiv_param g12a_32k_div_table[] = {
  92         {
  93                 .dual   = 1,
  94                 .n1     = 733,
  95                 .m1     = 8,
  96                 .n2     = 732,
  97                 .m2     = 11,
  98         }, {}
  99 };
 100 
 101 /* 32k_by_oscin clock */
 102 
 103 static struct clk_regmap g12a_aoclk_32k_by_oscin_pre = {
 104         .data = &(struct clk_regmap_gate_data){
 105                 .offset = AO_RTC_ALT_CLK_CNTL0,
 106                 .bit_idx = 31,
 107         },
 108         .hw.init = &(struct clk_init_data){
 109                 .name = "g12a_ao_32k_by_oscin_pre",
 110                 .ops = &clk_regmap_gate_ops,
 111                 .parent_hws = (const struct clk_hw *[]) {
 112                         &g12a_aoclk_cts_oscin.hw
 113                 },
 114                 .num_parents = 1,
 115         },
 116 };
 117 
 118 static struct clk_regmap g12a_aoclk_32k_by_oscin_div = {
 119         .data = &(struct meson_clk_dualdiv_data){
 120                 .n1 = {
 121                         .reg_off = AO_RTC_ALT_CLK_CNTL0,
 122                         .shift   = 0,
 123                         .width   = 12,
 124                 },
 125                 .n2 = {
 126                         .reg_off = AO_RTC_ALT_CLK_CNTL0,
 127                         .shift   = 12,
 128                         .width   = 12,
 129                 },
 130                 .m1 = {
 131                         .reg_off = AO_RTC_ALT_CLK_CNTL1,
 132                         .shift   = 0,
 133                         .width   = 12,
 134                 },
 135                 .m2 = {
 136                         .reg_off = AO_RTC_ALT_CLK_CNTL1,
 137                         .shift   = 12,
 138                         .width   = 12,
 139                 },
 140                 .dual = {
 141                         .reg_off = AO_RTC_ALT_CLK_CNTL0,
 142                         .shift   = 28,
 143                         .width   = 1,
 144                 },
 145                 .table = g12a_32k_div_table,
 146         },
 147         .hw.init = &(struct clk_init_data){
 148                 .name = "g12a_ao_32k_by_oscin_div",
 149                 .ops = &meson_clk_dualdiv_ops,
 150                 .parent_hws = (const struct clk_hw *[]) {
 151                         &g12a_aoclk_32k_by_oscin_pre.hw
 152                 },
 153                 .num_parents = 1,
 154         },
 155 };
 156 
 157 static struct clk_regmap g12a_aoclk_32k_by_oscin_sel = {
 158         .data = &(struct clk_regmap_mux_data) {
 159                 .offset = AO_RTC_ALT_CLK_CNTL1,
 160                 .mask = 0x1,
 161                 .shift = 24,
 162                 .flags = CLK_MUX_ROUND_CLOSEST,
 163         },
 164         .hw.init = &(struct clk_init_data){
 165                 .name = "g12a_ao_32k_by_oscin_sel",
 166                 .ops = &clk_regmap_mux_ops,
 167                 .parent_hws = (const struct clk_hw *[]) {
 168                         &g12a_aoclk_32k_by_oscin_div.hw,
 169                         &g12a_aoclk_32k_by_oscin_pre.hw,
 170                 },
 171                 .num_parents = 2,
 172                 .flags = CLK_SET_RATE_PARENT,
 173         },
 174 };
 175 
 176 static struct clk_regmap g12a_aoclk_32k_by_oscin = {
 177         .data = &(struct clk_regmap_gate_data){
 178                 .offset = AO_RTC_ALT_CLK_CNTL0,
 179                 .bit_idx = 30,
 180         },
 181         .hw.init = &(struct clk_init_data){
 182                 .name = "g12a_ao_32k_by_oscin",
 183                 .ops = &clk_regmap_gate_ops,
 184                 .parent_hws = (const struct clk_hw *[]) {
 185                         &g12a_aoclk_32k_by_oscin_sel.hw
 186                 },
 187                 .num_parents = 1,
 188                 .flags = CLK_SET_RATE_PARENT,
 189         },
 190 };
 191 
 192 /* cec clock */
 193 
 194 static struct clk_regmap g12a_aoclk_cec_pre = {
 195         .data = &(struct clk_regmap_gate_data){
 196                 .offset = AO_CEC_CLK_CNTL_REG0,
 197                 .bit_idx = 31,
 198         },
 199         .hw.init = &(struct clk_init_data){
 200                 .name = "g12a_ao_cec_pre",
 201                 .ops = &clk_regmap_gate_ops,
 202                 .parent_hws = (const struct clk_hw *[]) {
 203                         &g12a_aoclk_cts_oscin.hw
 204                 },
 205                 .num_parents = 1,
 206         },
 207 };
 208 
 209 static struct clk_regmap g12a_aoclk_cec_div = {
 210         .data = &(struct meson_clk_dualdiv_data){
 211                 .n1 = {
 212                         .reg_off = AO_CEC_CLK_CNTL_REG0,
 213                         .shift   = 0,
 214                         .width   = 12,
 215                 },
 216                 .n2 = {
 217                         .reg_off = AO_CEC_CLK_CNTL_REG0,
 218                         .shift   = 12,
 219                         .width   = 12,
 220                 },
 221                 .m1 = {
 222                         .reg_off = AO_CEC_CLK_CNTL_REG1,
 223                         .shift   = 0,
 224                         .width   = 12,
 225                 },
 226                 .m2 = {
 227                         .reg_off = AO_CEC_CLK_CNTL_REG1,
 228                         .shift   = 12,
 229                         .width   = 12,
 230                 },
 231                 .dual = {
 232                         .reg_off = AO_CEC_CLK_CNTL_REG0,
 233                         .shift   = 28,
 234                         .width   = 1,
 235                 },
 236                 .table = g12a_32k_div_table,
 237         },
 238         .hw.init = &(struct clk_init_data){
 239                 .name = "g12a_ao_cec_div",
 240                 .ops = &meson_clk_dualdiv_ops,
 241                 .parent_hws = (const struct clk_hw *[]) {
 242                         &g12a_aoclk_cec_pre.hw
 243                 },
 244                 .num_parents = 1,
 245         },
 246 };
 247 
 248 static struct clk_regmap g12a_aoclk_cec_sel = {
 249         .data = &(struct clk_regmap_mux_data) {
 250                 .offset = AO_CEC_CLK_CNTL_REG1,
 251                 .mask = 0x1,
 252                 .shift = 24,
 253                 .flags = CLK_MUX_ROUND_CLOSEST,
 254         },
 255         .hw.init = &(struct clk_init_data){
 256                 .name = "g12a_ao_cec_sel",
 257                 .ops = &clk_regmap_mux_ops,
 258                 .parent_hws = (const struct clk_hw *[]) {
 259                         &g12a_aoclk_cec_div.hw,
 260                         &g12a_aoclk_cec_pre.hw,
 261                 },
 262                 .num_parents = 2,
 263                 .flags = CLK_SET_RATE_PARENT,
 264         },
 265 };
 266 
 267 static struct clk_regmap g12a_aoclk_cec = {
 268         .data = &(struct clk_regmap_gate_data){
 269                 .offset = AO_CEC_CLK_CNTL_REG0,
 270                 .bit_idx = 30,
 271         },
 272         .hw.init = &(struct clk_init_data){
 273                 .name = "g12a_ao_cec",
 274                 .ops = &clk_regmap_gate_ops,
 275                 .parent_hws = (const struct clk_hw *[]) {
 276                         &g12a_aoclk_cec_sel.hw
 277                 },
 278                 .num_parents = 1,
 279                 .flags = CLK_SET_RATE_PARENT,
 280         },
 281 };
 282 
 283 static struct clk_regmap g12a_aoclk_cts_rtc_oscin = {
 284         .data = &(struct clk_regmap_mux_data) {
 285                 .offset = AO_RTI_PWR_CNTL_REG0,
 286                 .mask = 0x1,
 287                 .shift = 10,
 288                 .flags = CLK_MUX_ROUND_CLOSEST,
 289         },
 290         .hw.init = &(struct clk_init_data){
 291                 .name = "g12a_ao_cts_rtc_oscin",
 292                 .ops = &clk_regmap_mux_ops,
 293                 .parent_data = (const struct clk_parent_data []) {
 294                         { .hw = &g12a_aoclk_32k_by_oscin.hw },
 295                         { .fw_name = "ext-32k-0", },
 296                 },
 297                 .num_parents = 2,
 298                 .flags = CLK_SET_RATE_PARENT,
 299         },
 300 };
 301 
 302 static struct clk_regmap g12a_aoclk_clk81 = {
 303         .data = &(struct clk_regmap_mux_data) {
 304                 .offset = AO_RTI_PWR_CNTL_REG0,
 305                 .mask = 0x1,
 306                 .shift = 8,
 307                 .flags = CLK_MUX_ROUND_CLOSEST,
 308         },
 309         .hw.init = &(struct clk_init_data){
 310                 .name = "g12a_ao_clk81",
 311                 .ops = &clk_regmap_mux_ro_ops,
 312                 .parent_data = (const struct clk_parent_data []) {
 313                         { .fw_name = "mpeg-clk", },
 314                         { .hw = &g12a_aoclk_cts_rtc_oscin.hw },
 315                 },
 316                 .num_parents = 2,
 317                 .flags = CLK_SET_RATE_PARENT,
 318         },
 319 };
 320 
 321 static struct clk_regmap g12a_aoclk_saradc_mux = {
 322         .data = &(struct clk_regmap_mux_data) {
 323                 .offset = AO_SAR_CLK,
 324                 .mask = 0x3,
 325                 .shift = 9,
 326         },
 327         .hw.init = &(struct clk_init_data){
 328                 .name = "g12a_ao_saradc_mux",
 329                 .ops = &clk_regmap_mux_ops,
 330                 .parent_data = (const struct clk_parent_data []) {
 331                         { .fw_name = "xtal", },
 332                         { .hw = &g12a_aoclk_clk81.hw },
 333                 },
 334                 .num_parents = 2,
 335         },
 336 };
 337 
 338 static struct clk_regmap g12a_aoclk_saradc_div = {
 339         .data = &(struct clk_regmap_div_data) {
 340                 .offset = AO_SAR_CLK,
 341                 .shift = 0,
 342                 .width = 8,
 343         },
 344         .hw.init = &(struct clk_init_data){
 345                 .name = "g12a_ao_saradc_div",
 346                 .ops = &clk_regmap_divider_ops,
 347                 .parent_hws = (const struct clk_hw *[]) {
 348                         &g12a_aoclk_saradc_mux.hw
 349                 },
 350                 .num_parents = 1,
 351                 .flags = CLK_SET_RATE_PARENT,
 352         },
 353 };
 354 
 355 static struct clk_regmap g12a_aoclk_saradc_gate = {
 356         .data = &(struct clk_regmap_gate_data) {
 357                 .offset = AO_SAR_CLK,
 358                 .bit_idx = 8,
 359         },
 360         .hw.init = &(struct clk_init_data){
 361                 .name = "g12a_ao_saradc_gate",
 362                 .ops = &clk_regmap_gate_ops,
 363                 .parent_hws = (const struct clk_hw *[]) {
 364                         &g12a_aoclk_saradc_div.hw
 365                 },
 366                 .num_parents = 1,
 367                 .flags = CLK_SET_RATE_PARENT,
 368         },
 369 };
 370 
 371 static const unsigned int g12a_aoclk_reset[] = {
 372         [RESET_AO_IR_IN]        = 16,
 373         [RESET_AO_UART]         = 17,
 374         [RESET_AO_I2C_M]        = 18,
 375         [RESET_AO_I2C_S]        = 19,
 376         [RESET_AO_SAR_ADC]      = 20,
 377         [RESET_AO_UART2]        = 22,
 378         [RESET_AO_IR_OUT]       = 23,
 379 };
 380 
 381 static struct clk_regmap *g12a_aoclk_regmap[] = {
 382         &g12a_aoclk_ahb,
 383         &g12a_aoclk_ir_in,
 384         &g12a_aoclk_i2c_m0,
 385         &g12a_aoclk_i2c_s0,
 386         &g12a_aoclk_uart,
 387         &g12a_aoclk_prod_i2c,
 388         &g12a_aoclk_uart2,
 389         &g12a_aoclk_ir_out,
 390         &g12a_aoclk_saradc,
 391         &g12a_aoclk_mailbox,
 392         &g12a_aoclk_m3,
 393         &g12a_aoclk_ahb_sram,
 394         &g12a_aoclk_rti,
 395         &g12a_aoclk_m4_fclk,
 396         &g12a_aoclk_m4_hclk,
 397         &g12a_aoclk_cts_oscin,
 398         &g12a_aoclk_32k_by_oscin_pre,
 399         &g12a_aoclk_32k_by_oscin_div,
 400         &g12a_aoclk_32k_by_oscin_sel,
 401         &g12a_aoclk_32k_by_oscin,
 402         &g12a_aoclk_cec_pre,
 403         &g12a_aoclk_cec_div,
 404         &g12a_aoclk_cec_sel,
 405         &g12a_aoclk_cec,
 406         &g12a_aoclk_cts_rtc_oscin,
 407         &g12a_aoclk_clk81,
 408         &g12a_aoclk_saradc_mux,
 409         &g12a_aoclk_saradc_div,
 410         &g12a_aoclk_saradc_gate,
 411 };
 412 
 413 static const struct clk_hw_onecell_data g12a_aoclk_onecell_data = {
 414         .hws = {
 415                 [CLKID_AO_AHB]          = &g12a_aoclk_ahb.hw,
 416                 [CLKID_AO_IR_IN]        = &g12a_aoclk_ir_in.hw,
 417                 [CLKID_AO_I2C_M0]       = &g12a_aoclk_i2c_m0.hw,
 418                 [CLKID_AO_I2C_S0]       = &g12a_aoclk_i2c_s0.hw,
 419                 [CLKID_AO_UART]         = &g12a_aoclk_uart.hw,
 420                 [CLKID_AO_PROD_I2C]     = &g12a_aoclk_prod_i2c.hw,
 421                 [CLKID_AO_UART2]        = &g12a_aoclk_uart2.hw,
 422                 [CLKID_AO_IR_OUT]       = &g12a_aoclk_ir_out.hw,
 423                 [CLKID_AO_SAR_ADC]      = &g12a_aoclk_saradc.hw,
 424                 [CLKID_AO_MAILBOX]      = &g12a_aoclk_mailbox.hw,
 425                 [CLKID_AO_M3]           = &g12a_aoclk_m3.hw,
 426                 [CLKID_AO_AHB_SRAM]     = &g12a_aoclk_ahb_sram.hw,
 427                 [CLKID_AO_RTI]          = &g12a_aoclk_rti.hw,
 428                 [CLKID_AO_M4_FCLK]      = &g12a_aoclk_m4_fclk.hw,
 429                 [CLKID_AO_M4_HCLK]      = &g12a_aoclk_m4_hclk.hw,
 430                 [CLKID_AO_CLK81]        = &g12a_aoclk_clk81.hw,
 431                 [CLKID_AO_SAR_ADC_SEL]  = &g12a_aoclk_saradc_mux.hw,
 432                 [CLKID_AO_SAR_ADC_DIV]  = &g12a_aoclk_saradc_div.hw,
 433                 [CLKID_AO_SAR_ADC_CLK]  = &g12a_aoclk_saradc_gate.hw,
 434                 [CLKID_AO_CTS_OSCIN]    = &g12a_aoclk_cts_oscin.hw,
 435                 [CLKID_AO_32K_PRE]      = &g12a_aoclk_32k_by_oscin_pre.hw,
 436                 [CLKID_AO_32K_DIV]      = &g12a_aoclk_32k_by_oscin_div.hw,
 437                 [CLKID_AO_32K_SEL]      = &g12a_aoclk_32k_by_oscin_sel.hw,
 438                 [CLKID_AO_32K]          = &g12a_aoclk_32k_by_oscin.hw,
 439                 [CLKID_AO_CEC_PRE]      = &g12a_aoclk_cec_pre.hw,
 440                 [CLKID_AO_CEC_DIV]      = &g12a_aoclk_cec_div.hw,
 441                 [CLKID_AO_CEC_SEL]      = &g12a_aoclk_cec_sel.hw,
 442                 [CLKID_AO_CEC]          = &g12a_aoclk_cec.hw,
 443                 [CLKID_AO_CTS_RTC_OSCIN] = &g12a_aoclk_cts_rtc_oscin.hw,
 444         },
 445         .num = NR_CLKS,
 446 };
 447 
 448 static const struct meson_aoclk_data g12a_aoclkc_data = {
 449         .reset_reg      = AO_RTI_GEN_CNTL_REG0,
 450         .num_reset      = ARRAY_SIZE(g12a_aoclk_reset),
 451         .reset          = g12a_aoclk_reset,
 452         .num_clks       = ARRAY_SIZE(g12a_aoclk_regmap),
 453         .clks           = g12a_aoclk_regmap,
 454         .hw_data        = &g12a_aoclk_onecell_data,
 455 };
 456 
 457 static const struct of_device_id g12a_aoclkc_match_table[] = {
 458         {
 459                 .compatible     = "amlogic,meson-g12a-aoclkc",
 460                 .data           = &g12a_aoclkc_data,
 461         },
 462         { }
 463 };
 464 
 465 static struct platform_driver g12a_aoclkc_driver = {
 466         .probe          = meson_aoclkc_probe,
 467         .driver         = {
 468                 .name   = "g12a-aoclkc",
 469                 .of_match_table = g12a_aoclkc_match_table,
 470         },
 471 };
 472 
 473 builtin_platform_driver(g12a_aoclkc_driver);

/* [<][>][^][v][top][bottom][index][help] */