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
17struct clk_bcm63xx_table_entry {
18	const char * const name;
19	u8 bit;
20	unsigned long flags;
21};
22
23struct clk_bcm63xx_hw {
24	void __iomem *regs;
25	spinlock_t lock;
26
27	struct clk_hw_onecell_data data;
28};
29
30static 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
87static 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
167static 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
206static 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
249static 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
288static 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
352static 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
409static 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
485static 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;
535out_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
544static 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
559static 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
571static 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};
579builtin_platform_driver(clk_bcm63xx);
580