linux/drivers/clk/meson/g12a-aoclk.c
<<
>>
Prefs
   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)                                  \
  44static 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
  60AXG_AO_GATE(ahb, AO_CLK_GATE0, 0);
  61AXG_AO_GATE(ir_in, AO_CLK_GATE0, 1);
  62AXG_AO_GATE(i2c_m0, AO_CLK_GATE0, 2);
  63AXG_AO_GATE(i2c_s0, AO_CLK_GATE0, 3);
  64AXG_AO_GATE(uart, AO_CLK_GATE0, 4);
  65AXG_AO_GATE(prod_i2c, AO_CLK_GATE0, 5);
  66AXG_AO_GATE(uart2, AO_CLK_GATE0, 6);
  67AXG_AO_GATE(ir_out, AO_CLK_GATE0, 7);
  68AXG_AO_GATE(saradc, AO_CLK_GATE0, 8);
  69AXG_AO_GATE(mailbox, AO_CLK_GATE0_SP, 0);
  70AXG_AO_GATE(m3, AO_CLK_GATE0_SP, 1);
  71AXG_AO_GATE(ahb_sram, AO_CLK_GATE0_SP, 2);
  72AXG_AO_GATE(rti, AO_CLK_GATE0_SP, 3);
  73AXG_AO_GATE(m4_fclk, AO_CLK_GATE0_SP, 4);
  74AXG_AO_GATE(m4_hclk, AO_CLK_GATE0_SP, 5);
  75
  76static 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
  91static 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
 103static 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
 118static 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
 157static 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
 176static 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
 194static 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
 209static 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
 248static 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
 267static 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
 283static 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
 302static 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
 321static 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
 338static 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
 355static 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
 371static 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
 381static 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
 413static 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
 448static 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
 457static 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
 465static 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
 473builtin_platform_driver(g12a_aoclkc_driver);
 474