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