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