root/drivers/clk/meson/axg-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) 2018 Amlogic, inc.
   9  * Author: Qiufang Dai <qiufang.dai@amlogic.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 "axg-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_PWR_CNTL_REG1    0x0C
  26 #define AO_RTI_PWR_CNTL_REG0    0x10
  27 #define AO_RTI_GEN_CNTL_REG0    0x40
  28 #define AO_OSCIN_CNTL           0x58
  29 #define AO_CRT_CLK_CNTL1        0x68
  30 #define AO_SAR_CLK              0x90
  31 #define AO_RTC_ALT_CLK_CNTL0    0x94
  32 #define AO_RTC_ALT_CLK_CNTL1    0x98
  33 
  34 #define AXG_AO_GATE(_name, _bit)                                        \
  35 static struct clk_regmap axg_aoclk_##_name = {                          \
  36         .data = &(struct clk_regmap_gate_data) {                        \
  37                 .offset = (AO_RTI_GEN_CNTL_REG0),                       \
  38                 .bit_idx = (_bit),                                      \
  39         },                                                              \
  40         .hw.init = &(struct clk_init_data) {                            \
  41                 .name =  "axg_ao_" #_name,                              \
  42                 .ops = &clk_regmap_gate_ops,                            \
  43                 .parent_data = &(const struct clk_parent_data) {        \
  44                         .fw_name = "mpeg-clk",                          \
  45                 },                                                      \
  46                 .num_parents = 1,                                       \
  47                 .flags = CLK_IGNORE_UNUSED,                             \
  48         },                                                              \
  49 }
  50 
  51 AXG_AO_GATE(remote, 0);
  52 AXG_AO_GATE(i2c_master, 1);
  53 AXG_AO_GATE(i2c_slave, 2);
  54 AXG_AO_GATE(uart1, 3);
  55 AXG_AO_GATE(uart2, 5);
  56 AXG_AO_GATE(ir_blaster, 6);
  57 AXG_AO_GATE(saradc, 7);
  58 
  59 static struct clk_regmap axg_aoclk_cts_oscin = {
  60         .data = &(struct clk_regmap_gate_data){
  61                 .offset = AO_RTI_PWR_CNTL_REG0,
  62                 .bit_idx = 14,
  63         },
  64         .hw.init = &(struct clk_init_data){
  65                 .name = "cts_oscin",
  66                 .ops = &clk_regmap_gate_ro_ops,
  67                 .parent_data = &(const struct clk_parent_data) {
  68                         .fw_name = "xtal",
  69                 },
  70                 .num_parents = 1,
  71         },
  72 };
  73 
  74 static struct clk_regmap axg_aoclk_32k_pre = {
  75         .data = &(struct clk_regmap_gate_data){
  76                 .offset = AO_RTC_ALT_CLK_CNTL0,
  77                 .bit_idx = 31,
  78         },
  79         .hw.init = &(struct clk_init_data){
  80                 .name = "axg_ao_32k_pre",
  81                 .ops = &clk_regmap_gate_ops,
  82                 .parent_hws = (const struct clk_hw *[]) {
  83                         &axg_aoclk_cts_oscin.hw
  84                 },
  85                 .num_parents = 1,
  86         },
  87 };
  88 
  89 static const struct meson_clk_dualdiv_param axg_32k_div_table[] = {
  90         {
  91                 .dual   = 1,
  92                 .n1     = 733,
  93                 .m1     = 8,
  94                 .n2     = 732,
  95                 .m2     = 11,
  96         }, {}
  97 };
  98 
  99 static struct clk_regmap axg_aoclk_32k_div = {
 100         .data = &(struct meson_clk_dualdiv_data){
 101                 .n1 = {
 102                         .reg_off = AO_RTC_ALT_CLK_CNTL0,
 103                         .shift   = 0,
 104                         .width   = 12,
 105                 },
 106                 .n2 = {
 107                         .reg_off = AO_RTC_ALT_CLK_CNTL0,
 108                         .shift   = 12,
 109                         .width   = 12,
 110                 },
 111                 .m1 = {
 112                         .reg_off = AO_RTC_ALT_CLK_CNTL1,
 113                         .shift   = 0,
 114                         .width   = 12,
 115                 },
 116                 .m2 = {
 117                         .reg_off = AO_RTC_ALT_CLK_CNTL1,
 118                         .shift   = 12,
 119                         .width   = 12,
 120                 },
 121                 .dual = {
 122                         .reg_off = AO_RTC_ALT_CLK_CNTL0,
 123                         .shift   = 28,
 124                         .width   = 1,
 125                 },
 126                 .table = axg_32k_div_table,
 127         },
 128         .hw.init = &(struct clk_init_data){
 129                 .name = "axg_ao_32k_div",
 130                 .ops = &meson_clk_dualdiv_ops,
 131                 .parent_hws = (const struct clk_hw *[]) {
 132                         &axg_aoclk_32k_pre.hw
 133                 },
 134                 .num_parents = 1,
 135         },
 136 };
 137 
 138 static struct clk_regmap axg_aoclk_32k_sel = {
 139         .data = &(struct clk_regmap_mux_data) {
 140                 .offset = AO_RTC_ALT_CLK_CNTL1,
 141                 .mask = 0x1,
 142                 .shift = 24,
 143                 .flags = CLK_MUX_ROUND_CLOSEST,
 144         },
 145         .hw.init = &(struct clk_init_data){
 146                 .name = "axg_ao_32k_sel",
 147                 .ops = &clk_regmap_mux_ops,
 148                 .parent_hws = (const struct clk_hw *[]) {
 149                         &axg_aoclk_32k_div.hw,
 150                         &axg_aoclk_32k_pre.hw,
 151                 },
 152                 .num_parents = 2,
 153                 .flags = CLK_SET_RATE_PARENT,
 154         },
 155 };
 156 
 157 static struct clk_regmap axg_aoclk_32k = {
 158         .data = &(struct clk_regmap_gate_data){
 159                 .offset = AO_RTC_ALT_CLK_CNTL0,
 160                 .bit_idx = 30,
 161         },
 162         .hw.init = &(struct clk_init_data){
 163                 .name = "axg_ao_32k",
 164                 .ops = &clk_regmap_gate_ops,
 165                 .parent_hws = (const struct clk_hw *[]) {
 166                         &axg_aoclk_32k_sel.hw
 167                 },
 168                 .num_parents = 1,
 169                 .flags = CLK_SET_RATE_PARENT,
 170         },
 171 };
 172 
 173 static struct clk_regmap axg_aoclk_cts_rtc_oscin = {
 174         .data = &(struct clk_regmap_mux_data) {
 175                 .offset = AO_RTI_PWR_CNTL_REG0,
 176                 .mask = 0x1,
 177                 .shift = 10,
 178                 .flags = CLK_MUX_ROUND_CLOSEST,
 179         },
 180         .hw.init = &(struct clk_init_data){
 181                 .name = "axg_ao_cts_rtc_oscin",
 182                 .ops = &clk_regmap_mux_ops,
 183                 .parent_data = (const struct clk_parent_data []) {
 184                         { .hw = &axg_aoclk_32k.hw },
 185                         { .fw_name = "ext_32k-0", },
 186                 },
 187                 .num_parents = 2,
 188                 .flags = CLK_SET_RATE_PARENT,
 189         },
 190 };
 191 
 192 static struct clk_regmap axg_aoclk_clk81 = {
 193         .data = &(struct clk_regmap_mux_data) {
 194                 .offset = AO_RTI_PWR_CNTL_REG0,
 195                 .mask = 0x1,
 196                 .shift = 8,
 197                 .flags = CLK_MUX_ROUND_CLOSEST,
 198         },
 199         .hw.init = &(struct clk_init_data){
 200                 .name = "axg_ao_clk81",
 201                 .ops = &clk_regmap_mux_ro_ops,
 202                 .parent_data = (const struct clk_parent_data []) {
 203                         { .fw_name = "mpeg-clk", },
 204                         { .hw = &axg_aoclk_cts_rtc_oscin.hw },
 205                 },
 206                 .num_parents = 2,
 207                 .flags = CLK_SET_RATE_PARENT,
 208         },
 209 };
 210 
 211 static struct clk_regmap axg_aoclk_saradc_mux = {
 212         .data = &(struct clk_regmap_mux_data) {
 213                 .offset = AO_SAR_CLK,
 214                 .mask = 0x3,
 215                 .shift = 9,
 216         },
 217         .hw.init = &(struct clk_init_data){
 218                 .name = "axg_ao_saradc_mux",
 219                 .ops = &clk_regmap_mux_ops,
 220                 .parent_data = (const struct clk_parent_data []) {
 221                         { .fw_name = "xtal", },
 222                         { .hw = &axg_aoclk_clk81.hw },
 223                 },
 224                 .num_parents = 2,
 225         },
 226 };
 227 
 228 static struct clk_regmap axg_aoclk_saradc_div = {
 229         .data = &(struct clk_regmap_div_data) {
 230                 .offset = AO_SAR_CLK,
 231                 .shift = 0,
 232                 .width = 8,
 233         },
 234         .hw.init = &(struct clk_init_data){
 235                 .name = "axg_ao_saradc_div",
 236                 .ops = &clk_regmap_divider_ops,
 237                 .parent_hws = (const struct clk_hw *[]) {
 238                         &axg_aoclk_saradc_mux.hw
 239                 },
 240                 .num_parents = 1,
 241                 .flags = CLK_SET_RATE_PARENT,
 242         },
 243 };
 244 
 245 static struct clk_regmap axg_aoclk_saradc_gate = {
 246         .data = &(struct clk_regmap_gate_data) {
 247                 .offset = AO_SAR_CLK,
 248                 .bit_idx = 8,
 249         },
 250         .hw.init = &(struct clk_init_data){
 251                 .name = "axg_ao_saradc_gate",
 252                 .ops = &clk_regmap_gate_ops,
 253                 .parent_hws = (const struct clk_hw *[]) {
 254                         &axg_aoclk_saradc_div.hw
 255                 },
 256                 .num_parents = 1,
 257                 .flags = CLK_SET_RATE_PARENT,
 258         },
 259 };
 260 
 261 static const unsigned int axg_aoclk_reset[] = {
 262         [RESET_AO_REMOTE]       = 16,
 263         [RESET_AO_I2C_MASTER]   = 18,
 264         [RESET_AO_I2C_SLAVE]    = 19,
 265         [RESET_AO_UART1]        = 17,
 266         [RESET_AO_UART2]        = 22,
 267         [RESET_AO_IR_BLASTER]   = 23,
 268 };
 269 
 270 static struct clk_regmap *axg_aoclk_regmap[] = {
 271         &axg_aoclk_remote,
 272         &axg_aoclk_i2c_master,
 273         &axg_aoclk_i2c_slave,
 274         &axg_aoclk_uart1,
 275         &axg_aoclk_uart2,
 276         &axg_aoclk_ir_blaster,
 277         &axg_aoclk_saradc,
 278         &axg_aoclk_cts_oscin,
 279         &axg_aoclk_32k_pre,
 280         &axg_aoclk_32k_div,
 281         &axg_aoclk_32k_sel,
 282         &axg_aoclk_32k,
 283         &axg_aoclk_cts_rtc_oscin,
 284         &axg_aoclk_clk81,
 285         &axg_aoclk_saradc_mux,
 286         &axg_aoclk_saradc_div,
 287         &axg_aoclk_saradc_gate,
 288 };
 289 
 290 static const struct clk_hw_onecell_data axg_aoclk_onecell_data = {
 291         .hws = {
 292                 [CLKID_AO_REMOTE]       = &axg_aoclk_remote.hw,
 293                 [CLKID_AO_I2C_MASTER]   = &axg_aoclk_i2c_master.hw,
 294                 [CLKID_AO_I2C_SLAVE]    = &axg_aoclk_i2c_slave.hw,
 295                 [CLKID_AO_UART1]        = &axg_aoclk_uart1.hw,
 296                 [CLKID_AO_UART2]        = &axg_aoclk_uart2.hw,
 297                 [CLKID_AO_IR_BLASTER]   = &axg_aoclk_ir_blaster.hw,
 298                 [CLKID_AO_SAR_ADC]      = &axg_aoclk_saradc.hw,
 299                 [CLKID_AO_CLK81]        = &axg_aoclk_clk81.hw,
 300                 [CLKID_AO_SAR_ADC_SEL]  = &axg_aoclk_saradc_mux.hw,
 301                 [CLKID_AO_SAR_ADC_DIV]  = &axg_aoclk_saradc_div.hw,
 302                 [CLKID_AO_SAR_ADC_CLK]  = &axg_aoclk_saradc_gate.hw,
 303                 [CLKID_AO_CTS_OSCIN]    = &axg_aoclk_cts_oscin.hw,
 304                 [CLKID_AO_32K_PRE]      = &axg_aoclk_32k_pre.hw,
 305                 [CLKID_AO_32K_DIV]      = &axg_aoclk_32k_div.hw,
 306                 [CLKID_AO_32K_SEL]      = &axg_aoclk_32k_sel.hw,
 307                 [CLKID_AO_32K]          = &axg_aoclk_32k.hw,
 308                 [CLKID_AO_CTS_RTC_OSCIN] = &axg_aoclk_cts_rtc_oscin.hw,
 309         },
 310         .num = NR_CLKS,
 311 };
 312 
 313 static const struct meson_aoclk_data axg_aoclkc_data = {
 314         .reset_reg      = AO_RTI_GEN_CNTL_REG0,
 315         .num_reset      = ARRAY_SIZE(axg_aoclk_reset),
 316         .reset          = axg_aoclk_reset,
 317         .num_clks       = ARRAY_SIZE(axg_aoclk_regmap),
 318         .clks           = axg_aoclk_regmap,
 319         .hw_data        = &axg_aoclk_onecell_data,
 320 };
 321 
 322 static const struct of_device_id axg_aoclkc_match_table[] = {
 323         {
 324                 .compatible     = "amlogic,meson-axg-aoclkc",
 325                 .data           = &axg_aoclkc_data,
 326         },
 327         { }
 328 };
 329 
 330 static struct platform_driver axg_aoclkc_driver = {
 331         .probe          = meson_aoclkc_probe,
 332         .driver         = {
 333                 .name   = "axg-aoclkc",
 334                 .of_match_table = axg_aoclkc_match_table,
 335         },
 336 };
 337 
 338 builtin_platform_driver(axg_aoclkc_driver);

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