1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2020 Yangtao Li <frank@allwinnertech.com> |
4 | */ |
5 | |
6 | #include <linux/clk-provider.h> |
7 | #include <linux/module.h> |
8 | #include <linux/platform_device.h> |
9 | |
10 | #include "ccu_common.h" |
11 | #include "ccu_reset.h" |
12 | |
13 | #include "ccu_div.h" |
14 | #include "ccu_gate.h" |
15 | #include "ccu_mp.h" |
16 | #include "ccu_nm.h" |
17 | |
18 | #include "ccu-sun50i-a100-r.h" |
19 | |
20 | static const char * const cpus_r_apb2_parents[] = { "dcxo24M" , "osc32k" , |
21 | "iosc" , "pll-periph0" }; |
22 | static const struct ccu_mux_var_prediv cpus_r_apb2_predivs[] = { |
23 | { .index = 3, .shift = 0, .width = 5 }, |
24 | }; |
25 | |
26 | static struct ccu_div r_cpus_clk = { |
27 | .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), |
28 | |
29 | .mux = { |
30 | .shift = 24, |
31 | .width = 2, |
32 | |
33 | .var_predivs = cpus_r_apb2_predivs, |
34 | .n_var_predivs = ARRAY_SIZE(cpus_r_apb2_predivs), |
35 | }, |
36 | |
37 | .common = { |
38 | .reg = 0x000, |
39 | .features = CCU_FEATURE_VARIABLE_PREDIV, |
40 | .hw.init = CLK_HW_INIT_PARENTS("cpus" , |
41 | cpus_r_apb2_parents, |
42 | &ccu_div_ops, |
43 | 0), |
44 | }, |
45 | }; |
46 | |
47 | static CLK_FIXED_FACTOR_HW(r_ahb_clk, "r-ahb" , &r_cpus_clk.common.hw, 1, 1, 0); |
48 | |
49 | static struct ccu_div r_apb1_clk = { |
50 | .div = _SUNXI_CCU_DIV(0, 2), |
51 | |
52 | .common = { |
53 | .reg = 0x00c, |
54 | .hw.init = CLK_HW_INIT("r-apb1" , |
55 | "r-ahb" , |
56 | &ccu_div_ops, |
57 | 0), |
58 | }, |
59 | }; |
60 | |
61 | static struct ccu_div r_apb2_clk = { |
62 | .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), |
63 | |
64 | .mux = { |
65 | .shift = 24, |
66 | .width = 2, |
67 | |
68 | .var_predivs = cpus_r_apb2_predivs, |
69 | .n_var_predivs = ARRAY_SIZE(cpus_r_apb2_predivs), |
70 | }, |
71 | |
72 | .common = { |
73 | .reg = 0x010, |
74 | .features = CCU_FEATURE_VARIABLE_PREDIV, |
75 | .hw.init = CLK_HW_INIT_PARENTS("r-apb2" , |
76 | cpus_r_apb2_parents, |
77 | &ccu_div_ops, |
78 | 0), |
79 | }, |
80 | }; |
81 | |
82 | static const struct clk_parent_data clk_parent_r_apb1[] = { |
83 | { .hw = &r_apb1_clk.common.hw }, |
84 | }; |
85 | |
86 | static const struct clk_parent_data clk_parent_r_apb2[] = { |
87 | { .hw = &r_apb2_clk.common.hw }, |
88 | }; |
89 | |
90 | static SUNXI_CCU_GATE_DATA(r_apb1_timer_clk, "r-apb1-timer" , clk_parent_r_apb1, |
91 | 0x11c, BIT(0), 0); |
92 | |
93 | static SUNXI_CCU_GATE_DATA(r_apb1_twd_clk, "r-apb1-twd" , clk_parent_r_apb1, |
94 | 0x12c, BIT(0), 0); |
95 | |
96 | static const char * const r_apb1_pwm_clk_parents[] = { "dcxo24M" , "osc32k" , |
97 | "iosc" }; |
98 | static SUNXI_CCU_MUX(r_apb1_pwm_clk, "r-apb1-pwm" , r_apb1_pwm_clk_parents, |
99 | 0x130, 24, 2, 0); |
100 | |
101 | static SUNXI_CCU_GATE_DATA(r_apb1_bus_pwm_clk, "r-apb1-bus-pwm" , |
102 | clk_parent_r_apb1, 0x13c, BIT(0), 0); |
103 | |
104 | static SUNXI_CCU_GATE_DATA(r_apb1_ppu_clk, "r-apb1-ppu" , clk_parent_r_apb1, |
105 | 0x17c, BIT(0), 0); |
106 | |
107 | static SUNXI_CCU_GATE_DATA(r_apb2_uart_clk, "r-apb2-uart" , clk_parent_r_apb2, |
108 | 0x18c, BIT(0), 0); |
109 | |
110 | static SUNXI_CCU_GATE_DATA(r_apb2_i2c0_clk, "r-apb2-i2c0" , clk_parent_r_apb2, |
111 | 0x19c, BIT(0), 0); |
112 | |
113 | static SUNXI_CCU_GATE_DATA(r_apb2_i2c1_clk, "r-apb2-i2c1" , clk_parent_r_apb2, |
114 | 0x19c, BIT(1), 0); |
115 | |
116 | static const char * const r_apb1_ir_rx_parents[] = { "osc32k" , "dcxo24M" }; |
117 | static SUNXI_CCU_MP_WITH_MUX_GATE(r_apb1_ir_rx_clk, "r-apb1-ir-rx" , |
118 | r_apb1_ir_rx_parents, 0x1c0, |
119 | 0, 5, /* M */ |
120 | 8, 2, /* P */ |
121 | 24, 1, /* mux */ |
122 | BIT(31), /* gate */ |
123 | 0); |
124 | |
125 | static SUNXI_CCU_GATE_DATA(r_apb1_bus_ir_rx_clk, "r-apb1-bus-ir-rx" , |
126 | clk_parent_r_apb1, 0x1cc, BIT(0), 0); |
127 | |
128 | static SUNXI_CCU_GATE(r_ahb_bus_rtc_clk, "r-ahb-rtc" , "r-ahb" , |
129 | 0x20c, BIT(0), 0); |
130 | |
131 | static struct ccu_common *sun50i_a100_r_ccu_clks[] = { |
132 | &r_cpus_clk.common, |
133 | &r_apb1_clk.common, |
134 | &r_apb2_clk.common, |
135 | &r_apb1_timer_clk.common, |
136 | &r_apb1_twd_clk.common, |
137 | &r_apb1_pwm_clk.common, |
138 | &r_apb1_bus_pwm_clk.common, |
139 | &r_apb1_ppu_clk.common, |
140 | &r_apb2_uart_clk.common, |
141 | &r_apb2_i2c0_clk.common, |
142 | &r_apb2_i2c1_clk.common, |
143 | &r_apb1_ir_rx_clk.common, |
144 | &r_apb1_bus_ir_rx_clk.common, |
145 | &r_ahb_bus_rtc_clk.common, |
146 | }; |
147 | |
148 | static struct clk_hw_onecell_data sun50i_a100_r_hw_clks = { |
149 | .hws = { |
150 | [CLK_R_CPUS] = &r_cpus_clk.common.hw, |
151 | [CLK_R_AHB] = &r_ahb_clk.hw, |
152 | [CLK_R_APB1] = &r_apb1_clk.common.hw, |
153 | [CLK_R_APB2] = &r_apb2_clk.common.hw, |
154 | [CLK_R_APB1_TIMER] = &r_apb1_timer_clk.common.hw, |
155 | [CLK_R_APB1_TWD] = &r_apb1_twd_clk.common.hw, |
156 | [CLK_R_APB1_PWM] = &r_apb1_pwm_clk.common.hw, |
157 | [CLK_R_APB1_BUS_PWM] = &r_apb1_bus_pwm_clk.common.hw, |
158 | [CLK_R_APB1_PPU] = &r_apb1_ppu_clk.common.hw, |
159 | [CLK_R_APB2_UART] = &r_apb2_uart_clk.common.hw, |
160 | [CLK_R_APB2_I2C0] = &r_apb2_i2c0_clk.common.hw, |
161 | [CLK_R_APB2_I2C1] = &r_apb2_i2c1_clk.common.hw, |
162 | [CLK_R_APB1_IR] = &r_apb1_ir_rx_clk.common.hw, |
163 | [CLK_R_APB1_BUS_IR] = &r_apb1_bus_ir_rx_clk.common.hw, |
164 | [CLK_R_AHB_BUS_RTC] = &r_ahb_bus_rtc_clk.common.hw, |
165 | }, |
166 | .num = CLK_NUMBER, |
167 | }; |
168 | |
169 | static struct ccu_reset_map sun50i_a100_r_ccu_resets[] = { |
170 | [RST_R_APB1_TIMER] = { 0x11c, BIT(16) }, |
171 | [RST_R_APB1_BUS_PWM] = { 0x13c, BIT(16) }, |
172 | [RST_R_APB1_PPU] = { 0x17c, BIT(16) }, |
173 | [RST_R_APB2_UART] = { 0x18c, BIT(16) }, |
174 | [RST_R_APB2_I2C0] = { 0x19c, BIT(16) }, |
175 | [RST_R_APB2_I2C1] = { 0x19c, BIT(17) }, |
176 | [RST_R_APB1_BUS_IR] = { 0x1cc, BIT(16) }, |
177 | [RST_R_AHB_BUS_RTC] = { 0x20c, BIT(16) }, |
178 | }; |
179 | |
180 | static const struct sunxi_ccu_desc sun50i_a100_r_ccu_desc = { |
181 | .ccu_clks = sun50i_a100_r_ccu_clks, |
182 | .num_ccu_clks = ARRAY_SIZE(sun50i_a100_r_ccu_clks), |
183 | |
184 | .hw_clks = &sun50i_a100_r_hw_clks, |
185 | |
186 | .resets = sun50i_a100_r_ccu_resets, |
187 | .num_resets = ARRAY_SIZE(sun50i_a100_r_ccu_resets), |
188 | }; |
189 | |
190 | static int sun50i_a100_r_ccu_probe(struct platform_device *pdev) |
191 | { |
192 | void __iomem *reg; |
193 | |
194 | reg = devm_platform_ioremap_resource(pdev, index: 0); |
195 | if (IS_ERR(ptr: reg)) |
196 | return PTR_ERR(ptr: reg); |
197 | |
198 | return devm_sunxi_ccu_probe(dev: &pdev->dev, reg, desc: &sun50i_a100_r_ccu_desc); |
199 | } |
200 | |
201 | static const struct of_device_id sun50i_a100_r_ccu_ids[] = { |
202 | { .compatible = "allwinner,sun50i-a100-r-ccu" }, |
203 | { } |
204 | }; |
205 | |
206 | static struct platform_driver sun50i_a100_r_ccu_driver = { |
207 | .probe = sun50i_a100_r_ccu_probe, |
208 | .driver = { |
209 | .name = "sun50i-a100-r-ccu" , |
210 | .suppress_bind_attrs = true, |
211 | .of_match_table = sun50i_a100_r_ccu_ids, |
212 | }, |
213 | }; |
214 | module_platform_driver(sun50i_a100_r_ccu_driver); |
215 | |
216 | MODULE_IMPORT_NS(SUNXI_CCU); |
217 | MODULE_LICENSE("GPL" ); |
218 | |