File Index
Files and directories
Sign in
FILE

sckc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/at91/sckc.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * drivers/clk/at91/sckc.c
  4 *
  5 *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
  6 */
  7
  8#include <linux/clk-provider.h>
  9#include <linux/clkdev.h>
 10#include <linux/delay.h>
 11#include <linux/of.h>
 12#include <linux/of_address.h>
 13#include <linux/io.h>
 14
 15#include <dt-bindings/clock/at91.h>
 16
 17#define SLOW_CLOCK_FREQ		32768
 18#define SLOWCK_SW_CYCLES	5
 19#define SLOWCK_SW_TIME_USEC	((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
 20				 SLOW_CLOCK_FREQ)
 21
 22#define	AT91_SCKC_CR			0x00
 23
 24struct clk_slow_bits {
 25	u32 cr_rcen;
 26	u32 cr_osc32en;
 27	u32 cr_osc32byp;
 28	u32 cr_oscsel;
 29};
 30
 31struct clk_slow_osc {
 32	struct clk_hw hw;
 33	void __iomem *sckcr;
 34	const struct clk_slow_bits *bits;
 35	unsigned long startup_usec;
 36};
 37
 38#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
 39
 40struct clk_sama5d4_slow_osc {
 41	struct clk_hw hw;
 42	void __iomem *sckcr;
 43	const struct clk_slow_bits *bits;
 44	unsigned long startup_usec;
 45	bool prepared;
 46};
 47
 48#define to_clk_sama5d4_slow_osc(hw) container_of(hw, struct clk_sama5d4_slow_osc, hw)
 49
 50struct clk_slow_rc_osc {
 51	struct clk_hw hw;
 52	void __iomem *sckcr;
 53	const struct clk_slow_bits *bits;
 54	unsigned long frequency;
 55	unsigned long accuracy;
 56	unsigned long startup_usec;
 57};
 58
 59#define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
 60
 61struct clk_sam9x5_slow {
 62	struct clk_hw hw;
 63	void __iomem *sckcr;
 64	const struct clk_slow_bits *bits;
 65	u8 parent;
 66};
 67
 68#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
 69
 70static int clk_slow_osc_prepare(struct clk_hw *hw)
 71{
 72	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
 73	void __iomem *sckcr = osc->sckcr;
 74	u32 tmp = readl(sckcr);
 75
 76	if (tmp & (osc->bits->cr_osc32byp | osc->bits->cr_osc32en))
 77		return 0;
 78
 79	writel(tmp | osc->bits->cr_osc32en, sckcr);
 80
 81	if (system_state < SYSTEM_RUNNING)
 82		udelay(osc->startup_usec);
 83	else
 84		usleep_range(osc->startup_usec, osc->startup_usec + 1);
 85
 86	return 0;
 87}
 88
 89static void clk_slow_osc_unprepare(struct clk_hw *hw)
 90{
 91	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
 92	void __iomem *sckcr = osc->sckcr;
 93	u32 tmp = readl(sckcr);
 94
 95	if (tmp & osc->bits->cr_osc32byp)
 96		return;
 97
 98	writel(tmp & ~osc->bits->cr_osc32en, sckcr);
 99}
100
101static int clk_slow_osc_is_prepared(struct clk_hw *hw)
102{
103	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
104	void __iomem *sckcr = osc->sckcr;
105	u32 tmp = readl(sckcr);
106
107	if (tmp & osc->bits->cr_osc32byp)
108		return 1;
109
110	return !!(tmp & osc->bits->cr_osc32en);
111}
112
113static const struct clk_ops slow_osc_ops = {
114	.prepare = clk_slow_osc_prepare,
115	.unprepare = clk_slow_osc_unprepare,
116	.is_prepared = clk_slow_osc_is_prepared,
117};
118
119static struct clk_hw * __init
120at91_clk_register_slow_osc(void __iomem *sckcr,
121			   const char *name,
122			   const struct clk_parent_data *parent_data,
123			   unsigned long startup,
124			   bool bypass,
125			   const struct clk_slow_bits *bits)
126{
127	struct clk_slow_osc *osc;
128	struct clk_hw *hw;
129	struct clk_init_data init = {};
130	int ret;
131
132	if (!sckcr || !name || !parent_data)
133		return ERR_PTR(-EINVAL);
134
135	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
136	if (!osc)
137		return ERR_PTR(-ENOMEM);
138
139	init.name = name;
140	init.ops = &slow_osc_ops;
141	init.parent_data = parent_data;
142	init.num_parents = 1;
143	init.flags = CLK_IGNORE_UNUSED;
144
145	osc->hw.init = &init;
146	osc->sckcr = sckcr;
147	osc->startup_usec = startup;
148	osc->bits = bits;
149
150	if (bypass)
151		writel((readl(sckcr) & ~osc->bits->cr_osc32en) |
152					osc->bits->cr_osc32byp, sckcr);
153
154	hw = &osc->hw;
155	ret = clk_hw_register(NULL, &osc->hw);
156	if (ret) {
157		kfree(osc);
158		hw = ERR_PTR(ret);
159	}
160
161	return hw;
162}
163
164static void at91_clk_unregister_slow_osc(struct clk_hw *hw)
165{
166	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
167
168	clk_hw_unregister(hw);
169	kfree(osc);
170}
171
172static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
173						 unsigned long parent_rate)
174{
175	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
176
177	return osc->frequency;
178}
179
180static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
181						     unsigned long parent_acc)
182{
183	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
184
185	return osc->accuracy;
186}
187
188static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
189{
190	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
191	void __iomem *sckcr = osc->sckcr;
192
193	writel(readl(sckcr) | osc->bits->cr_rcen, sckcr);
194
195	if (system_state < SYSTEM_RUNNING)
196		udelay(osc->startup_usec);
197	else
198		usleep_range(osc->startup_usec, osc->startup_usec + 1);
199
200	return 0;
201}
202
203static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
204{
205	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
206	void __iomem *sckcr = osc->sckcr;
207
208	writel(readl(sckcr) & ~osc->bits->cr_rcen, sckcr);
209}
210
211static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
212{
213	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
214
215	return !!(readl(osc->sckcr) & osc->bits->cr_rcen);
216}
217
218static const struct clk_ops slow_rc_osc_ops = {
219	.prepare = clk_slow_rc_osc_prepare,
220	.unprepare = clk_slow_rc_osc_unprepare,
221	.is_prepared = clk_slow_rc_osc_is_prepared,
222	.recalc_rate = clk_slow_rc_osc_recalc_rate,
223	.recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
224};
225
226static struct clk_hw * __init
227at91_clk_register_slow_rc_osc(void __iomem *sckcr,
228			      const char *name,
229			      unsigned long frequency,
230			      unsigned long accuracy,
231			      unsigned long startup,
232			      const struct clk_slow_bits *bits)
233{
234	struct clk_slow_rc_osc *osc;
235	struct clk_hw *hw;
236	struct clk_init_data init;
237	int ret;
238
239	if (!sckcr || !name)
240		return ERR_PTR(-EINVAL);
241
242	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
243	if (!osc)
244		return ERR_PTR(-ENOMEM);
245
246	init.name = name;
247	init.ops = &slow_rc_osc_ops;
248	init.parent_names = NULL;
249	init.num_parents = 0;
250	init.flags = CLK_IGNORE_UNUSED;
251
252	osc->hw.init = &init;
253	osc->sckcr = sckcr;
254	osc->bits = bits;
255	osc->frequency = frequency;
256	osc->accuracy = accuracy;
257	osc->startup_usec = startup;
258
259	hw = &osc->hw;
260	ret = clk_hw_register(NULL, &osc->hw);
261	if (ret) {
262		kfree(osc);
263		hw = ERR_PTR(ret);
264	}
265
266	return hw;
267}
268
269static void at91_clk_unregister_slow_rc_osc(struct clk_hw *hw)
270{
271	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
272
273	clk_hw_unregister(hw);
274	kfree(osc);
275}
276
277static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
278{
279	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
280	void __iomem *sckcr = slowck->sckcr;
281	u32 tmp;
282
283	if (index > 1)
284		return -EINVAL;
285
286	tmp = readl(sckcr);
287
288	if ((!index && !(tmp & slowck->bits->cr_oscsel)) ||
289	    (index && (tmp & slowck->bits->cr_oscsel)))
290		return 0;
291
292	if (index)
293		tmp |= slowck->bits->cr_oscsel;
294	else
295		tmp &= ~slowck->bits->cr_oscsel;
296
297	writel(tmp, sckcr);
298
299	if (system_state < SYSTEM_RUNNING)
300		udelay(SLOWCK_SW_TIME_USEC);
301	else
302		usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
303
304	return 0;
305}
306
307static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
308{
309	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
310
311	return !!(readl(slowck->sckcr) & slowck->bits->cr_oscsel);
312}
313
314static const struct clk_ops sam9x5_slow_ops = {
315	.determine_rate = clk_hw_determine_rate_no_reparent,
316	.set_parent = clk_sam9x5_slow_set_parent,
317	.get_parent = clk_sam9x5_slow_get_parent,
318};
319
320static struct clk_hw * __init
321at91_clk_register_sam9x5_slow(void __iomem *sckcr,
322			      const char *name,
323			      const struct clk_hw **parent_hws,
324			      int num_parents,
325			      const struct clk_slow_bits *bits)
326{
327	struct clk_sam9x5_slow *slowck;
328	struct clk_hw *hw;
329	struct clk_init_data init = {};
330	int ret;
331
332	if (!sckcr || !name || !parent_hws || !num_parents)
333		return ERR_PTR(-EINVAL);
334
335	slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
336	if (!slowck)
337		return ERR_PTR(-ENOMEM);
338
339	init.name = name;
340	init.ops = &sam9x5_slow_ops;
341	init.parent_hws = parent_hws;
342	init.num_parents = num_parents;
343	init.flags = 0;
344
345	slowck->hw.init = &init;
346	slowck->sckcr = sckcr;
347	slowck->bits = bits;
348	slowck->parent = !!(readl(sckcr) & slowck->bits->cr_oscsel);
349
350	hw = &slowck->hw;
351	ret = clk_hw_register(NULL, &slowck->hw);
352	if (ret) {
353		kfree(slowck);
354		hw = ERR_PTR(ret);
355	}
356
357	return hw;
358}
359
360static void at91_clk_unregister_sam9x5_slow(struct clk_hw *hw)
361{
362	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
363
364	clk_hw_unregister(hw);
365	kfree(slowck);
366}
367
368static void __init at91sam9x5_sckc_register(struct device_node *np,
369					    unsigned int rc_osc_startup_us,
370					    const struct clk_slow_bits *bits)
371{
372	void __iomem *regbase = of_iomap(np, 0);
373	struct device_node *child = NULL;
374	const char *xtal_name;
375	struct clk_hw *slow_rc, *slow_osc, *slowck;
376	static struct clk_parent_data parent_data = {
377		.name = "slow_xtal",
378	};
379	const struct clk_hw *parent_hws[2];
380	bool bypass;
381	int ret;
382
383	if (!regbase)
384		return;
385
386	slow_rc = at91_clk_register_slow_rc_osc(regbase, "slow_rc_osc",
387						32768, 50000000,
388						rc_osc_startup_us, bits);
389	if (IS_ERR(slow_rc))
390		return;
391
392	xtal_name = of_clk_get_parent_name(np, 0);
393	if (!xtal_name) {
394		/* DT backward compatibility */
395		child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc");
396		if (!child)
397			goto unregister_slow_rc;
398
399		xtal_name = of_clk_get_parent_name(child, 0);
400		bypass = of_property_read_bool(child, "atmel,osc-bypass");
401
402		child =  of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow");
403	} else {
404		bypass = of_property_read_bool(np, "atmel,osc-bypass");
405	}
406
407	if (!xtal_name)
408		goto unregister_slow_rc;
409
410	parent_data.fw_name = xtal_name;
411
412	slow_osc = at91_clk_register_slow_osc(regbase, "slow_osc",
413					      &parent_data, 1200000, bypass, bits);
414	if (IS_ERR(slow_osc))
415		goto unregister_slow_rc;
416
417	parent_hws[0] = slow_rc;
418	parent_hws[1] = slow_osc;
419	slowck = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_hws,
420					       2, bits);
421	if (IS_ERR(slowck))
422		goto unregister_slow_osc;
423
424	/* DT backward compatibility */
425	if (child)
426		ret = of_clk_add_hw_provider(child, of_clk_hw_simple_get,
427					     slowck);
428	else
429		ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
430
431	if (WARN_ON(ret))
432		goto unregister_slowck;
433
434	return;
435
436unregister_slowck:
437	at91_clk_unregister_sam9x5_slow(slowck);
438unregister_slow_osc:
439	at91_clk_unregister_slow_osc(slow_osc);
440unregister_slow_rc:
441	at91_clk_unregister_slow_rc_osc(slow_rc);
442}
443
444static const struct clk_slow_bits at91sam9x5_bits = {
445	.cr_rcen = BIT(0),
446	.cr_osc32en = BIT(1),
447	.cr_osc32byp = BIT(2),
448	.cr_oscsel = BIT(3),
449};
450
451static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
452{
453	at91sam9x5_sckc_register(np, 75, &at91sam9x5_bits);
454}
455CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
456	       of_at91sam9x5_sckc_setup);
457
458static void __init of_sama5d3_sckc_setup(struct device_node *np)
459{
460	at91sam9x5_sckc_register(np, 500, &at91sam9x5_bits);
461}
462CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc",
463	       of_sama5d3_sckc_setup);
464
465static const struct clk_slow_bits at91sam9x60_bits = {
466	.cr_osc32en = BIT(1),
467	.cr_osc32byp = BIT(2),
468	.cr_oscsel = BIT(24),
469};
470
471static void __init of_sam9x60_sckc_setup(struct device_node *np)
472{
473	void __iomem *regbase = of_iomap(np, 0);
474	struct clk_hw_onecell_data *clk_data;
475	struct clk_hw *slow_rc, *slow_osc, *hw;
476	const char *xtal_name;
477	const struct clk_hw *parent_hws[2];
478	static struct clk_parent_data parent_data = {
479		.name = "slow_xtal",
480	};
481	bool bypass;
482	int ret;
483
484	if (!regbase)
485		return;
486
487	slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL, "slow_rc_osc",
488							   NULL, 0, 32768,
489							   93750000);
490	if (IS_ERR(slow_rc))
491		return;
492
493	xtal_name = of_clk_get_parent_name(np, 0);
494	if (!xtal_name)
495		goto unregister_slow_rc;
496
497	parent_data.fw_name = xtal_name;
498	bypass = of_property_read_bool(np, "atmel,osc-bypass");
499	slow_osc = at91_clk_register_slow_osc(regbase, "slow_osc",
500					      &parent_data, 5000000, bypass,
501					      &at91sam9x60_bits);
502	if (IS_ERR(slow_osc))
503		goto unregister_slow_rc;
504
505	clk_data = kzalloc(struct_size(clk_data, hws, 2), GFP_KERNEL);
506	if (!clk_data)
507		goto unregister_slow_osc;
508
509	/* MD_SLCK and TD_SLCK. */
510	clk_data->num = 2;
511	hw = clk_hw_register_fixed_rate_parent_hw(NULL, "md_slck", slow_rc,
512						  0, 32768);
513	if (IS_ERR(hw))
514		goto clk_data_free;
515	clk_data->hws[SCKC_MD_SLCK] = hw;
516
517	parent_hws[0] = slow_rc;
518	parent_hws[1] = slow_osc;
519	hw = at91_clk_register_sam9x5_slow(regbase, "td_slck", parent_hws,
520					   2, &at91sam9x60_bits);
521	if (IS_ERR(hw))
522		goto unregister_md_slck;
523	clk_data->hws[SCKC_TD_SLCK] = hw;
524
525	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
526	if (WARN_ON(ret))
527		goto unregister_td_slck;
528
529	return;
530
531unregister_td_slck:
532	at91_clk_unregister_sam9x5_slow(clk_data->hws[SCKC_TD_SLCK]);
533unregister_md_slck:
534	clk_hw_unregister(clk_data->hws[SCKC_MD_SLCK]);
535clk_data_free:
536	kfree(clk_data);
537unregister_slow_osc:
538	at91_clk_unregister_slow_osc(slow_osc);
539unregister_slow_rc:
540	clk_hw_unregister(slow_rc);
541}
542CLK_OF_DECLARE(sam9x60_clk_sckc, "microchip,sam9x60-sckc",
543	       of_sam9x60_sckc_setup);
544
545static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
546{
547	struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
548
549	if (osc->prepared)
550		return 0;
551
552	/*
553	 * Assume that if it has already been selected (for example by the
554	 * bootloader), enough time has already passed.
555	 */
556	if ((readl(osc->sckcr) & osc->bits->cr_oscsel)) {
557		osc->prepared = true;
558		return 0;
559	}
560
561	if (system_state < SYSTEM_RUNNING)
562		udelay(osc->startup_usec);
563	else
564		usleep_range(osc->startup_usec, osc->startup_usec + 1);
565	osc->prepared = true;
566
567	return 0;
568}
569
570static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw *hw)
571{
572	struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
573
574	return osc->prepared;
575}
576
577static const struct clk_ops sama5d4_slow_osc_ops = {
578	.prepare = clk_sama5d4_slow_osc_prepare,
579	.is_prepared = clk_sama5d4_slow_osc_is_prepared,
580};
581
582static const struct clk_slow_bits at91sama5d4_bits = {
583	.cr_oscsel = BIT(3),
584};
585
586static void __init of_sama5d4_sckc_setup(struct device_node *np)
587{
588	void __iomem *regbase = of_iomap(np, 0);
589	struct clk_hw *slow_rc, *slowck;
590	struct clk_sama5d4_slow_osc *osc;
591	struct clk_init_data init = {};
592	const char *xtal_name;
593	const struct clk_hw *parent_hws[2];
594	static struct clk_parent_data parent_data = {
595		.name = "slow_xtal",
596	};
597	int ret;
598
599	if (!regbase)
600		return;
601
602	slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL,
603							   "slow_rc_osc",
604							   NULL, 0, 32768,
605							   250000000);
606	if (IS_ERR(slow_rc))
607		return;
608
609	xtal_name = of_clk_get_parent_name(np, 0);
610	if (!xtal_name)
611		goto unregister_slow_rc;
612	parent_data.fw_name = xtal_name;
613
614	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
615	if (!osc)
616		goto unregister_slow_rc;
617
618	init.name = "slow_osc";
619	init.ops = &sama5d4_slow_osc_ops;
620	init.parent_data = &parent_data;
621	init.num_parents = 1;
622	init.flags = CLK_IGNORE_UNUSED;
623
624	osc->hw.init = &init;
625	osc->sckcr = regbase;
626	osc->startup_usec = 1200000;
627	osc->bits = &at91sama5d4_bits;
628
629	ret = clk_hw_register(NULL, &osc->hw);
630	if (ret)
631		goto free_slow_osc_data;
632
633	parent_hws[0] = slow_rc;
634	parent_hws[1] = &osc->hw;
635	slowck = at91_clk_register_sam9x5_slow(regbase, "slowck",
636					       parent_hws, 2,
637					       &at91sama5d4_bits);
638	if (IS_ERR(slowck))
639		goto unregister_slow_osc;
640
641	ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
642	if (WARN_ON(ret))
643		goto unregister_slowck;
644
645	return;
646
647unregister_slowck:
648	at91_clk_unregister_sam9x5_slow(slowck);
649unregister_slow_osc:
650	clk_hw_unregister(&osc->hw);
651free_slow_osc_data:
652	kfree(osc);
653unregister_slow_rc:
654	clk_hw_unregister(slow_rc);
655}
656CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
657	       of_sama5d4_sckc_setup);
~/ Read-only file preview.