Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2016 Icenowy Zheng <icenowy@aosc.xyz>
0004  */
0005 
0006 #include <linux/clk-provider.h>
0007 #include <linux/module.h>
0008 #include <linux/of_device.h>
0009 #include <linux/platform_device.h>
0010 
0011 #include "ccu_common.h"
0012 #include "ccu_reset.h"
0013 
0014 #include "ccu_div.h"
0015 #include "ccu_gate.h"
0016 #include "ccu_mp.h"
0017 #include "ccu_nm.h"
0018 
0019 #include "ccu-sun8i-r.h"
0020 
0021 static const struct clk_parent_data ar100_parents[] = {
0022     { .fw_name = "losc" },
0023     { .fw_name = "hosc" },
0024     { .fw_name = "pll-periph" },
0025     { .fw_name = "iosc" },
0026 };
0027 
0028 static const struct ccu_mux_var_prediv ar100_predivs[] = {
0029     { .index = 2, .shift = 8, .width = 5 },
0030 };
0031 
0032 static struct ccu_div ar100_clk = {
0033     .div        = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
0034 
0035     .mux        = {
0036         .shift  = 16,
0037         .width  = 2,
0038 
0039         .var_predivs    = ar100_predivs,
0040         .n_var_predivs  = ARRAY_SIZE(ar100_predivs),
0041     },
0042 
0043     .common     = {
0044         .reg        = 0x00,
0045         .features   = CCU_FEATURE_VARIABLE_PREDIV,
0046         .hw.init    = CLK_HW_INIT_PARENTS_DATA("ar100",
0047                                ar100_parents,
0048                                &ccu_div_ops,
0049                                0),
0050     },
0051 };
0052 
0053 static CLK_FIXED_FACTOR_HW(ahb0_clk, "ahb0", &ar100_clk.common.hw, 1, 1, 0);
0054 
0055 static SUNXI_CCU_M(apb0_clk, "apb0", "ahb0", 0x0c, 0, 2, 0);
0056 
0057 /*
0058  * Define the parent as an array that can be reused to save space
0059  * instead of having compound literals for each gate. Also have it
0060  * non-const so we can change it on the A83T.
0061  */
0062 static const struct clk_hw *apb0_gate_parent[] = { &apb0_clk.common.hw };
0063 static SUNXI_CCU_GATE_HWS(apb0_pio_clk,     "apb0-pio",
0064               apb0_gate_parent, 0x28, BIT(0), 0);
0065 static SUNXI_CCU_GATE_HWS(apb0_ir_clk,      "apb0-ir",
0066               apb0_gate_parent, 0x28, BIT(1), 0);
0067 static SUNXI_CCU_GATE_HWS(apb0_timer_clk,   "apb0-timer",
0068               apb0_gate_parent, 0x28, BIT(2), 0);
0069 static SUNXI_CCU_GATE_HWS(apb0_rsb_clk,     "apb0-rsb",
0070               apb0_gate_parent, 0x28, BIT(3), 0);
0071 static SUNXI_CCU_GATE_HWS(apb0_uart_clk,    "apb0-uart",
0072               apb0_gate_parent, 0x28, BIT(4), 0);
0073 static SUNXI_CCU_GATE_HWS(apb0_i2c_clk,     "apb0-i2c",
0074               apb0_gate_parent, 0x28, BIT(6), 0);
0075 static SUNXI_CCU_GATE_HWS(apb0_twd_clk,     "apb0-twd",
0076               apb0_gate_parent, 0x28, BIT(7), 0);
0077 
0078 static const char * const r_mod0_default_parents[] = { "osc32k", "osc24M" };
0079 static SUNXI_CCU_MP_WITH_MUX_GATE(ir_clk, "ir",
0080                   r_mod0_default_parents, 0x54,
0081                   0, 4,     /* M */
0082                   16, 2,    /* P */
0083                   24, 2,    /* mux */
0084                   BIT(31),  /* gate */
0085                   0);
0086 
0087 static const struct clk_parent_data a83t_r_mod0_parents[] = {
0088     { .fw_name = "iosc" },
0089     { .fw_name = "hosc" },
0090 };
0091 static const struct ccu_mux_fixed_prediv a83t_ir_predivs[] = {
0092     { .index = 0, .div = 16 },
0093 };
0094 static struct ccu_mp a83t_ir_clk = {
0095     .enable = BIT(31),
0096 
0097     .m  = _SUNXI_CCU_DIV(0, 4),
0098     .p  = _SUNXI_CCU_DIV(16, 2),
0099 
0100     .mux    = {
0101         .shift  = 24,
0102         .width  = 2,
0103         .fixed_predivs  = a83t_ir_predivs,
0104         .n_predivs  = ARRAY_SIZE(a83t_ir_predivs),
0105     },
0106 
0107     .common     = {
0108         .reg        = 0x54,
0109         .features   = CCU_FEATURE_VARIABLE_PREDIV,
0110         .hw.init    = CLK_HW_INIT_PARENTS_DATA("ir",
0111                                a83t_r_mod0_parents,
0112                                &ccu_mp_ops,
0113                                0),
0114     },
0115 };
0116 
0117 static struct ccu_common *sun8i_r_ccu_clks[] = {
0118     &ar100_clk.common,
0119     &apb0_clk.common,
0120     &apb0_pio_clk.common,
0121     &apb0_ir_clk.common,
0122     &apb0_timer_clk.common,
0123     &apb0_rsb_clk.common,
0124     &apb0_uart_clk.common,
0125     &apb0_i2c_clk.common,
0126     &apb0_twd_clk.common,
0127     &ir_clk.common,
0128     &a83t_ir_clk.common,
0129 };
0130 
0131 static struct clk_hw_onecell_data sun8i_a83t_r_hw_clks = {
0132     .hws    = {
0133         [CLK_AR100]     = &ar100_clk.common.hw,
0134         [CLK_AHB0]      = &ahb0_clk.hw,
0135         [CLK_APB0]      = &apb0_clk.common.hw,
0136         [CLK_APB0_PIO]      = &apb0_pio_clk.common.hw,
0137         [CLK_APB0_IR]       = &apb0_ir_clk.common.hw,
0138         [CLK_APB0_TIMER]    = &apb0_timer_clk.common.hw,
0139         [CLK_APB0_RSB]      = &apb0_rsb_clk.common.hw,
0140         [CLK_APB0_UART]     = &apb0_uart_clk.common.hw,
0141         [CLK_APB0_I2C]      = &apb0_i2c_clk.common.hw,
0142         [CLK_APB0_TWD]      = &apb0_twd_clk.common.hw,
0143         [CLK_IR]        = &a83t_ir_clk.common.hw,
0144     },
0145     .num    = CLK_NUMBER,
0146 };
0147 
0148 static struct clk_hw_onecell_data sun8i_h3_r_hw_clks = {
0149     .hws    = {
0150         [CLK_AR100]     = &ar100_clk.common.hw,
0151         [CLK_AHB0]      = &ahb0_clk.hw,
0152         [CLK_APB0]      = &apb0_clk.common.hw,
0153         [CLK_APB0_PIO]      = &apb0_pio_clk.common.hw,
0154         [CLK_APB0_IR]       = &apb0_ir_clk.common.hw,
0155         [CLK_APB0_TIMER]    = &apb0_timer_clk.common.hw,
0156         [CLK_APB0_UART]     = &apb0_uart_clk.common.hw,
0157         [CLK_APB0_I2C]      = &apb0_i2c_clk.common.hw,
0158         [CLK_APB0_TWD]      = &apb0_twd_clk.common.hw,
0159         [CLK_IR]        = &ir_clk.common.hw,
0160     },
0161     .num    = CLK_NUMBER,
0162 };
0163 
0164 static struct clk_hw_onecell_data sun50i_a64_r_hw_clks = {
0165     .hws    = {
0166         [CLK_AR100]     = &ar100_clk.common.hw,
0167         [CLK_AHB0]      = &ahb0_clk.hw,
0168         [CLK_APB0]      = &apb0_clk.common.hw,
0169         [CLK_APB0_PIO]      = &apb0_pio_clk.common.hw,
0170         [CLK_APB0_IR]       = &apb0_ir_clk.common.hw,
0171         [CLK_APB0_TIMER]    = &apb0_timer_clk.common.hw,
0172         [CLK_APB0_RSB]      = &apb0_rsb_clk.common.hw,
0173         [CLK_APB0_UART]     = &apb0_uart_clk.common.hw,
0174         [CLK_APB0_I2C]      = &apb0_i2c_clk.common.hw,
0175         [CLK_APB0_TWD]      = &apb0_twd_clk.common.hw,
0176         [CLK_IR]        = &ir_clk.common.hw,
0177     },
0178     .num    = CLK_NUMBER,
0179 };
0180 
0181 static struct ccu_reset_map sun8i_a83t_r_ccu_resets[] = {
0182     [RST_APB0_IR]       =  { 0xb0, BIT(1) },
0183     [RST_APB0_TIMER]    =  { 0xb0, BIT(2) },
0184     [RST_APB0_RSB]      =  { 0xb0, BIT(3) },
0185     [RST_APB0_UART]     =  { 0xb0, BIT(4) },
0186     [RST_APB0_I2C]      =  { 0xb0, BIT(6) },
0187 };
0188 
0189 static struct ccu_reset_map sun8i_h3_r_ccu_resets[] = {
0190     [RST_APB0_IR]       =  { 0xb0, BIT(1) },
0191     [RST_APB0_TIMER]    =  { 0xb0, BIT(2) },
0192     [RST_APB0_UART]     =  { 0xb0, BIT(4) },
0193     [RST_APB0_I2C]      =  { 0xb0, BIT(6) },
0194 };
0195 
0196 static struct ccu_reset_map sun50i_a64_r_ccu_resets[] = {
0197     [RST_APB0_IR]       =  { 0xb0, BIT(1) },
0198     [RST_APB0_TIMER]    =  { 0xb0, BIT(2) },
0199     [RST_APB0_RSB]      =  { 0xb0, BIT(3) },
0200     [RST_APB0_UART]     =  { 0xb0, BIT(4) },
0201     [RST_APB0_I2C]      =  { 0xb0, BIT(6) },
0202 };
0203 
0204 static const struct sunxi_ccu_desc sun8i_a83t_r_ccu_desc = {
0205     .ccu_clks   = sun8i_r_ccu_clks,
0206     .num_ccu_clks   = ARRAY_SIZE(sun8i_r_ccu_clks),
0207 
0208     .hw_clks    = &sun8i_a83t_r_hw_clks,
0209 
0210     .resets     = sun8i_a83t_r_ccu_resets,
0211     .num_resets = ARRAY_SIZE(sun8i_a83t_r_ccu_resets),
0212 };
0213 
0214 static const struct sunxi_ccu_desc sun8i_h3_r_ccu_desc = {
0215     .ccu_clks   = sun8i_r_ccu_clks,
0216     .num_ccu_clks   = ARRAY_SIZE(sun8i_r_ccu_clks),
0217 
0218     .hw_clks    = &sun8i_h3_r_hw_clks,
0219 
0220     .resets     = sun8i_h3_r_ccu_resets,
0221     .num_resets = ARRAY_SIZE(sun8i_h3_r_ccu_resets),
0222 };
0223 
0224 static const struct sunxi_ccu_desc sun50i_a64_r_ccu_desc = {
0225     .ccu_clks   = sun8i_r_ccu_clks,
0226     .num_ccu_clks   = ARRAY_SIZE(sun8i_r_ccu_clks),
0227 
0228     .hw_clks    = &sun50i_a64_r_hw_clks,
0229 
0230     .resets     = sun50i_a64_r_ccu_resets,
0231     .num_resets = ARRAY_SIZE(sun50i_a64_r_ccu_resets),
0232 };
0233 
0234 static int sun8i_r_ccu_probe(struct platform_device *pdev)
0235 {
0236     const struct sunxi_ccu_desc *desc;
0237     void __iomem *reg;
0238 
0239     desc = of_device_get_match_data(&pdev->dev);
0240     if (!desc)
0241         return -EINVAL;
0242 
0243     reg = devm_platform_ioremap_resource(pdev, 0);
0244     if (IS_ERR(reg))
0245         return PTR_ERR(reg);
0246 
0247     return devm_sunxi_ccu_probe(&pdev->dev, reg, desc);
0248 }
0249 
0250 static const struct of_device_id sun8i_r_ccu_ids[] = {
0251     {
0252         .compatible = "allwinner,sun8i-a83t-r-ccu",
0253         .data = &sun8i_a83t_r_ccu_desc,
0254     },
0255     {
0256         .compatible = "allwinner,sun8i-h3-r-ccu",
0257         .data = &sun8i_h3_r_ccu_desc,
0258     },
0259     {
0260         .compatible = "allwinner,sun50i-a64-r-ccu",
0261         .data = &sun50i_a64_r_ccu_desc,
0262     },
0263     { }
0264 };
0265 
0266 static struct platform_driver sun8i_r_ccu_driver = {
0267     .probe  = sun8i_r_ccu_probe,
0268     .driver = {
0269         .name           = "sun8i-r-ccu",
0270         .suppress_bind_attrs    = true,
0271         .of_match_table     = sun8i_r_ccu_ids,
0272     },
0273 };
0274 module_platform_driver(sun8i_r_ccu_driver);
0275 
0276 MODULE_IMPORT_NS(SUNXI_CCU);
0277 MODULE_LICENSE("GPL");