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