GNU Linux-libre 5.15.54-gnu
[releases.git] / drivers / clk / sunxi-ng / ccu-sun8i-de2.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io>
4  */
5
6 #include <linux/clk.h>
7 #include <linux/clk-provider.h>
8 #include <linux/of_address.h>
9 #include <linux/of_platform.h>
10 #include <linux/platform_device.h>
11 #include <linux/reset.h>
12
13 #include "ccu_common.h"
14 #include "ccu_div.h"
15 #include "ccu_gate.h"
16 #include "ccu_reset.h"
17
18 #include "ccu-sun8i-de2.h"
19
20 static SUNXI_CCU_GATE(bus_mixer0_clk,   "bus-mixer0",   "bus-de",
21                       0x04, BIT(0), 0);
22 static SUNXI_CCU_GATE(bus_mixer1_clk,   "bus-mixer1",   "bus-de",
23                       0x04, BIT(1), 0);
24 static SUNXI_CCU_GATE(bus_wb_clk,       "bus-wb",       "bus-de",
25                       0x04, BIT(2), 0);
26 static SUNXI_CCU_GATE(bus_rot_clk,      "bus-rot",      "bus-de",
27                       0x04, BIT(3), 0);
28
29 static SUNXI_CCU_GATE(mixer0_clk,       "mixer0",       "mixer0-div",
30                       0x00, BIT(0), CLK_SET_RATE_PARENT);
31 static SUNXI_CCU_GATE(mixer1_clk,       "mixer1",       "mixer1-div",
32                       0x00, BIT(1), CLK_SET_RATE_PARENT);
33 static SUNXI_CCU_GATE(wb_clk,           "wb",           "wb-div",
34                       0x00, BIT(2), CLK_SET_RATE_PARENT);
35 static SUNXI_CCU_GATE(rot_clk,          "rot",          "rot-div",
36                       0x00, BIT(3), CLK_SET_RATE_PARENT);
37
38 static SUNXI_CCU_M(mixer0_div_clk, "mixer0-div", "de", 0x0c, 0, 4,
39                    CLK_SET_RATE_PARENT);
40 static SUNXI_CCU_M(mixer1_div_clk, "mixer1-div", "de", 0x0c, 4, 4,
41                    CLK_SET_RATE_PARENT);
42 static SUNXI_CCU_M(wb_div_clk, "wb-div", "de", 0x0c, 8, 4,
43                    CLK_SET_RATE_PARENT);
44 static SUNXI_CCU_M(rot_div_clk, "rot-div", "de", 0x0c, 0x0c, 4,
45                    CLK_SET_RATE_PARENT);
46
47 static SUNXI_CCU_M(mixer0_div_a83_clk, "mixer0-div", "pll-de", 0x0c, 0, 4,
48                    CLK_SET_RATE_PARENT);
49 static SUNXI_CCU_M(mixer1_div_a83_clk, "mixer1-div", "pll-de", 0x0c, 4, 4,
50                    CLK_SET_RATE_PARENT);
51 static SUNXI_CCU_M(wb_div_a83_clk, "wb-div", "pll-de", 0x0c, 8, 4,
52                    CLK_SET_RATE_PARENT);
53 static SUNXI_CCU_M(rot_div_a83_clk, "rot-div", "pll-de", 0x0c, 0x0c, 4,
54                    CLK_SET_RATE_PARENT);
55
56 static struct ccu_common *sun8i_a83t_de2_clks[] = {
57         &mixer0_clk.common,
58         &mixer1_clk.common,
59         &wb_clk.common,
60
61         &bus_mixer0_clk.common,
62         &bus_mixer1_clk.common,
63         &bus_wb_clk.common,
64
65         &mixer0_div_a83_clk.common,
66         &mixer1_div_a83_clk.common,
67         &wb_div_a83_clk.common,
68
69         &bus_rot_clk.common,
70         &rot_clk.common,
71         &rot_div_a83_clk.common,
72 };
73
74 static struct ccu_common *sun8i_h3_de2_clks[] = {
75         &mixer0_clk.common,
76         &mixer1_clk.common,
77         &wb_clk.common,
78
79         &bus_mixer0_clk.common,
80         &bus_mixer1_clk.common,
81         &bus_wb_clk.common,
82
83         &mixer0_div_clk.common,
84         &mixer1_div_clk.common,
85         &wb_div_clk.common,
86 };
87
88 static struct ccu_common *sun8i_v3s_de2_clks[] = {
89         &mixer0_clk.common,
90         &wb_clk.common,
91
92         &bus_mixer0_clk.common,
93         &bus_wb_clk.common,
94
95         &mixer0_div_clk.common,
96         &wb_div_clk.common,
97 };
98
99 static struct ccu_common *sun50i_a64_de2_clks[] = {
100         &mixer0_clk.common,
101         &mixer1_clk.common,
102         &wb_clk.common,
103
104         &bus_mixer0_clk.common,
105         &bus_mixer1_clk.common,
106         &bus_wb_clk.common,
107
108         &mixer0_div_clk.common,
109         &mixer1_div_clk.common,
110         &wb_div_clk.common,
111
112         &bus_rot_clk.common,
113         &rot_clk.common,
114         &rot_div_clk.common,
115 };
116
117 static struct clk_hw_onecell_data sun8i_a83t_de2_hw_clks = {
118         .hws    = {
119                 [CLK_MIXER0]            = &mixer0_clk.common.hw,
120                 [CLK_MIXER1]            = &mixer1_clk.common.hw,
121                 [CLK_WB]                = &wb_clk.common.hw,
122                 [CLK_ROT]               = &rot_clk.common.hw,
123
124                 [CLK_BUS_MIXER0]        = &bus_mixer0_clk.common.hw,
125                 [CLK_BUS_MIXER1]        = &bus_mixer1_clk.common.hw,
126                 [CLK_BUS_WB]            = &bus_wb_clk.common.hw,
127                 [CLK_BUS_ROT]           = &bus_rot_clk.common.hw,
128
129                 [CLK_MIXER0_DIV]        = &mixer0_div_a83_clk.common.hw,
130                 [CLK_MIXER1_DIV]        = &mixer1_div_a83_clk.common.hw,
131                 [CLK_WB_DIV]            = &wb_div_a83_clk.common.hw,
132                 [CLK_ROT_DIV]           = &rot_div_a83_clk.common.hw,
133         },
134         .num    = CLK_NUMBER_WITH_ROT,
135 };
136
137 static struct clk_hw_onecell_data sun8i_h3_de2_hw_clks = {
138         .hws    = {
139                 [CLK_MIXER0]            = &mixer0_clk.common.hw,
140                 [CLK_MIXER1]            = &mixer1_clk.common.hw,
141                 [CLK_WB]                = &wb_clk.common.hw,
142
143                 [CLK_BUS_MIXER0]        = &bus_mixer0_clk.common.hw,
144                 [CLK_BUS_MIXER1]        = &bus_mixer1_clk.common.hw,
145                 [CLK_BUS_WB]            = &bus_wb_clk.common.hw,
146
147                 [CLK_MIXER0_DIV]        = &mixer0_div_clk.common.hw,
148                 [CLK_MIXER1_DIV]        = &mixer1_div_clk.common.hw,
149                 [CLK_WB_DIV]            = &wb_div_clk.common.hw,
150         },
151         .num    = CLK_NUMBER_WITHOUT_ROT,
152 };
153
154 static struct clk_hw_onecell_data sun8i_v3s_de2_hw_clks = {
155         .hws    = {
156                 [CLK_MIXER0]            = &mixer0_clk.common.hw,
157                 [CLK_WB]                = &wb_clk.common.hw,
158
159                 [CLK_BUS_MIXER0]        = &bus_mixer0_clk.common.hw,
160                 [CLK_BUS_WB]            = &bus_wb_clk.common.hw,
161
162                 [CLK_MIXER0_DIV]        = &mixer0_div_clk.common.hw,
163                 [CLK_WB_DIV]            = &wb_div_clk.common.hw,
164         },
165         .num    = CLK_NUMBER_WITHOUT_ROT,
166 };
167
168 static struct clk_hw_onecell_data sun50i_a64_de2_hw_clks = {
169         .hws    = {
170                 [CLK_MIXER0]            = &mixer0_clk.common.hw,
171                 [CLK_MIXER1]            = &mixer1_clk.common.hw,
172                 [CLK_WB]                = &wb_clk.common.hw,
173                 [CLK_ROT]               = &rot_clk.common.hw,
174
175                 [CLK_BUS_MIXER0]        = &bus_mixer0_clk.common.hw,
176                 [CLK_BUS_MIXER1]        = &bus_mixer1_clk.common.hw,
177                 [CLK_BUS_WB]            = &bus_wb_clk.common.hw,
178                 [CLK_BUS_ROT]           = &bus_rot_clk.common.hw,
179
180                 [CLK_MIXER0_DIV]        = &mixer0_div_clk.common.hw,
181                 [CLK_MIXER1_DIV]        = &mixer1_div_clk.common.hw,
182                 [CLK_WB_DIV]            = &wb_div_clk.common.hw,
183                 [CLK_ROT_DIV]           = &rot_div_clk.common.hw,
184         },
185         .num    = CLK_NUMBER_WITH_ROT,
186 };
187
188 static struct ccu_reset_map sun8i_a83t_de2_resets[] = {
189         [RST_MIXER0]    = { 0x08, BIT(0) },
190         /*
191          * Mixer1 reset line is shared with wb, so only RST_WB is
192          * exported here.
193          */
194         [RST_WB]        = { 0x08, BIT(2) },
195         [RST_ROT]       = { 0x08, BIT(3) },
196 };
197
198 static struct ccu_reset_map sun8i_h3_de2_resets[] = {
199         [RST_MIXER0]    = { 0x08, BIT(0) },
200         /*
201          * Mixer1 reset line is shared with wb, so only RST_WB is
202          * exported here.
203          * V3s doesn't have mixer1, so it also shares this struct.
204          */
205         [RST_WB]        = { 0x08, BIT(2) },
206 };
207
208 static struct ccu_reset_map sun50i_a64_de2_resets[] = {
209         [RST_MIXER0]    = { 0x08, BIT(0) },
210         [RST_MIXER1]    = { 0x08, BIT(1) },
211         [RST_WB]        = { 0x08, BIT(2) },
212         [RST_ROT]       = { 0x08, BIT(3) },
213 };
214
215 static struct ccu_reset_map sun50i_h5_de2_resets[] = {
216         [RST_MIXER0]    = { 0x08, BIT(0) },
217         [RST_MIXER1]    = { 0x08, BIT(1) },
218         [RST_WB]        = { 0x08, BIT(2) },
219 };
220
221 static const struct sunxi_ccu_desc sun8i_a83t_de2_clk_desc = {
222         .ccu_clks       = sun8i_a83t_de2_clks,
223         .num_ccu_clks   = ARRAY_SIZE(sun8i_a83t_de2_clks),
224
225         .hw_clks        = &sun8i_a83t_de2_hw_clks,
226
227         .resets         = sun8i_a83t_de2_resets,
228         .num_resets     = ARRAY_SIZE(sun8i_a83t_de2_resets),
229 };
230
231 static const struct sunxi_ccu_desc sun8i_h3_de2_clk_desc = {
232         .ccu_clks       = sun8i_h3_de2_clks,
233         .num_ccu_clks   = ARRAY_SIZE(sun8i_h3_de2_clks),
234
235         .hw_clks        = &sun8i_h3_de2_hw_clks,
236
237         .resets         = sun8i_h3_de2_resets,
238         .num_resets     = ARRAY_SIZE(sun8i_h3_de2_resets),
239 };
240
241 static const struct sunxi_ccu_desc sun8i_r40_de2_clk_desc = {
242         .ccu_clks       = sun50i_a64_de2_clks,
243         .num_ccu_clks   = ARRAY_SIZE(sun50i_a64_de2_clks),
244
245         .hw_clks        = &sun50i_a64_de2_hw_clks,
246
247         .resets         = sun8i_a83t_de2_resets,
248         .num_resets     = ARRAY_SIZE(sun8i_a83t_de2_resets),
249 };
250
251 static const struct sunxi_ccu_desc sun8i_v3s_de2_clk_desc = {
252         .ccu_clks       = sun8i_v3s_de2_clks,
253         .num_ccu_clks   = ARRAY_SIZE(sun8i_v3s_de2_clks),
254
255         .hw_clks        = &sun8i_v3s_de2_hw_clks,
256
257         .resets         = sun8i_a83t_de2_resets,
258         .num_resets     = ARRAY_SIZE(sun8i_a83t_de2_resets),
259 };
260
261 static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = {
262         .ccu_clks       = sun50i_a64_de2_clks,
263         .num_ccu_clks   = ARRAY_SIZE(sun50i_a64_de2_clks),
264
265         .hw_clks        = &sun50i_a64_de2_hw_clks,
266
267         .resets         = sun50i_a64_de2_resets,
268         .num_resets     = ARRAY_SIZE(sun50i_a64_de2_resets),
269 };
270
271 static const struct sunxi_ccu_desc sun50i_h5_de2_clk_desc = {
272         .ccu_clks       = sun8i_h3_de2_clks,
273         .num_ccu_clks   = ARRAY_SIZE(sun8i_h3_de2_clks),
274
275         .hw_clks        = &sun8i_h3_de2_hw_clks,
276
277         .resets         = sun50i_h5_de2_resets,
278         .num_resets     = ARRAY_SIZE(sun50i_h5_de2_resets),
279 };
280
281 static int sunxi_de2_clk_probe(struct platform_device *pdev)
282 {
283         struct resource *res;
284         struct clk *bus_clk, *mod_clk;
285         struct reset_control *rstc;
286         void __iomem *reg;
287         const struct sunxi_ccu_desc *ccu_desc;
288         int ret;
289
290         ccu_desc = of_device_get_match_data(&pdev->dev);
291         if (!ccu_desc)
292                 return -EINVAL;
293
294         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
295         reg = devm_ioremap_resource(&pdev->dev, res);
296         if (IS_ERR(reg))
297                 return PTR_ERR(reg);
298
299         bus_clk = devm_clk_get(&pdev->dev, "bus");
300         if (IS_ERR(bus_clk)) {
301                 ret = PTR_ERR(bus_clk);
302                 if (ret != -EPROBE_DEFER)
303                         dev_err(&pdev->dev, "Couldn't get bus clk: %d\n", ret);
304                 return ret;
305         }
306
307         mod_clk = devm_clk_get(&pdev->dev, "mod");
308         if (IS_ERR(mod_clk)) {
309                 ret = PTR_ERR(mod_clk);
310                 if (ret != -EPROBE_DEFER)
311                         dev_err(&pdev->dev, "Couldn't get mod clk: %d\n", ret);
312                 return ret;
313         }
314
315         rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
316         if (IS_ERR(rstc)) {
317                 ret = PTR_ERR(rstc);
318                 if (ret != -EPROBE_DEFER)
319                         dev_err(&pdev->dev,
320                                 "Couldn't get reset control: %d\n", ret);
321                 return ret;
322         }
323
324         /* The clocks need to be enabled for us to access the registers */
325         ret = clk_prepare_enable(bus_clk);
326         if (ret) {
327                 dev_err(&pdev->dev, "Couldn't enable bus clk: %d\n", ret);
328                 return ret;
329         }
330
331         ret = clk_prepare_enable(mod_clk);
332         if (ret) {
333                 dev_err(&pdev->dev, "Couldn't enable mod clk: %d\n", ret);
334                 goto err_disable_bus_clk;
335         }
336
337         /* The reset control needs to be asserted for the controls to work */
338         ret = reset_control_deassert(rstc);
339         if (ret) {
340                 dev_err(&pdev->dev,
341                         "Couldn't deassert reset control: %d\n", ret);
342                 goto err_disable_mod_clk;
343         }
344
345         ret = devm_sunxi_ccu_probe(&pdev->dev, reg, ccu_desc);
346         if (ret)
347                 goto err_assert_reset;
348
349         return 0;
350
351 err_assert_reset:
352         reset_control_assert(rstc);
353 err_disable_mod_clk:
354         clk_disable_unprepare(mod_clk);
355 err_disable_bus_clk:
356         clk_disable_unprepare(bus_clk);
357         return ret;
358 }
359
360 static const struct of_device_id sunxi_de2_clk_ids[] = {
361         {
362                 .compatible = "allwinner,sun8i-a83t-de2-clk",
363                 .data = &sun8i_a83t_de2_clk_desc,
364         },
365         {
366                 .compatible = "allwinner,sun8i-h3-de2-clk",
367                 .data = &sun8i_h3_de2_clk_desc,
368         },
369         {
370                 .compatible = "allwinner,sun8i-r40-de2-clk",
371                 .data = &sun8i_r40_de2_clk_desc,
372         },
373         {
374                 .compatible = "allwinner,sun8i-v3s-de2-clk",
375                 .data = &sun8i_v3s_de2_clk_desc,
376         },
377         {
378                 .compatible = "allwinner,sun50i-a64-de2-clk",
379                 .data = &sun50i_a64_de2_clk_desc,
380         },
381         {
382                 .compatible = "allwinner,sun50i-h5-de2-clk",
383                 .data = &sun50i_h5_de2_clk_desc,
384         },
385         {
386                 .compatible = "allwinner,sun50i-h6-de3-clk",
387                 .data = &sun50i_h5_de2_clk_desc,
388         },
389         { }
390 };
391
392 static struct platform_driver sunxi_de2_clk_driver = {
393         .probe  = sunxi_de2_clk_probe,
394         .driver = {
395                 .name   = "sunxi-de2-clks",
396                 .of_match_table = sunxi_de2_clk_ids,
397         },
398 };
399 builtin_platform_driver(sunxi_de2_clk_driver);