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