Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
  4 */
  5
  6#include <linux/clk-provider.h>
  7#include <linux/clkdev.h>
  8#include <linux/clk/at91_pmc.h>
  9#include <linux/delay.h>
 10#include <linux/mfd/syscon.h>
 11#include <linux/regmap.h>
 12
 13#include "pmc.h"
 14
 15#define SLOW_CLOCK_FREQ		32768
 16#define MAINF_DIV		16
 17#define MAINFRDY_TIMEOUT	(((MAINF_DIV + 1) * USEC_PER_SEC) / \
 18				 SLOW_CLOCK_FREQ)
 19#define MAINF_LOOP_MIN_WAIT	(USEC_PER_SEC / SLOW_CLOCK_FREQ)
 20#define MAINF_LOOP_MAX_WAIT	MAINFRDY_TIMEOUT
 21
 22#define MOR_KEY_MASK		(0xff << 16)
 23
 24#define clk_main_parent_select(s)	(((s) & \
 25					(AT91_PMC_MOSCEN | \
 26					AT91_PMC_OSCBYPASS)) ? 1 : 0)
 27
 28struct clk_main_osc {
 29	struct clk_hw hw;
 30	struct regmap *regmap;
 31	struct at91_clk_pms pms;
 32};
 33
 34#define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)
 35
 36struct clk_main_rc_osc {
 37	struct clk_hw hw;
 38	struct regmap *regmap;
 39	unsigned long frequency;
 40	unsigned long accuracy;
 41	struct at91_clk_pms pms;
 42};
 43
 44#define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw)
 45
 46struct clk_rm9200_main {
 47	struct clk_hw hw;
 48	struct regmap *regmap;
 49};
 50
 51#define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw)
 52
 53struct clk_sam9x5_main {
 54	struct clk_hw hw;
 55	struct regmap *regmap;
 56	struct at91_clk_pms pms;
 57	u8 parent;
 58};
 59
 60#define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw)
 61
 62static inline bool clk_main_osc_ready(struct regmap *regmap)
 63{
 64	unsigned int status;
 65
 66	regmap_read(regmap, AT91_PMC_SR, &status);
 67
 68	return status & AT91_PMC_MOSCS;
 69}
 70
 71static int clk_main_osc_prepare(struct clk_hw *hw)
 72{
 73	struct clk_main_osc *osc = to_clk_main_osc(hw);
 74	struct regmap *regmap = osc->regmap;
 75	u32 tmp;
 76
 77	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
 78	tmp &= ~MOR_KEY_MASK;
 79
 80	if (tmp & AT91_PMC_OSCBYPASS)
 81		return 0;
 82
 83	if (!(tmp & AT91_PMC_MOSCEN)) {
 84		tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
 85		regmap_write(regmap, AT91_CKGR_MOR, tmp);
 86	}
 87
 88	while (!clk_main_osc_ready(regmap))
 89		cpu_relax();
 90
 91	return 0;
 92}
 93
 94static void clk_main_osc_unprepare(struct clk_hw *hw)
 95{
 96	struct clk_main_osc *osc = to_clk_main_osc(hw);
 97	struct regmap *regmap = osc->regmap;
 98	u32 tmp;
 99
100	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
101	if (tmp & AT91_PMC_OSCBYPASS)
102		return;
103
104	if (!(tmp & AT91_PMC_MOSCEN))
105		return;
106
107	tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
108	regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
109}
110
111static int clk_main_osc_is_prepared(struct clk_hw *hw)
112{
113	struct clk_main_osc *osc = to_clk_main_osc(hw);
114	struct regmap *regmap = osc->regmap;
115	u32 tmp, status;
116
117	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
118	if (tmp & AT91_PMC_OSCBYPASS)
119		return 1;
120
121	regmap_read(regmap, AT91_PMC_SR, &status);
122
123	return (status & AT91_PMC_MOSCS) && clk_main_parent_select(tmp);
124}
125
126static int clk_main_osc_save_context(struct clk_hw *hw)
127{
128	struct clk_main_osc *osc = to_clk_main_osc(hw);
129
130	osc->pms.status = clk_main_osc_is_prepared(hw);
131
132	return 0;
133}
134
135static void clk_main_osc_restore_context(struct clk_hw *hw)
136{
137	struct clk_main_osc *osc = to_clk_main_osc(hw);
138
139	if (osc->pms.status)
140		clk_main_osc_prepare(hw);
141}
142
143static const struct clk_ops main_osc_ops = {
144	.prepare = clk_main_osc_prepare,
145	.unprepare = clk_main_osc_unprepare,
146	.is_prepared = clk_main_osc_is_prepared,
147	.save_context = clk_main_osc_save_context,
148	.restore_context = clk_main_osc_restore_context,
149};
150
151struct clk_hw * __init
152at91_clk_register_main_osc(struct regmap *regmap,
153			   const char *name,
154			   const char *parent_name,
155			   bool bypass)
156{
157	struct clk_main_osc *osc;
158	struct clk_init_data init;
159	struct clk_hw *hw;
160	int ret;
161
162	if (!name || !parent_name)
163		return ERR_PTR(-EINVAL);
164
165	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
166	if (!osc)
167		return ERR_PTR(-ENOMEM);
168
169	init.name = name;
170	init.ops = &main_osc_ops;
171	init.parent_names = &parent_name;
172	init.num_parents = 1;
173	init.flags = CLK_IGNORE_UNUSED;
174
175	osc->hw.init = &init;
176	osc->regmap = regmap;
177
178	if (bypass)
179		regmap_update_bits(regmap,
180				   AT91_CKGR_MOR, MOR_KEY_MASK |
181				   AT91_PMC_OSCBYPASS,
182				   AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
183
184	hw = &osc->hw;
185	ret = clk_hw_register(NULL, &osc->hw);
186	if (ret) {
187		kfree(osc);
188		hw = ERR_PTR(ret);
189	}
190
191	return hw;
192}
193
194static bool clk_main_rc_osc_ready(struct regmap *regmap)
195{
196	unsigned int status;
197
198	regmap_read(regmap, AT91_PMC_SR, &status);
199
200	return !!(status & AT91_PMC_MOSCRCS);
201}
202
203static int clk_main_rc_osc_prepare(struct clk_hw *hw)
204{
205	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
206	struct regmap *regmap = osc->regmap;
207	unsigned int mor;
208
209	regmap_read(regmap, AT91_CKGR_MOR, &mor);
210
211	if (!(mor & AT91_PMC_MOSCRCEN))
212		regmap_update_bits(regmap, AT91_CKGR_MOR,
213				   MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
214				   AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
215
216	while (!clk_main_rc_osc_ready(regmap))
217		cpu_relax();
218
219	return 0;
220}
221
222static void clk_main_rc_osc_unprepare(struct clk_hw *hw)
223{
224	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
225	struct regmap *regmap = osc->regmap;
226	unsigned int mor;
227
228	regmap_read(regmap, AT91_CKGR_MOR, &mor);
229
230	if (!(mor & AT91_PMC_MOSCRCEN))
231		return;
232
233	regmap_update_bits(regmap, AT91_CKGR_MOR,
234			   MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);
235}
236
237static int clk_main_rc_osc_is_prepared(struct clk_hw *hw)
238{
239	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
240	struct regmap *regmap = osc->regmap;
241	unsigned int mor, status;
242
243	regmap_read(regmap, AT91_CKGR_MOR, &mor);
244	regmap_read(regmap, AT91_PMC_SR, &status);
245
246	return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS);
247}
248
249static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw,
250						 unsigned long parent_rate)
251{
252	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
253
254	return osc->frequency;
255}
256
257static unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw,
258						     unsigned long parent_acc)
259{
260	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
261
262	return osc->accuracy;
263}
264
265static int clk_main_rc_osc_save_context(struct clk_hw *hw)
266{
267	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
268
269	osc->pms.status = clk_main_rc_osc_is_prepared(hw);
270
271	return 0;
272}
273
274static void clk_main_rc_osc_restore_context(struct clk_hw *hw)
275{
276	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
277
278	if (osc->pms.status)
279		clk_main_rc_osc_prepare(hw);
280}
281
282static const struct clk_ops main_rc_osc_ops = {
283	.prepare = clk_main_rc_osc_prepare,
284	.unprepare = clk_main_rc_osc_unprepare,
285	.is_prepared = clk_main_rc_osc_is_prepared,
286	.recalc_rate = clk_main_rc_osc_recalc_rate,
287	.recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
288	.save_context = clk_main_rc_osc_save_context,
289	.restore_context = clk_main_rc_osc_restore_context,
290};
291
292struct clk_hw * __init
293at91_clk_register_main_rc_osc(struct regmap *regmap,
294			      const char *name,
295			      u32 frequency, u32 accuracy)
296{
297	struct clk_main_rc_osc *osc;
298	struct clk_init_data init;
299	struct clk_hw *hw;
300	int ret;
301
302	if (!name || !frequency)
303		return ERR_PTR(-EINVAL);
304
305	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
306	if (!osc)
307		return ERR_PTR(-ENOMEM);
308
309	init.name = name;
310	init.ops = &main_rc_osc_ops;
311	init.parent_names = NULL;
312	init.num_parents = 0;
313	init.flags = CLK_IGNORE_UNUSED;
314
315	osc->hw.init = &init;
316	osc->regmap = regmap;
317	osc->frequency = frequency;
318	osc->accuracy = accuracy;
319
320	hw = &osc->hw;
321	ret = clk_hw_register(NULL, hw);
322	if (ret) {
323		kfree(osc);
324		hw = ERR_PTR(ret);
325	}
326
327	return hw;
328}
329
330static int clk_main_probe_frequency(struct regmap *regmap)
331{
332	unsigned long prep_time, timeout;
333	unsigned int mcfr;
334
335	timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);
336	do {
337		prep_time = jiffies;
338		regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
339		if (mcfr & AT91_PMC_MAINRDY)
340			return 0;
341		if (system_state < SYSTEM_RUNNING)
342			udelay(MAINF_LOOP_MIN_WAIT);
343		else
344			usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
345	} while (time_before(prep_time, timeout));
346
347	return -ETIMEDOUT;
348}
349
350static unsigned long clk_main_recalc_rate(struct regmap *regmap,
351					  unsigned long parent_rate)
352{
353	unsigned int mcfr;
354
355	if (parent_rate)
356		return parent_rate;
357
358	pr_warn("Main crystal frequency not set, using approximate value\n");
359	regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
360	if (!(mcfr & AT91_PMC_MAINRDY))
361		return 0;
362
363	return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
364}
365
366static int clk_rm9200_main_prepare(struct clk_hw *hw)
367{
368	struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
369
370	return clk_main_probe_frequency(clkmain->regmap);
371}
372
373static int clk_rm9200_main_is_prepared(struct clk_hw *hw)
374{
375	struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
376	unsigned int status;
377
378	regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);
379
380	return !!(status & AT91_PMC_MAINRDY);
381}
382
383static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
384						 unsigned long parent_rate)
385{
386	struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
387
388	return clk_main_recalc_rate(clkmain->regmap, parent_rate);
389}
390
391static const struct clk_ops rm9200_main_ops = {
392	.prepare = clk_rm9200_main_prepare,
393	.is_prepared = clk_rm9200_main_is_prepared,
394	.recalc_rate = clk_rm9200_main_recalc_rate,
395};
396
397struct clk_hw * __init
398at91_clk_register_rm9200_main(struct regmap *regmap,
399			      const char *name,
400			      const char *parent_name)
401{
402	struct clk_rm9200_main *clkmain;
403	struct clk_init_data init;
404	struct clk_hw *hw;
405	int ret;
406
407	if (!name)
408		return ERR_PTR(-EINVAL);
409
410	if (!parent_name)
411		return ERR_PTR(-EINVAL);
412
413	clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
414	if (!clkmain)
415		return ERR_PTR(-ENOMEM);
416
417	init.name = name;
418	init.ops = &rm9200_main_ops;
419	init.parent_names = &parent_name;
420	init.num_parents = 1;
421	init.flags = 0;
422
423	clkmain->hw.init = &init;
424	clkmain->regmap = regmap;
425
426	hw = &clkmain->hw;
427	ret = clk_hw_register(NULL, &clkmain->hw);
428	if (ret) {
429		kfree(clkmain);
430		hw = ERR_PTR(ret);
431	}
432
433	return hw;
434}
435
436static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
437{
438	unsigned int status;
439
440	regmap_read(regmap, AT91_PMC_SR, &status);
441
442	return !!(status & AT91_PMC_MOSCSELS);
443}
444
445static int clk_sam9x5_main_prepare(struct clk_hw *hw)
446{
447	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
448	struct regmap *regmap = clkmain->regmap;
449
450	while (!clk_sam9x5_main_ready(regmap))
451		cpu_relax();
452
453	return clk_main_probe_frequency(regmap);
454}
455
456static int clk_sam9x5_main_is_prepared(struct clk_hw *hw)
457{
458	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
459
460	return clk_sam9x5_main_ready(clkmain->regmap);
461}
462
463static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
464						 unsigned long parent_rate)
465{
466	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
467
468	return clk_main_recalc_rate(clkmain->regmap, parent_rate);
469}
470
471static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
472{
473	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
474	struct regmap *regmap = clkmain->regmap;
475	unsigned int tmp;
476
477	if (index > 1)
478		return -EINVAL;
479
480	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
481
482	if (index && !(tmp & AT91_PMC_MOSCSEL))
483		tmp = AT91_PMC_MOSCSEL;
484	else if (!index && (tmp & AT91_PMC_MOSCSEL))
485		tmp = 0;
486	else
487		return 0;
488
489	regmap_update_bits(regmap, AT91_CKGR_MOR,
490			   AT91_PMC_MOSCSEL | MOR_KEY_MASK,
491			   tmp | AT91_PMC_KEY);
492
493	while (!clk_sam9x5_main_ready(regmap))
494		cpu_relax();
495
496	return 0;
497}
498
499static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)
500{
501	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
502	unsigned int status;
503
504	regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
505
506	return clk_main_parent_select(status);
507}
508
509static int clk_sam9x5_main_save_context(struct clk_hw *hw)
510{
511	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
512
513	clkmain->pms.status = clk_main_rc_osc_is_prepared(&clkmain->hw);
514	clkmain->pms.parent = clk_sam9x5_main_get_parent(&clkmain->hw);
515
516	return 0;
517}
518
519static void clk_sam9x5_main_restore_context(struct clk_hw *hw)
520{
521	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
522	int ret;
523
524	ret = clk_sam9x5_main_set_parent(hw, clkmain->pms.parent);
525	if (ret)
526		return;
527
528	if (clkmain->pms.status)
529		clk_sam9x5_main_prepare(hw);
530}
531
532static const struct clk_ops sam9x5_main_ops = {
533	.prepare = clk_sam9x5_main_prepare,
534	.is_prepared = clk_sam9x5_main_is_prepared,
535	.recalc_rate = clk_sam9x5_main_recalc_rate,
536	.set_parent = clk_sam9x5_main_set_parent,
537	.get_parent = clk_sam9x5_main_get_parent,
538	.save_context = clk_sam9x5_main_save_context,
539	.restore_context = clk_sam9x5_main_restore_context,
540};
541
542struct clk_hw * __init
543at91_clk_register_sam9x5_main(struct regmap *regmap,
544			      const char *name,
545			      const char **parent_names,
546			      int num_parents)
547{
548	struct clk_sam9x5_main *clkmain;
549	struct clk_init_data init;
550	unsigned int status;
551	struct clk_hw *hw;
552	int ret;
553
554	if (!name)
555		return ERR_PTR(-EINVAL);
556
557	if (!parent_names || !num_parents)
558		return ERR_PTR(-EINVAL);
559
560	clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
561	if (!clkmain)
562		return ERR_PTR(-ENOMEM);
563
564	init.name = name;
565	init.ops = &sam9x5_main_ops;
566	init.parent_names = parent_names;
567	init.num_parents = num_parents;
568	init.flags = CLK_SET_PARENT_GATE;
569
570	clkmain->hw.init = &init;
571	clkmain->regmap = regmap;
572	regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
573	clkmain->parent = clk_main_parent_select(status);
574
575	hw = &clkmain->hw;
576	ret = clk_hw_register(NULL, &clkmain->hw);
577	if (ret) {
578		kfree(clkmain);
579		hw = ERR_PTR(ret);
580	}
581
582	return hw;
583}