Linux Audio

Check our new training course

Linux kernel drivers training

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