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
16struct clk_bcm63xx_table_entry {
17 const char * const name;
18 u8 bit;
19 unsigned long flags;
20};
21
22struct clk_bcm63xx_hw {
23 void __iomem *regs;
24 spinlock_t lock;
25
26 struct clk_hw_onecell_data data;
27};
28
29static 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
86static 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
166static 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
205static 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
248static 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
287static 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
351static 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
408static 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
484static 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;
534out_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
543static 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
556static 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
568static 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};
576builtin_platform_driver(clk_bcm63xx);
577

source code of linux/drivers/clk/bcm/clk-bcm63xx-gate.c