Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Amlogic Meson-AXG Clock Controller Driver
0004  *
0005  * Copyright (c) 2016 Baylibre SAS.
0006  * Author: Michael Turquette <mturquette@baylibre.com>
0007  *
0008  * Copyright (c) 2018 Amlogic, inc.
0009  * Author: Qiufang Dai <qiufang.dai@amlogic.com>
0010  */
0011 #include <linux/clk-provider.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/reset-controller.h>
0014 #include <linux/mfd/syscon.h>
0015 #include <linux/module.h>
0016 #include "meson-aoclk.h"
0017 #include "axg-aoclk.h"
0018 
0019 #include "clk-regmap.h"
0020 #include "clk-dualdiv.h"
0021 
0022 /*
0023  * AO Configuration Clock registers offsets
0024  * Register offsets from the data sheet must be multiplied by 4.
0025  */
0026 #define AO_RTI_PWR_CNTL_REG1    0x0C
0027 #define AO_RTI_PWR_CNTL_REG0    0x10
0028 #define AO_RTI_GEN_CNTL_REG0    0x40
0029 #define AO_OSCIN_CNTL       0x58
0030 #define AO_CRT_CLK_CNTL1    0x68
0031 #define AO_SAR_CLK      0x90
0032 #define AO_RTC_ALT_CLK_CNTL0    0x94
0033 #define AO_RTC_ALT_CLK_CNTL1    0x98
0034 
0035 #define AXG_AO_GATE(_name, _bit)                    \
0036 static struct clk_regmap axg_aoclk_##_name = {              \
0037     .data = &(struct clk_regmap_gate_data) {            \
0038         .offset = (AO_RTI_GEN_CNTL_REG0),           \
0039         .bit_idx = (_bit),                  \
0040     },                              \
0041     .hw.init = &(struct clk_init_data) {                \
0042         .name =  "axg_ao_" #_name,              \
0043         .ops = &clk_regmap_gate_ops,                \
0044         .parent_data = &(const struct clk_parent_data) {    \
0045             .fw_name = "mpeg-clk",              \
0046         },                          \
0047         .num_parents = 1,                   \
0048         .flags = CLK_IGNORE_UNUSED,             \
0049     },                              \
0050 }
0051 
0052 AXG_AO_GATE(remote, 0);
0053 AXG_AO_GATE(i2c_master, 1);
0054 AXG_AO_GATE(i2c_slave, 2);
0055 AXG_AO_GATE(uart1, 3);
0056 AXG_AO_GATE(uart2, 5);
0057 AXG_AO_GATE(ir_blaster, 6);
0058 AXG_AO_GATE(saradc, 7);
0059 
0060 static struct clk_regmap axg_aoclk_cts_oscin = {
0061     .data = &(struct clk_regmap_gate_data){
0062         .offset = AO_RTI_PWR_CNTL_REG0,
0063         .bit_idx = 14,
0064     },
0065     .hw.init = &(struct clk_init_data){
0066         .name = "cts_oscin",
0067         .ops = &clk_regmap_gate_ro_ops,
0068         .parent_data = &(const struct clk_parent_data) {
0069             .fw_name = "xtal",
0070         },
0071         .num_parents = 1,
0072     },
0073 };
0074 
0075 static struct clk_regmap axg_aoclk_32k_pre = {
0076     .data = &(struct clk_regmap_gate_data){
0077         .offset = AO_RTC_ALT_CLK_CNTL0,
0078         .bit_idx = 31,
0079     },
0080     .hw.init = &(struct clk_init_data){
0081         .name = "axg_ao_32k_pre",
0082         .ops = &clk_regmap_gate_ops,
0083         .parent_hws = (const struct clk_hw *[]) {
0084             &axg_aoclk_cts_oscin.hw
0085         },
0086         .num_parents = 1,
0087     },
0088 };
0089 
0090 static const struct meson_clk_dualdiv_param axg_32k_div_table[] = {
0091     {
0092         .dual   = 1,
0093         .n1 = 733,
0094         .m1 = 8,
0095         .n2 = 732,
0096         .m2 = 11,
0097     }, {}
0098 };
0099 
0100 static struct clk_regmap axg_aoclk_32k_div = {
0101     .data = &(struct meson_clk_dualdiv_data){
0102         .n1 = {
0103             .reg_off = AO_RTC_ALT_CLK_CNTL0,
0104             .shift   = 0,
0105             .width   = 12,
0106         },
0107         .n2 = {
0108             .reg_off = AO_RTC_ALT_CLK_CNTL0,
0109             .shift   = 12,
0110             .width   = 12,
0111         },
0112         .m1 = {
0113             .reg_off = AO_RTC_ALT_CLK_CNTL1,
0114             .shift   = 0,
0115             .width   = 12,
0116         },
0117         .m2 = {
0118             .reg_off = AO_RTC_ALT_CLK_CNTL1,
0119             .shift   = 12,
0120             .width   = 12,
0121         },
0122         .dual = {
0123             .reg_off = AO_RTC_ALT_CLK_CNTL0,
0124             .shift   = 28,
0125             .width   = 1,
0126         },
0127         .table = axg_32k_div_table,
0128     },
0129     .hw.init = &(struct clk_init_data){
0130         .name = "axg_ao_32k_div",
0131         .ops = &meson_clk_dualdiv_ops,
0132         .parent_hws = (const struct clk_hw *[]) {
0133             &axg_aoclk_32k_pre.hw
0134         },
0135         .num_parents = 1,
0136     },
0137 };
0138 
0139 static struct clk_regmap axg_aoclk_32k_sel = {
0140     .data = &(struct clk_regmap_mux_data) {
0141         .offset = AO_RTC_ALT_CLK_CNTL1,
0142         .mask = 0x1,
0143         .shift = 24,
0144         .flags = CLK_MUX_ROUND_CLOSEST,
0145     },
0146     .hw.init = &(struct clk_init_data){
0147         .name = "axg_ao_32k_sel",
0148         .ops = &clk_regmap_mux_ops,
0149         .parent_hws = (const struct clk_hw *[]) {
0150             &axg_aoclk_32k_div.hw,
0151             &axg_aoclk_32k_pre.hw,
0152         },
0153         .num_parents = 2,
0154         .flags = CLK_SET_RATE_PARENT,
0155     },
0156 };
0157 
0158 static struct clk_regmap axg_aoclk_32k = {
0159     .data = &(struct clk_regmap_gate_data){
0160         .offset = AO_RTC_ALT_CLK_CNTL0,
0161         .bit_idx = 30,
0162     },
0163     .hw.init = &(struct clk_init_data){
0164         .name = "axg_ao_32k",
0165         .ops = &clk_regmap_gate_ops,
0166         .parent_hws = (const struct clk_hw *[]) {
0167             &axg_aoclk_32k_sel.hw
0168         },
0169         .num_parents = 1,
0170         .flags = CLK_SET_RATE_PARENT,
0171     },
0172 };
0173 
0174 static struct clk_regmap axg_aoclk_cts_rtc_oscin = {
0175     .data = &(struct clk_regmap_mux_data) {
0176         .offset = AO_RTI_PWR_CNTL_REG0,
0177         .mask = 0x1,
0178         .shift = 10,
0179         .flags = CLK_MUX_ROUND_CLOSEST,
0180     },
0181     .hw.init = &(struct clk_init_data){
0182         .name = "axg_ao_cts_rtc_oscin",
0183         .ops = &clk_regmap_mux_ops,
0184         .parent_data = (const struct clk_parent_data []) {
0185             { .hw = &axg_aoclk_32k.hw },
0186             { .fw_name = "ext_32k-0", },
0187         },
0188         .num_parents = 2,
0189         .flags = CLK_SET_RATE_PARENT,
0190     },
0191 };
0192 
0193 static struct clk_regmap axg_aoclk_clk81 = {
0194     .data = &(struct clk_regmap_mux_data) {
0195         .offset = AO_RTI_PWR_CNTL_REG0,
0196         .mask = 0x1,
0197         .shift = 8,
0198         .flags = CLK_MUX_ROUND_CLOSEST,
0199     },
0200     .hw.init = &(struct clk_init_data){
0201         .name = "axg_ao_clk81",
0202         .ops = &clk_regmap_mux_ro_ops,
0203         .parent_data = (const struct clk_parent_data []) {
0204             { .fw_name = "mpeg-clk", },
0205             { .hw = &axg_aoclk_cts_rtc_oscin.hw },
0206         },
0207         .num_parents = 2,
0208         .flags = CLK_SET_RATE_PARENT,
0209     },
0210 };
0211 
0212 static struct clk_regmap axg_aoclk_saradc_mux = {
0213     .data = &(struct clk_regmap_mux_data) {
0214         .offset = AO_SAR_CLK,
0215         .mask = 0x3,
0216         .shift = 9,
0217     },
0218     .hw.init = &(struct clk_init_data){
0219         .name = "axg_ao_saradc_mux",
0220         .ops = &clk_regmap_mux_ops,
0221         .parent_data = (const struct clk_parent_data []) {
0222             { .fw_name = "xtal", },
0223             { .hw = &axg_aoclk_clk81.hw },
0224         },
0225         .num_parents = 2,
0226     },
0227 };
0228 
0229 static struct clk_regmap axg_aoclk_saradc_div = {
0230     .data = &(struct clk_regmap_div_data) {
0231         .offset = AO_SAR_CLK,
0232         .shift = 0,
0233         .width = 8,
0234     },
0235     .hw.init = &(struct clk_init_data){
0236         .name = "axg_ao_saradc_div",
0237         .ops = &clk_regmap_divider_ops,
0238         .parent_hws = (const struct clk_hw *[]) {
0239             &axg_aoclk_saradc_mux.hw
0240         },
0241         .num_parents = 1,
0242         .flags = CLK_SET_RATE_PARENT,
0243     },
0244 };
0245 
0246 static struct clk_regmap axg_aoclk_saradc_gate = {
0247     .data = &(struct clk_regmap_gate_data) {
0248         .offset = AO_SAR_CLK,
0249         .bit_idx = 8,
0250     },
0251     .hw.init = &(struct clk_init_data){
0252         .name = "axg_ao_saradc_gate",
0253         .ops = &clk_regmap_gate_ops,
0254         .parent_hws = (const struct clk_hw *[]) {
0255             &axg_aoclk_saradc_div.hw
0256         },
0257         .num_parents = 1,
0258         .flags = CLK_SET_RATE_PARENT,
0259     },
0260 };
0261 
0262 static const unsigned int axg_aoclk_reset[] = {
0263     [RESET_AO_REMOTE]   = 16,
0264     [RESET_AO_I2C_MASTER]   = 18,
0265     [RESET_AO_I2C_SLAVE]    = 19,
0266     [RESET_AO_UART1]    = 17,
0267     [RESET_AO_UART2]    = 22,
0268     [RESET_AO_IR_BLASTER]   = 23,
0269 };
0270 
0271 static struct clk_regmap *axg_aoclk_regmap[] = {
0272     &axg_aoclk_remote,
0273     &axg_aoclk_i2c_master,
0274     &axg_aoclk_i2c_slave,
0275     &axg_aoclk_uart1,
0276     &axg_aoclk_uart2,
0277     &axg_aoclk_ir_blaster,
0278     &axg_aoclk_saradc,
0279     &axg_aoclk_cts_oscin,
0280     &axg_aoclk_32k_pre,
0281     &axg_aoclk_32k_div,
0282     &axg_aoclk_32k_sel,
0283     &axg_aoclk_32k,
0284     &axg_aoclk_cts_rtc_oscin,
0285     &axg_aoclk_clk81,
0286     &axg_aoclk_saradc_mux,
0287     &axg_aoclk_saradc_div,
0288     &axg_aoclk_saradc_gate,
0289 };
0290 
0291 static const struct clk_hw_onecell_data axg_aoclk_onecell_data = {
0292     .hws = {
0293         [CLKID_AO_REMOTE]   = &axg_aoclk_remote.hw,
0294         [CLKID_AO_I2C_MASTER]   = &axg_aoclk_i2c_master.hw,
0295         [CLKID_AO_I2C_SLAVE]    = &axg_aoclk_i2c_slave.hw,
0296         [CLKID_AO_UART1]    = &axg_aoclk_uart1.hw,
0297         [CLKID_AO_UART2]    = &axg_aoclk_uart2.hw,
0298         [CLKID_AO_IR_BLASTER]   = &axg_aoclk_ir_blaster.hw,
0299         [CLKID_AO_SAR_ADC]  = &axg_aoclk_saradc.hw,
0300         [CLKID_AO_CLK81]    = &axg_aoclk_clk81.hw,
0301         [CLKID_AO_SAR_ADC_SEL]  = &axg_aoclk_saradc_mux.hw,
0302         [CLKID_AO_SAR_ADC_DIV]  = &axg_aoclk_saradc_div.hw,
0303         [CLKID_AO_SAR_ADC_CLK]  = &axg_aoclk_saradc_gate.hw,
0304         [CLKID_AO_CTS_OSCIN]    = &axg_aoclk_cts_oscin.hw,
0305         [CLKID_AO_32K_PRE]  = &axg_aoclk_32k_pre.hw,
0306         [CLKID_AO_32K_DIV]  = &axg_aoclk_32k_div.hw,
0307         [CLKID_AO_32K_SEL]  = &axg_aoclk_32k_sel.hw,
0308         [CLKID_AO_32K]      = &axg_aoclk_32k.hw,
0309         [CLKID_AO_CTS_RTC_OSCIN] = &axg_aoclk_cts_rtc_oscin.hw,
0310     },
0311     .num = NR_CLKS,
0312 };
0313 
0314 static const struct meson_aoclk_data axg_aoclkc_data = {
0315     .reset_reg  = AO_RTI_GEN_CNTL_REG0,
0316     .num_reset  = ARRAY_SIZE(axg_aoclk_reset),
0317     .reset      = axg_aoclk_reset,
0318     .num_clks   = ARRAY_SIZE(axg_aoclk_regmap),
0319     .clks       = axg_aoclk_regmap,
0320     .hw_data    = &axg_aoclk_onecell_data,
0321 };
0322 
0323 static const struct of_device_id axg_aoclkc_match_table[] = {
0324     {
0325         .compatible = "amlogic,meson-axg-aoclkc",
0326         .data       = &axg_aoclkc_data,
0327     },
0328     { }
0329 };
0330 MODULE_DEVICE_TABLE(of, axg_aoclkc_match_table);
0331 
0332 static struct platform_driver axg_aoclkc_driver = {
0333     .probe      = meson_aoclkc_probe,
0334     .driver     = {
0335         .name   = "axg-aoclkc",
0336         .of_match_table = axg_aoclkc_match_table,
0337     },
0338 };
0339 
0340 module_platform_driver(axg_aoclkc_driver);
0341 MODULE_LICENSE("GPL v2");