Commit | Line | Data |
---|---|---|
1ccea77e | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
c80dfd9b PW |
2 | /* |
3 | * Hi3516CV300 Clock and Reset Generator Driver | |
4 | * | |
5 | * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. | |
c80dfd9b PW |
6 | */ |
7 | ||
8 | #include <dt-bindings/clock/hi3516cv300-clock.h> | |
9 | #include <linux/clk-provider.h> | |
10 | #include <linux/module.h> | |
11 | #include <linux/of_device.h> | |
12 | #include <linux/platform_device.h> | |
13 | #include "clk.h" | |
14 | #include "crg.h" | |
15 | #include "reset.h" | |
16 | ||
17 | /* hi3516CV300 core CRG */ | |
18 | #define HI3516CV300_INNER_CLK_OFFSET 64 | |
19 | #define HI3516CV300_FIXED_3M 65 | |
20 | #define HI3516CV300_FIXED_6M 66 | |
21 | #define HI3516CV300_FIXED_24M 67 | |
22 | #define HI3516CV300_FIXED_49P5 68 | |
23 | #define HI3516CV300_FIXED_50M 69 | |
24 | #define HI3516CV300_FIXED_83P3M 70 | |
25 | #define HI3516CV300_FIXED_99M 71 | |
26 | #define HI3516CV300_FIXED_100M 72 | |
27 | #define HI3516CV300_FIXED_148P5M 73 | |
28 | #define HI3516CV300_FIXED_198M 74 | |
29 | #define HI3516CV300_FIXED_297M 75 | |
30 | #define HI3516CV300_UART_MUX 76 | |
31 | #define HI3516CV300_FMC_MUX 77 | |
32 | #define HI3516CV300_MMC0_MUX 78 | |
33 | #define HI3516CV300_MMC1_MUX 79 | |
34 | #define HI3516CV300_MMC2_MUX 80 | |
35 | #define HI3516CV300_MMC3_MUX 81 | |
36 | #define HI3516CV300_PWM_MUX 82 | |
37 | #define HI3516CV300_CRG_NR_CLKS 128 | |
38 | ||
39 | static const struct hisi_fixed_rate_clock hi3516cv300_fixed_rate_clks[] = { | |
40 | { HI3516CV300_FIXED_3M, "3m", NULL, 0, 3000000, }, | |
41 | { HI3516CV300_FIXED_6M, "6m", NULL, 0, 6000000, }, | |
42 | { HI3516CV300_FIXED_24M, "24m", NULL, 0, 24000000, }, | |
43 | { HI3516CV300_FIXED_49P5, "49.5m", NULL, 0, 49500000, }, | |
44 | { HI3516CV300_FIXED_50M, "50m", NULL, 0, 50000000, }, | |
45 | { HI3516CV300_FIXED_83P3M, "83.3m", NULL, 0, 83300000, }, | |
46 | { HI3516CV300_FIXED_99M, "99m", NULL, 0, 99000000, }, | |
47 | { HI3516CV300_FIXED_100M, "100m", NULL, 0, 100000000, }, | |
48 | { HI3516CV300_FIXED_148P5M, "148.5m", NULL, 0, 148500000, }, | |
49 | { HI3516CV300_FIXED_198M, "198m", NULL, 0, 198000000, }, | |
50 | { HI3516CV300_FIXED_297M, "297m", NULL, 0, 297000000, }, | |
51 | { HI3516CV300_APB_CLK, "apb", NULL, 0, 50000000, }, | |
52 | }; | |
53 | ||
54 | static const char *const uart_mux_p[] = {"24m", "6m"}; | |
55 | static const char *const fmc_mux_p[] = { | |
56 | "24m", "83.3m", "148.5m", "198m", "297m" | |
57 | }; | |
58 | static const char *const mmc_mux_p[] = {"49.5m"}; | |
59 | static const char *const mmc2_mux_p[] = {"99m", "49.5m"}; | |
60 | static const char *const pwm_mux_p[] = {"3m", "50m", "24m", "24m"}; | |
61 | ||
62 | static u32 uart_mux_table[] = {0, 1}; | |
63 | static u32 fmc_mux_table[] = {0, 1, 2, 3, 4}; | |
64 | static u32 mmc_mux_table[] = {0}; | |
65 | static u32 mmc2_mux_table[] = {0, 2}; | |
66 | static u32 pwm_mux_table[] = {0, 1, 2, 3}; | |
67 | ||
68 | static const struct hisi_mux_clock hi3516cv300_mux_clks[] = { | |
69 | { HI3516CV300_UART_MUX, "uart_mux", uart_mux_p, ARRAY_SIZE(uart_mux_p), | |
70 | CLK_SET_RATE_PARENT, 0xe4, 19, 1, 0, uart_mux_table, }, | |
71 | { HI3516CV300_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p), | |
72 | CLK_SET_RATE_PARENT, 0xc0, 2, 3, 0, fmc_mux_table, }, | |
73 | { HI3516CV300_MMC0_MUX, "mmc0_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p), | |
74 | CLK_SET_RATE_PARENT, 0xc4, 4, 2, 0, mmc_mux_table, }, | |
75 | { HI3516CV300_MMC1_MUX, "mmc1_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p), | |
76 | CLK_SET_RATE_PARENT, 0xc4, 12, 2, 0, mmc_mux_table, }, | |
77 | { HI3516CV300_MMC2_MUX, "mmc2_mux", mmc2_mux_p, ARRAY_SIZE(mmc2_mux_p), | |
78 | CLK_SET_RATE_PARENT, 0xc4, 20, 2, 0, mmc2_mux_table, }, | |
79 | { HI3516CV300_MMC3_MUX, "mmc3_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p), | |
80 | CLK_SET_RATE_PARENT, 0xc8, 4, 2, 0, mmc_mux_table, }, | |
81 | { HI3516CV300_PWM_MUX, "pwm_mux", pwm_mux_p, ARRAY_SIZE(pwm_mux_p), | |
82 | CLK_SET_RATE_PARENT, 0x38, 2, 2, 0, pwm_mux_table, }, | |
83 | }; | |
84 | ||
85 | static const struct hisi_gate_clock hi3516cv300_gate_clks[] = { | |
86 | ||
87 | { HI3516CV300_UART0_CLK, "clk_uart0", "uart_mux", CLK_SET_RATE_PARENT, | |
88 | 0xe4, 15, 0, }, | |
89 | { HI3516CV300_UART1_CLK, "clk_uart1", "uart_mux", CLK_SET_RATE_PARENT, | |
90 | 0xe4, 16, 0, }, | |
91 | { HI3516CV300_UART2_CLK, "clk_uart2", "uart_mux", CLK_SET_RATE_PARENT, | |
92 | 0xe4, 17, 0, }, | |
93 | ||
94 | { HI3516CV300_SPI0_CLK, "clk_spi0", "100m", CLK_SET_RATE_PARENT, | |
95 | 0xe4, 13, 0, }, | |
96 | { HI3516CV300_SPI1_CLK, "clk_spi1", "100m", CLK_SET_RATE_PARENT, | |
97 | 0xe4, 14, 0, }, | |
98 | ||
99 | { HI3516CV300_FMC_CLK, "clk_fmc", "fmc_mux", CLK_SET_RATE_PARENT, | |
100 | 0xc0, 1, 0, }, | |
101 | { HI3516CV300_MMC0_CLK, "clk_mmc0", "mmc0_mux", CLK_SET_RATE_PARENT, | |
102 | 0xc4, 1, 0, }, | |
103 | { HI3516CV300_MMC1_CLK, "clk_mmc1", "mmc1_mux", CLK_SET_RATE_PARENT, | |
104 | 0xc4, 9, 0, }, | |
105 | { HI3516CV300_MMC2_CLK, "clk_mmc2", "mmc2_mux", CLK_SET_RATE_PARENT, | |
106 | 0xc4, 17, 0, }, | |
107 | { HI3516CV300_MMC3_CLK, "clk_mmc3", "mmc3_mux", CLK_SET_RATE_PARENT, | |
108 | 0xc8, 1, 0, }, | |
109 | ||
110 | { HI3516CV300_ETH_CLK, "clk_eth", NULL, 0, 0xec, 1, 0, }, | |
111 | ||
112 | { HI3516CV300_DMAC_CLK, "clk_dmac", NULL, 0, 0xd8, 5, 0, }, | |
113 | { HI3516CV300_PWM_CLK, "clk_pwm", "pwm_mux", CLK_SET_RATE_PARENT, | |
114 | 0x38, 1, 0, }, | |
115 | ||
116 | { HI3516CV300_USB2_BUS_CLK, "clk_usb2_bus", NULL, 0, 0xb8, 0, 0, }, | |
117 | { HI3516CV300_USB2_OHCI48M_CLK, "clk_usb2_ohci48m", NULL, 0, | |
118 | 0xb8, 1, 0, }, | |
119 | { HI3516CV300_USB2_OHCI12M_CLK, "clk_usb2_ohci12m", NULL, 0, | |
120 | 0xb8, 2, 0, }, | |
121 | { HI3516CV300_USB2_OTG_UTMI_CLK, "clk_usb2_otg_utmi", NULL, 0, | |
122 | 0xb8, 3, 0, }, | |
123 | { HI3516CV300_USB2_HST_PHY_CLK, "clk_usb2_hst_phy", NULL, 0, | |
124 | 0xb8, 4, 0, }, | |
125 | { HI3516CV300_USB2_UTMI0_CLK, "clk_usb2_utmi0", NULL, 0, 0xb8, 5, 0, }, | |
126 | { HI3516CV300_USB2_PHY_CLK, "clk_usb2_phy", NULL, 0, 0xb8, 7, 0, }, | |
127 | }; | |
128 | ||
129 | static struct hisi_clock_data *hi3516cv300_clk_register( | |
130 | struct platform_device *pdev) | |
131 | { | |
132 | struct hisi_clock_data *clk_data; | |
133 | int ret; | |
134 | ||
135 | clk_data = hisi_clk_alloc(pdev, HI3516CV300_CRG_NR_CLKS); | |
136 | if (!clk_data) | |
137 | return ERR_PTR(-ENOMEM); | |
138 | ||
139 | ret = hisi_clk_register_fixed_rate(hi3516cv300_fixed_rate_clks, | |
140 | ARRAY_SIZE(hi3516cv300_fixed_rate_clks), clk_data); | |
141 | if (ret) | |
142 | return ERR_PTR(ret); | |
143 | ||
144 | ret = hisi_clk_register_mux(hi3516cv300_mux_clks, | |
145 | ARRAY_SIZE(hi3516cv300_mux_clks), clk_data); | |
146 | if (ret) | |
147 | goto unregister_fixed_rate; | |
148 | ||
149 | ret = hisi_clk_register_gate(hi3516cv300_gate_clks, | |
150 | ARRAY_SIZE(hi3516cv300_gate_clks), clk_data); | |
151 | if (ret) | |
152 | goto unregister_mux; | |
153 | ||
154 | ret = of_clk_add_provider(pdev->dev.of_node, | |
155 | of_clk_src_onecell_get, &clk_data->clk_data); | |
156 | if (ret) | |
157 | goto unregister_gate; | |
158 | ||
159 | return clk_data; | |
160 | ||
161 | unregister_gate: | |
162 | hisi_clk_unregister_gate(hi3516cv300_gate_clks, | |
163 | ARRAY_SIZE(hi3516cv300_gate_clks), clk_data); | |
164 | unregister_mux: | |
165 | hisi_clk_unregister_mux(hi3516cv300_mux_clks, | |
166 | ARRAY_SIZE(hi3516cv300_mux_clks), clk_data); | |
167 | unregister_fixed_rate: | |
168 | hisi_clk_unregister_fixed_rate(hi3516cv300_fixed_rate_clks, | |
169 | ARRAY_SIZE(hi3516cv300_fixed_rate_clks), clk_data); | |
170 | return ERR_PTR(ret); | |
171 | } | |
172 | ||
173 | static void hi3516cv300_clk_unregister(struct platform_device *pdev) | |
174 | { | |
175 | struct hisi_crg_dev *crg = platform_get_drvdata(pdev); | |
176 | ||
177 | of_clk_del_provider(pdev->dev.of_node); | |
178 | ||
179 | hisi_clk_unregister_gate(hi3516cv300_gate_clks, | |
180 | ARRAY_SIZE(hi3516cv300_gate_clks), crg->clk_data); | |
181 | hisi_clk_unregister_mux(hi3516cv300_mux_clks, | |
182 | ARRAY_SIZE(hi3516cv300_mux_clks), crg->clk_data); | |
183 | hisi_clk_unregister_fixed_rate(hi3516cv300_fixed_rate_clks, | |
184 | ARRAY_SIZE(hi3516cv300_fixed_rate_clks), crg->clk_data); | |
185 | } | |
186 | ||
187 | static const struct hisi_crg_funcs hi3516cv300_crg_funcs = { | |
188 | .register_clks = hi3516cv300_clk_register, | |
189 | .unregister_clks = hi3516cv300_clk_unregister, | |
190 | }; | |
191 | ||
192 | /* hi3516CV300 sysctrl CRG */ | |
193 | #define HI3516CV300_SYSCTRL_NR_CLKS 16 | |
194 | ||
df934cbc | 195 | static const char *const wdt_mux_p[] __initconst = { "3m", "apb" }; |
c80dfd9b PW |
196 | static u32 wdt_mux_table[] = {0, 1}; |
197 | ||
198 | static const struct hisi_mux_clock hi3516cv300_sysctrl_mux_clks[] = { | |
199 | { HI3516CV300_WDT_CLK, "wdt", wdt_mux_p, ARRAY_SIZE(wdt_mux_p), | |
200 | CLK_SET_RATE_PARENT, 0x0, 23, 1, 0, wdt_mux_table, }, | |
201 | }; | |
202 | ||
203 | static struct hisi_clock_data *hi3516cv300_sysctrl_clk_register( | |
204 | struct platform_device *pdev) | |
205 | { | |
206 | struct hisi_clock_data *clk_data; | |
207 | int ret; | |
208 | ||
209 | clk_data = hisi_clk_alloc(pdev, HI3516CV300_SYSCTRL_NR_CLKS); | |
210 | if (!clk_data) | |
211 | return ERR_PTR(-ENOMEM); | |
212 | ||
213 | ret = hisi_clk_register_mux(hi3516cv300_sysctrl_mux_clks, | |
214 | ARRAY_SIZE(hi3516cv300_sysctrl_mux_clks), clk_data); | |
215 | if (ret) | |
216 | return ERR_PTR(ret); | |
217 | ||
218 | ||
219 | ret = of_clk_add_provider(pdev->dev.of_node, | |
220 | of_clk_src_onecell_get, &clk_data->clk_data); | |
221 | if (ret) | |
222 | goto unregister_mux; | |
223 | ||
224 | return clk_data; | |
225 | ||
226 | unregister_mux: | |
227 | hisi_clk_unregister_mux(hi3516cv300_sysctrl_mux_clks, | |
228 | ARRAY_SIZE(hi3516cv300_sysctrl_mux_clks), clk_data); | |
229 | return ERR_PTR(ret); | |
230 | } | |
231 | ||
232 | static void hi3516cv300_sysctrl_clk_unregister(struct platform_device *pdev) | |
233 | { | |
234 | struct hisi_crg_dev *crg = platform_get_drvdata(pdev); | |
235 | ||
236 | of_clk_del_provider(pdev->dev.of_node); | |
237 | ||
238 | hisi_clk_unregister_mux(hi3516cv300_sysctrl_mux_clks, | |
239 | ARRAY_SIZE(hi3516cv300_sysctrl_mux_clks), | |
240 | crg->clk_data); | |
241 | } | |
242 | ||
243 | static const struct hisi_crg_funcs hi3516cv300_sysctrl_funcs = { | |
244 | .register_clks = hi3516cv300_sysctrl_clk_register, | |
245 | .unregister_clks = hi3516cv300_sysctrl_clk_unregister, | |
246 | }; | |
247 | ||
248 | static const struct of_device_id hi3516cv300_crg_match_table[] = { | |
249 | { | |
250 | .compatible = "hisilicon,hi3516cv300-crg", | |
251 | .data = &hi3516cv300_crg_funcs | |
252 | }, | |
253 | { | |
254 | .compatible = "hisilicon,hi3516cv300-sysctrl", | |
255 | .data = &hi3516cv300_sysctrl_funcs | |
256 | }, | |
257 | { } | |
258 | }; | |
259 | MODULE_DEVICE_TABLE(of, hi3516cv300_crg_match_table); | |
260 | ||
261 | static int hi3516cv300_crg_probe(struct platform_device *pdev) | |
262 | { | |
263 | struct hisi_crg_dev *crg; | |
264 | ||
265 | crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL); | |
266 | if (!crg) | |
267 | return -ENOMEM; | |
268 | ||
269 | crg->funcs = of_device_get_match_data(&pdev->dev); | |
270 | if (!crg->funcs) | |
271 | return -ENOENT; | |
272 | ||
273 | crg->rstc = hisi_reset_init(pdev); | |
274 | if (!crg->rstc) | |
275 | return -ENOMEM; | |
276 | ||
277 | crg->clk_data = crg->funcs->register_clks(pdev); | |
278 | if (IS_ERR(crg->clk_data)) { | |
279 | hisi_reset_exit(crg->rstc); | |
280 | return PTR_ERR(crg->clk_data); | |
281 | } | |
282 | ||
283 | platform_set_drvdata(pdev, crg); | |
284 | return 0; | |
285 | } | |
286 | ||
287 | static int hi3516cv300_crg_remove(struct platform_device *pdev) | |
288 | { | |
289 | struct hisi_crg_dev *crg = platform_get_drvdata(pdev); | |
290 | ||
291 | hisi_reset_exit(crg->rstc); | |
292 | crg->funcs->unregister_clks(pdev); | |
293 | return 0; | |
294 | } | |
295 | ||
296 | static struct platform_driver hi3516cv300_crg_driver = { | |
297 | .probe = hi3516cv300_crg_probe, | |
298 | .remove = hi3516cv300_crg_remove, | |
299 | .driver = { | |
300 | .name = "hi3516cv300-crg", | |
301 | .of_match_table = hi3516cv300_crg_match_table, | |
302 | }, | |
303 | }; | |
304 | ||
305 | static int __init hi3516cv300_crg_init(void) | |
306 | { | |
307 | return platform_driver_register(&hi3516cv300_crg_driver); | |
308 | } | |
309 | core_initcall(hi3516cv300_crg_init); | |
310 | ||
311 | static void __exit hi3516cv300_crg_exit(void) | |
312 | { | |
313 | platform_driver_unregister(&hi3516cv300_crg_driver); | |
314 | } | |
315 | module_exit(hi3516cv300_crg_exit); | |
316 | ||
317 | MODULE_LICENSE("GPL v2"); | |
318 | MODULE_DESCRIPTION("HiSilicon Hi3516CV300 CRG Driver"); |