0001
0002
0003
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
0059
0060
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,
0082 16, 2,
0083 24, 2,
0084 BIT(31),
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");