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 
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 
544 static void 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 
557 static const struct of_device_id clk_bcm63xx_dt_ids[] = {
558 	{ .compatible = "brcm,bcm3368-clocks", .data = &bcm3368_clocks, },
559 	{ .compatible = "brcm,bcm6318-clocks", .data = &bcm6318_clocks, },
560 	{ .compatible = "brcm,bcm6318-ubus-clocks", .data = &bcm6318_ubus_clocks, },
561 	{ .compatible = "brcm,bcm6328-clocks", .data = &bcm6328_clocks, },
562 	{ .compatible = "brcm,bcm6358-clocks", .data = &bcm6358_clocks, },
563 	{ .compatible = "brcm,bcm6362-clocks", .data = &bcm6362_clocks, },
564 	{ .compatible = "brcm,bcm6368-clocks", .data = &bcm6368_clocks, },
565 	{ .compatible = "brcm,bcm63268-clocks", .data = &bcm63268_clocks, },
566 	{ }
567 };
568 
569 static struct platform_driver clk_bcm63xx = {
570 	.probe = clk_bcm63xx_probe,
571 	.remove_new = clk_bcm63xx_remove,
572 	.driver = {
573 		.name = "bcm63xx-clock",
574 		.of_match_table = clk_bcm63xx_dt_ids,
575 	},
576 };
577 builtin_platform_driver(clk_bcm63xx);
578