1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #include <linux/clk-provider.h> |
4 | #include <linux/init.h> |
5 | #include <linux/of.h> |
6 | #include <linux/platform_device.h> |
7 | |
8 | #include <dt-bindings/clock/bcm3368-clock.h> |
9 | #include <dt-bindings/clock/bcm6318-clock.h> |
10 | #include <dt-bindings/clock/bcm6328-clock.h> |
11 | #include <dt-bindings/clock/bcm6358-clock.h> |
12 | #include <dt-bindings/clock/bcm6362-clock.h> |
13 | #include <dt-bindings/clock/bcm6368-clock.h> |
14 | #include <dt-bindings/clock/bcm63268-clock.h> |
15 | |
16 | struct clk_bcm63xx_table_entry { |
17 | const char * const name; |
18 | u8 bit; |
19 | unsigned long flags; |
20 | }; |
21 | |
22 | struct clk_bcm63xx_hw { |
23 | void __iomem *regs; |
24 | spinlock_t lock; |
25 | |
26 | struct clk_hw_onecell_data data; |
27 | }; |
28 | |
29 | static const struct clk_bcm63xx_table_entry bcm3368_clocks[] = { |
30 | { |
31 | .name = "mac" , |
32 | .bit = BCM3368_CLK_MAC, |
33 | }, { |
34 | .name = "tc" , |
35 | .bit = BCM3368_CLK_TC, |
36 | }, { |
37 | .name = "us_top" , |
38 | .bit = BCM3368_CLK_US_TOP, |
39 | }, { |
40 | .name = "ds_top" , |
41 | .bit = BCM3368_CLK_DS_TOP, |
42 | }, { |
43 | .name = "acm" , |
44 | .bit = BCM3368_CLK_ACM, |
45 | }, { |
46 | .name = "spi" , |
47 | .bit = BCM3368_CLK_SPI, |
48 | }, { |
49 | .name = "usbs" , |
50 | .bit = BCM3368_CLK_USBS, |
51 | }, { |
52 | .name = "bmu" , |
53 | .bit = BCM3368_CLK_BMU, |
54 | }, { |
55 | .name = "pcm" , |
56 | .bit = BCM3368_CLK_PCM, |
57 | }, { |
58 | .name = "ntp" , |
59 | .bit = BCM3368_CLK_NTP, |
60 | }, { |
61 | .name = "acp_b" , |
62 | .bit = BCM3368_CLK_ACP_B, |
63 | }, { |
64 | .name = "acp_a" , |
65 | .bit = BCM3368_CLK_ACP_A, |
66 | }, { |
67 | .name = "emusb" , |
68 | .bit = BCM3368_CLK_EMUSB, |
69 | }, { |
70 | .name = "enet0" , |
71 | .bit = BCM3368_CLK_ENET0, |
72 | }, { |
73 | .name = "enet1" , |
74 | .bit = BCM3368_CLK_ENET1, |
75 | }, { |
76 | .name = "usbsu" , |
77 | .bit = BCM3368_CLK_USBSU, |
78 | }, { |
79 | .name = "ephy" , |
80 | .bit = BCM3368_CLK_EPHY, |
81 | }, { |
82 | /* sentinel */ |
83 | }, |
84 | }; |
85 | |
86 | static const struct clk_bcm63xx_table_entry bcm6318_clocks[] = { |
87 | { |
88 | .name = "adsl_asb" , |
89 | .bit = BCM6318_CLK_ADSL_ASB, |
90 | }, { |
91 | .name = "usb_asb" , |
92 | .bit = BCM6318_CLK_USB_ASB, |
93 | }, { |
94 | .name = "mips_asb" , |
95 | .bit = BCM6318_CLK_MIPS_ASB, |
96 | }, { |
97 | .name = "pcie_asb" , |
98 | .bit = BCM6318_CLK_PCIE_ASB, |
99 | }, { |
100 | .name = "phymips_asb" , |
101 | .bit = BCM6318_CLK_PHYMIPS_ASB, |
102 | }, { |
103 | .name = "robosw_asb" , |
104 | .bit = BCM6318_CLK_ROBOSW_ASB, |
105 | }, { |
106 | .name = "sar_asb" , |
107 | .bit = BCM6318_CLK_SAR_ASB, |
108 | }, { |
109 | .name = "sdr_asb" , |
110 | .bit = BCM6318_CLK_SDR_ASB, |
111 | }, { |
112 | .name = "swreg_asb" , |
113 | .bit = BCM6318_CLK_SWREG_ASB, |
114 | }, { |
115 | .name = "periph_asb" , |
116 | .bit = BCM6318_CLK_PERIPH_ASB, |
117 | }, { |
118 | .name = "cpubus160" , |
119 | .bit = BCM6318_CLK_CPUBUS160, |
120 | }, { |
121 | .name = "adsl" , |
122 | .bit = BCM6318_CLK_ADSL, |
123 | }, { |
124 | .name = "sar125" , |
125 | .bit = BCM6318_CLK_SAR125, |
126 | }, { |
127 | .name = "mips" , |
128 | .bit = BCM6318_CLK_MIPS, |
129 | .flags = CLK_IS_CRITICAL, |
130 | }, { |
131 | .name = "pcie" , |
132 | .bit = BCM6318_CLK_PCIE, |
133 | }, { |
134 | .name = "robosw250" , |
135 | .bit = BCM6318_CLK_ROBOSW250, |
136 | }, { |
137 | .name = "robosw025" , |
138 | .bit = BCM6318_CLK_ROBOSW025, |
139 | }, { |
140 | .name = "sdr" , |
141 | .bit = BCM6318_CLK_SDR, |
142 | .flags = CLK_IS_CRITICAL, |
143 | }, { |
144 | .name = "usbd" , |
145 | .bit = BCM6318_CLK_USBD, |
146 | }, { |
147 | .name = "hsspi" , |
148 | .bit = BCM6318_CLK_HSSPI, |
149 | }, { |
150 | .name = "pcie25" , |
151 | .bit = BCM6318_CLK_PCIE25, |
152 | }, { |
153 | .name = "phymips" , |
154 | .bit = BCM6318_CLK_PHYMIPS, |
155 | }, { |
156 | .name = "afe" , |
157 | .bit = BCM6318_CLK_AFE, |
158 | }, { |
159 | .name = "qproc" , |
160 | .bit = BCM6318_CLK_QPROC, |
161 | }, { |
162 | /* sentinel */ |
163 | }, |
164 | }; |
165 | |
166 | static const struct clk_bcm63xx_table_entry bcm6318_ubus_clocks[] = { |
167 | { |
168 | .name = "adsl-ubus" , |
169 | .bit = BCM6318_UCLK_ADSL, |
170 | }, { |
171 | .name = "arb-ubus" , |
172 | .bit = BCM6318_UCLK_ARB, |
173 | .flags = CLK_IS_CRITICAL, |
174 | }, { |
175 | .name = "mips-ubus" , |
176 | .bit = BCM6318_UCLK_MIPS, |
177 | .flags = CLK_IS_CRITICAL, |
178 | }, { |
179 | .name = "pcie-ubus" , |
180 | .bit = BCM6318_UCLK_PCIE, |
181 | }, { |
182 | .name = "periph-ubus" , |
183 | .bit = BCM6318_UCLK_PERIPH, |
184 | .flags = CLK_IS_CRITICAL, |
185 | }, { |
186 | .name = "phymips-ubus" , |
187 | .bit = BCM6318_UCLK_PHYMIPS, |
188 | }, { |
189 | .name = "robosw-ubus" , |
190 | .bit = BCM6318_UCLK_ROBOSW, |
191 | }, { |
192 | .name = "sar-ubus" , |
193 | .bit = BCM6318_UCLK_SAR, |
194 | }, { |
195 | .name = "sdr-ubus" , |
196 | .bit = BCM6318_UCLK_SDR, |
197 | }, { |
198 | .name = "usb-ubus" , |
199 | .bit = BCM6318_UCLK_USB, |
200 | }, { |
201 | /* sentinel */ |
202 | }, |
203 | }; |
204 | |
205 | static const struct clk_bcm63xx_table_entry bcm6328_clocks[] = { |
206 | { |
207 | .name = "phy_mips" , |
208 | .bit = BCM6328_CLK_PHYMIPS, |
209 | }, { |
210 | .name = "adsl_qproc" , |
211 | .bit = BCM6328_CLK_ADSL_QPROC, |
212 | }, { |
213 | .name = "adsl_afe" , |
214 | .bit = BCM6328_CLK_ADSL_AFE, |
215 | }, { |
216 | .name = "adsl" , |
217 | .bit = BCM6328_CLK_ADSL, |
218 | }, { |
219 | .name = "mips" , |
220 | .bit = BCM6328_CLK_MIPS, |
221 | .flags = CLK_IS_CRITICAL, |
222 | }, { |
223 | .name = "sar" , |
224 | .bit = BCM6328_CLK_SAR, |
225 | }, { |
226 | .name = "pcm" , |
227 | .bit = BCM6328_CLK_PCM, |
228 | }, { |
229 | .name = "usbd" , |
230 | .bit = BCM6328_CLK_USBD, |
231 | }, { |
232 | .name = "usbh" , |
233 | .bit = BCM6328_CLK_USBH, |
234 | }, { |
235 | .name = "hsspi" , |
236 | .bit = BCM6328_CLK_HSSPI, |
237 | }, { |
238 | .name = "pcie" , |
239 | .bit = BCM6328_CLK_PCIE, |
240 | }, { |
241 | .name = "robosw" , |
242 | .bit = BCM6328_CLK_ROBOSW, |
243 | }, { |
244 | /* sentinel */ |
245 | }, |
246 | }; |
247 | |
248 | static const struct clk_bcm63xx_table_entry bcm6358_clocks[] = { |
249 | { |
250 | .name = "enet" , |
251 | .bit = BCM6358_CLK_ENET, |
252 | }, { |
253 | .name = "adslphy" , |
254 | .bit = BCM6358_CLK_ADSLPHY, |
255 | }, { |
256 | .name = "pcm" , |
257 | .bit = BCM6358_CLK_PCM, |
258 | }, { |
259 | .name = "spi" , |
260 | .bit = BCM6358_CLK_SPI, |
261 | }, { |
262 | .name = "usbs" , |
263 | .bit = BCM6358_CLK_USBS, |
264 | }, { |
265 | .name = "sar" , |
266 | .bit = BCM6358_CLK_SAR, |
267 | }, { |
268 | .name = "emusb" , |
269 | .bit = BCM6358_CLK_EMUSB, |
270 | }, { |
271 | .name = "enet0" , |
272 | .bit = BCM6358_CLK_ENET0, |
273 | }, { |
274 | .name = "enet1" , |
275 | .bit = BCM6358_CLK_ENET1, |
276 | }, { |
277 | .name = "usbsu" , |
278 | .bit = BCM6358_CLK_USBSU, |
279 | }, { |
280 | .name = "ephy" , |
281 | .bit = BCM6358_CLK_EPHY, |
282 | }, { |
283 | /* sentinel */ |
284 | }, |
285 | }; |
286 | |
287 | static const struct clk_bcm63xx_table_entry bcm6362_clocks[] = { |
288 | { |
289 | .name = "adsl_qproc" , |
290 | .bit = BCM6362_CLK_ADSL_QPROC, |
291 | }, { |
292 | .name = "adsl_afe" , |
293 | .bit = BCM6362_CLK_ADSL_AFE, |
294 | }, { |
295 | .name = "adsl" , |
296 | .bit = BCM6362_CLK_ADSL, |
297 | }, { |
298 | .name = "mips" , |
299 | .bit = BCM6362_CLK_MIPS, |
300 | .flags = CLK_IS_CRITICAL, |
301 | }, { |
302 | .name = "wlan_ocp" , |
303 | .bit = BCM6362_CLK_WLAN_OCP, |
304 | }, { |
305 | .name = "swpkt_usb" , |
306 | .bit = BCM6362_CLK_SWPKT_USB, |
307 | }, { |
308 | .name = "swpkt_sar" , |
309 | .bit = BCM6362_CLK_SWPKT_SAR, |
310 | }, { |
311 | .name = "sar" , |
312 | .bit = BCM6362_CLK_SAR, |
313 | }, { |
314 | .name = "robosw" , |
315 | .bit = BCM6362_CLK_ROBOSW, |
316 | }, { |
317 | .name = "pcm" , |
318 | .bit = BCM6362_CLK_PCM, |
319 | }, { |
320 | .name = "usbd" , |
321 | .bit = BCM6362_CLK_USBD, |
322 | }, { |
323 | .name = "usbh" , |
324 | .bit = BCM6362_CLK_USBH, |
325 | }, { |
326 | .name = "ipsec" , |
327 | .bit = BCM6362_CLK_IPSEC, |
328 | }, { |
329 | .name = "spi" , |
330 | .bit = BCM6362_CLK_SPI, |
331 | }, { |
332 | .name = "hsspi" , |
333 | .bit = BCM6362_CLK_HSSPI, |
334 | }, { |
335 | .name = "pcie" , |
336 | .bit = BCM6362_CLK_PCIE, |
337 | }, { |
338 | .name = "fap" , |
339 | .bit = BCM6362_CLK_FAP, |
340 | }, { |
341 | .name = "phymips" , |
342 | .bit = BCM6362_CLK_PHYMIPS, |
343 | }, { |
344 | .name = "nand" , |
345 | .bit = BCM6362_CLK_NAND, |
346 | }, { |
347 | /* sentinel */ |
348 | }, |
349 | }; |
350 | |
351 | static const struct clk_bcm63xx_table_entry bcm6368_clocks[] = { |
352 | { |
353 | .name = "vdsl_qproc" , |
354 | .bit = BCM6368_CLK_VDSL_QPROC, |
355 | }, { |
356 | .name = "vdsl_afe" , |
357 | .bit = BCM6368_CLK_VDSL_AFE, |
358 | }, { |
359 | .name = "vdsl_bonding" , |
360 | .bit = BCM6368_CLK_VDSL_BONDING, |
361 | }, { |
362 | .name = "vdsl" , |
363 | .bit = BCM6368_CLK_VDSL, |
364 | }, { |
365 | .name = "phymips" , |
366 | .bit = BCM6368_CLK_PHYMIPS, |
367 | }, { |
368 | .name = "swpkt_usb" , |
369 | .bit = BCM6368_CLK_SWPKT_USB, |
370 | }, { |
371 | .name = "swpkt_sar" , |
372 | .bit = BCM6368_CLK_SWPKT_SAR, |
373 | }, { |
374 | .name = "spi" , |
375 | .bit = BCM6368_CLK_SPI, |
376 | }, { |
377 | .name = "usbd" , |
378 | .bit = BCM6368_CLK_USBD, |
379 | }, { |
380 | .name = "sar" , |
381 | .bit = BCM6368_CLK_SAR, |
382 | }, { |
383 | .name = "robosw" , |
384 | .bit = BCM6368_CLK_ROBOSW, |
385 | }, { |
386 | .name = "utopia" , |
387 | .bit = BCM6368_CLK_UTOPIA, |
388 | }, { |
389 | .name = "pcm" , |
390 | .bit = BCM6368_CLK_PCM, |
391 | }, { |
392 | .name = "usbh" , |
393 | .bit = BCM6368_CLK_USBH, |
394 | }, { |
395 | .name = "disable_gless" , |
396 | .bit = BCM6368_CLK_DIS_GLESS, |
397 | }, { |
398 | .name = "nand" , |
399 | .bit = BCM6368_CLK_NAND, |
400 | }, { |
401 | .name = "ipsec" , |
402 | .bit = BCM6368_CLK_IPSEC, |
403 | }, { |
404 | /* sentinel */ |
405 | }, |
406 | }; |
407 | |
408 | static const struct clk_bcm63xx_table_entry bcm63268_clocks[] = { |
409 | { |
410 | .name = "disable_gless" , |
411 | .bit = BCM63268_CLK_DIS_GLESS, |
412 | }, { |
413 | .name = "vdsl_qproc" , |
414 | .bit = BCM63268_CLK_VDSL_QPROC, |
415 | }, { |
416 | .name = "vdsl_afe" , |
417 | .bit = BCM63268_CLK_VDSL_AFE, |
418 | }, { |
419 | .name = "vdsl" , |
420 | .bit = BCM63268_CLK_VDSL, |
421 | }, { |
422 | .name = "mips" , |
423 | .bit = BCM63268_CLK_MIPS, |
424 | .flags = CLK_IS_CRITICAL, |
425 | }, { |
426 | .name = "wlan_ocp" , |
427 | .bit = BCM63268_CLK_WLAN_OCP, |
428 | }, { |
429 | .name = "dect" , |
430 | .bit = BCM63268_CLK_DECT, |
431 | }, { |
432 | .name = "fap0" , |
433 | .bit = BCM63268_CLK_FAP0, |
434 | }, { |
435 | .name = "fap1" , |
436 | .bit = BCM63268_CLK_FAP1, |
437 | }, { |
438 | .name = "sar" , |
439 | .bit = BCM63268_CLK_SAR, |
440 | }, { |
441 | .name = "robosw" , |
442 | .bit = BCM63268_CLK_ROBOSW, |
443 | }, { |
444 | .name = "pcm" , |
445 | .bit = BCM63268_CLK_PCM, |
446 | }, { |
447 | .name = "usbd" , |
448 | .bit = BCM63268_CLK_USBD, |
449 | }, { |
450 | .name = "usbh" , |
451 | .bit = BCM63268_CLK_USBH, |
452 | }, { |
453 | .name = "ipsec" , |
454 | .bit = BCM63268_CLK_IPSEC, |
455 | }, { |
456 | .name = "spi" , |
457 | .bit = BCM63268_CLK_SPI, |
458 | }, { |
459 | .name = "hsspi" , |
460 | .bit = BCM63268_CLK_HSSPI, |
461 | }, { |
462 | .name = "pcie" , |
463 | .bit = BCM63268_CLK_PCIE, |
464 | }, { |
465 | .name = "phymips" , |
466 | .bit = BCM63268_CLK_PHYMIPS, |
467 | }, { |
468 | .name = "gmac" , |
469 | .bit = BCM63268_CLK_GMAC, |
470 | }, { |
471 | .name = "nand" , |
472 | .bit = BCM63268_CLK_NAND, |
473 | }, { |
474 | .name = "tbus" , |
475 | .bit = BCM63268_CLK_TBUS, |
476 | }, { |
477 | .name = "robosw250" , |
478 | .bit = BCM63268_CLK_ROBOSW250, |
479 | }, { |
480 | /* sentinel */ |
481 | }, |
482 | }; |
483 | |
484 | static int clk_bcm63xx_probe(struct platform_device *pdev) |
485 | { |
486 | const struct clk_bcm63xx_table_entry *entry, *table; |
487 | struct clk_bcm63xx_hw *hw; |
488 | u8 maxbit = 0; |
489 | int i, ret; |
490 | |
491 | table = of_device_get_match_data(dev: &pdev->dev); |
492 | if (!table) |
493 | return -EINVAL; |
494 | |
495 | for (entry = table; entry->name; entry++) |
496 | maxbit = max_t(u8, maxbit, entry->bit); |
497 | maxbit++; |
498 | |
499 | hw = devm_kzalloc(dev: &pdev->dev, struct_size(hw, data.hws, maxbit), |
500 | GFP_KERNEL); |
501 | if (!hw) |
502 | return -ENOMEM; |
503 | |
504 | platform_set_drvdata(pdev, data: hw); |
505 | |
506 | spin_lock_init(&hw->lock); |
507 | |
508 | hw->data.num = maxbit; |
509 | for (i = 0; i < maxbit; i++) |
510 | hw->data.hws[i] = ERR_PTR(error: -ENODEV); |
511 | |
512 | hw->regs = devm_platform_ioremap_resource(pdev, index: 0); |
513 | if (IS_ERR(ptr: hw->regs)) |
514 | return PTR_ERR(ptr: hw->regs); |
515 | |
516 | for (entry = table; entry->name; entry++) { |
517 | struct clk_hw *clk; |
518 | |
519 | clk = clk_hw_register_gate(&pdev->dev, entry->name, NULL, |
520 | entry->flags, hw->regs, entry->bit, |
521 | CLK_GATE_BIG_ENDIAN, &hw->lock); |
522 | if (IS_ERR(ptr: clk)) { |
523 | ret = PTR_ERR(ptr: clk); |
524 | goto out_err; |
525 | } |
526 | |
527 | hw->data.hws[entry->bit] = clk; |
528 | } |
529 | |
530 | ret = of_clk_add_hw_provider(np: pdev->dev.of_node, get: of_clk_hw_onecell_get, |
531 | data: &hw->data); |
532 | if (!ret) |
533 | return 0; |
534 | out_err: |
535 | for (i = 0; i < hw->data.num; i++) { |
536 | if (!IS_ERR(ptr: hw->data.hws[i])) |
537 | clk_hw_unregister_gate(hw: hw->data.hws[i]); |
538 | } |
539 | |
540 | return ret; |
541 | } |
542 | |
543 | static void clk_bcm63xx_remove(struct platform_device *pdev) |
544 | { |
545 | struct clk_bcm63xx_hw *hw = platform_get_drvdata(pdev); |
546 | int i; |
547 | |
548 | of_clk_del_provider(np: pdev->dev.of_node); |
549 | |
550 | for (i = 0; i < hw->data.num; i++) { |
551 | if (!IS_ERR(ptr: hw->data.hws[i])) |
552 | clk_hw_unregister_gate(hw: hw->data.hws[i]); |
553 | } |
554 | } |
555 | |
556 | static const struct of_device_id clk_bcm63xx_dt_ids[] = { |
557 | { .compatible = "brcm,bcm3368-clocks" , .data = &bcm3368_clocks, }, |
558 | { .compatible = "brcm,bcm6318-clocks" , .data = &bcm6318_clocks, }, |
559 | { .compatible = "brcm,bcm6318-ubus-clocks" , .data = &bcm6318_ubus_clocks, }, |
560 | { .compatible = "brcm,bcm6328-clocks" , .data = &bcm6328_clocks, }, |
561 | { .compatible = "brcm,bcm6358-clocks" , .data = &bcm6358_clocks, }, |
562 | { .compatible = "brcm,bcm6362-clocks" , .data = &bcm6362_clocks, }, |
563 | { .compatible = "brcm,bcm6368-clocks" , .data = &bcm6368_clocks, }, |
564 | { .compatible = "brcm,bcm63268-clocks" , .data = &bcm63268_clocks, }, |
565 | { } |
566 | }; |
567 | |
568 | static struct platform_driver clk_bcm63xx = { |
569 | .probe = clk_bcm63xx_probe, |
570 | .remove_new = clk_bcm63xx_remove, |
571 | .driver = { |
572 | .name = "bcm63xx-clock" , |
573 | .of_match_table = clk_bcm63xx_dt_ids, |
574 | }, |
575 | }; |
576 | builtin_platform_driver(clk_bcm63xx); |
577 | |