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(&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(&pdev->dev, struct_size(hw, data.hws, maxbit),
500			  GFP_KERNEL);
501	if (!hw)
502		return -ENOMEM;
503
504	platform_set_drvdata(pdev, 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(-ENODEV);
511
512	hw->regs = devm_platform_ioremap_resource(pdev, 0);
513	if (IS_ERR(hw->regs))
514		return PTR_ERR(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(clk)) {
523			ret = PTR_ERR(clk);
524			goto out_err;
525		}
526
527		hw->data.hws[entry->bit] = clk;
528	}
529
530	ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
531				     &hw->data);
532	if (!ret)
533		return 0;
534out_err:
535	for (i = 0; i < hw->data.num; i++) {
536		if (!IS_ERR(hw->data.hws[i]))
537			clk_hw_unregister_gate(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(pdev->dev.of_node);
549
550	for (i = 0; i < hw->data.num; i++) {
551		if (!IS_ERR(hw->data.hws[i]))
552			clk_hw_unregister_gate(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