Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1/*
  2 *  Copyright (C) 2015 Atmel Corporation,
  3 *                     Nicolas Ferre <nicolas.ferre@atmel.com>
  4 *
  5 * Based on clk-programmable & clk-peripheral drivers by Boris BREZILLON.
  6 *
  7 * This program is free software; you can redistribute it and/or modify
  8 * it under the terms of the GNU General Public License as published by
  9 * the Free Software Foundation; either version 2 of the License, or
 10 * (at your option) any later version.
 11 *
 12 */
 13
 14#include <linux/clk-provider.h>
 15#include <linux/clkdev.h>
 16#include <linux/clk/at91_pmc.h>
 17#include <linux/of.h>
 18#include <linux/mfd/syscon.h>
 19#include <linux/regmap.h>
 20
 21#include "pmc.h"
 22
 23#define PERIPHERAL_MAX		64
 24#define PERIPHERAL_ID_MIN	2
 25
 26#define GENERATED_SOURCE_MAX	6
 27#define GENERATED_MAX_DIV	255
 28
 29#define GCK_ID_SSC0		43
 30#define GCK_ID_SSC1		44
 31#define GCK_ID_I2S0		54
 32#define GCK_ID_I2S1		55
 33#define GCK_ID_CLASSD		59
 34#define GCK_INDEX_DT_AUDIO_PLL	5
 35
 36struct clk_generated {
 37	struct clk_hw hw;
 38	struct regmap *regmap;
 39	struct clk_range range;
 40	spinlock_t *lock;
 41	u32 id;
 42	u32 gckdiv;
 43	u8 parent_id;
 44	bool audio_pll_allowed;
 45};
 46
 47#define to_clk_generated(hw) \
 48	container_of(hw, struct clk_generated, hw)
 49
 50static int clk_generated_enable(struct clk_hw *hw)
 51{
 52	struct clk_generated *gck = to_clk_generated(hw);
 53	unsigned long flags;
 54
 55	pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n",
 56		 __func__, gck->gckdiv, gck->parent_id);
 57
 58	spin_lock_irqsave(gck->lock, flags);
 59	regmap_write(gck->regmap, AT91_PMC_PCR,
 60		     (gck->id & AT91_PMC_PCR_PID_MASK));
 61	regmap_update_bits(gck->regmap, AT91_PMC_PCR,
 62			   AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK |
 63			   AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
 64			   AT91_PMC_PCR_GCKCSS(gck->parent_id) |
 65			   AT91_PMC_PCR_CMD |
 66			   AT91_PMC_PCR_GCKDIV(gck->gckdiv) |
 67			   AT91_PMC_PCR_GCKEN);
 68	spin_unlock_irqrestore(gck->lock, flags);
 69	return 0;
 70}
 71
 72static void clk_generated_disable(struct clk_hw *hw)
 73{
 74	struct clk_generated *gck = to_clk_generated(hw);
 75	unsigned long flags;
 76
 77	spin_lock_irqsave(gck->lock, flags);
 78	regmap_write(gck->regmap, AT91_PMC_PCR,
 79		     (gck->id & AT91_PMC_PCR_PID_MASK));
 80	regmap_update_bits(gck->regmap, AT91_PMC_PCR,
 81			   AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
 82			   AT91_PMC_PCR_CMD);
 83	spin_unlock_irqrestore(gck->lock, flags);
 84}
 85
 86static int clk_generated_is_enabled(struct clk_hw *hw)
 87{
 88	struct clk_generated *gck = to_clk_generated(hw);
 89	unsigned long flags;
 90	unsigned int status;
 91
 92	spin_lock_irqsave(gck->lock, flags);
 93	regmap_write(gck->regmap, AT91_PMC_PCR,
 94		     (gck->id & AT91_PMC_PCR_PID_MASK));
 95	regmap_read(gck->regmap, AT91_PMC_PCR, &status);
 96	spin_unlock_irqrestore(gck->lock, flags);
 97
 98	return status & AT91_PMC_PCR_GCKEN ? 1 : 0;
 99}
100
101static unsigned long
102clk_generated_recalc_rate(struct clk_hw *hw,
103			  unsigned long parent_rate)
104{
105	struct clk_generated *gck = to_clk_generated(hw);
106
107	return DIV_ROUND_CLOSEST(parent_rate, gck->gckdiv + 1);
108}
109
110static void clk_generated_best_diff(struct clk_rate_request *req,
111				    struct clk_hw *parent,
112				    unsigned long parent_rate, u32 div,
113				    int *best_diff, long *best_rate)
114{
115	unsigned long tmp_rate;
116	int tmp_diff;
117
118	if (!div)
119		tmp_rate = parent_rate;
120	else
121		tmp_rate = parent_rate / div;
122	tmp_diff = abs(req->rate - tmp_rate);
123
124	if (*best_diff < 0 || *best_diff > tmp_diff) {
125		*best_rate = tmp_rate;
126		*best_diff = tmp_diff;
127		req->best_parent_rate = parent_rate;
128		req->best_parent_hw = parent;
129	}
130}
131
132static int clk_generated_determine_rate(struct clk_hw *hw,
133					struct clk_rate_request *req)
134{
135	struct clk_generated *gck = to_clk_generated(hw);
136	struct clk_hw *parent = NULL;
137	struct clk_rate_request req_parent = *req;
138	long best_rate = -EINVAL;
139	unsigned long min_rate, parent_rate;
140	int best_diff = -1;
141	int i;
142	u32 div;
143
144	for (i = 0; i < clk_hw_get_num_parents(hw) - 1; i++) {
145		parent = clk_hw_get_parent_by_index(hw, i);
146		if (!parent)
147			continue;
148
149		parent_rate = clk_hw_get_rate(parent);
150		min_rate = DIV_ROUND_CLOSEST(parent_rate, GENERATED_MAX_DIV + 1);
151		if (!parent_rate ||
152		    (gck->range.max && min_rate > gck->range.max))
153			continue;
154
155		div = DIV_ROUND_CLOSEST(parent_rate, req->rate);
156
157		clk_generated_best_diff(req, parent, parent_rate, div,
158					&best_diff, &best_rate);
159
160		if (!best_diff)
161			break;
162	}
163
164	/*
165	 * The audio_pll rate can be modified, unlike the five others clocks
166	 * that should never be altered.
167	 * The audio_pll can technically be used by multiple consumers. However,
168	 * with the rate locking, the first consumer to enable to clock will be
169	 * the one definitely setting the rate of the clock.
170	 * Since audio IPs are most likely to request the same rate, we enforce
171	 * that the only clks able to modify gck rate are those of audio IPs.
172	 */
173
174	if (!gck->audio_pll_allowed)
175		goto end;
176
177	parent = clk_hw_get_parent_by_index(hw, GCK_INDEX_DT_AUDIO_PLL);
178	if (!parent)
179		goto end;
180
181	for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
182		req_parent.rate = req->rate * div;
183		__clk_determine_rate(parent, &req_parent);
184		clk_generated_best_diff(req, parent, req_parent.rate, div,
185					&best_diff, &best_rate);
186
187		if (!best_diff)
188			break;
189	}
190
191end:
192	pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
193		 __func__, best_rate,
194		 __clk_get_name((req->best_parent_hw)->clk),
195		 req->best_parent_rate);
196
197	if (best_rate < 0)
198		return best_rate;
199
200	req->rate = best_rate;
201	return 0;
202}
203
204/* No modification of hardware as we have the flag CLK_SET_PARENT_GATE set */
205static int clk_generated_set_parent(struct clk_hw *hw, u8 index)
206{
207	struct clk_generated *gck = to_clk_generated(hw);
208
209	if (index >= clk_hw_get_num_parents(hw))
210		return -EINVAL;
211
212	gck->parent_id = index;
213	return 0;
214}
215
216static u8 clk_generated_get_parent(struct clk_hw *hw)
217{
218	struct clk_generated *gck = to_clk_generated(hw);
219
220	return gck->parent_id;
221}
222
223/* No modification of hardware as we have the flag CLK_SET_RATE_GATE set */
224static int clk_generated_set_rate(struct clk_hw *hw,
225				  unsigned long rate,
226				  unsigned long parent_rate)
227{
228	struct clk_generated *gck = to_clk_generated(hw);
229	u32 div;
230
231	if (!rate)
232		return -EINVAL;
233
234	if (gck->range.max && rate > gck->range.max)
235		return -EINVAL;
236
237	div = DIV_ROUND_CLOSEST(parent_rate, rate);
238	if (div > GENERATED_MAX_DIV + 1 || !div)
239		return -EINVAL;
240
241	gck->gckdiv = div - 1;
242	return 0;
243}
244
245static const struct clk_ops generated_ops = {
246	.enable = clk_generated_enable,
247	.disable = clk_generated_disable,
248	.is_enabled = clk_generated_is_enabled,
249	.recalc_rate = clk_generated_recalc_rate,
250	.determine_rate = clk_generated_determine_rate,
251	.get_parent = clk_generated_get_parent,
252	.set_parent = clk_generated_set_parent,
253	.set_rate = clk_generated_set_rate,
254};
255
256/**
257 * clk_generated_startup - Initialize a given clock to its default parent and
258 * divisor parameter.
259 *
260 * @gck:	Generated clock to set the startup parameters for.
261 *
262 * Take parameters from the hardware and update local clock configuration
263 * accordingly.
264 */
265static void clk_generated_startup(struct clk_generated *gck)
266{
267	u32 tmp;
268	unsigned long flags;
269
270	spin_lock_irqsave(gck->lock, flags);
271	regmap_write(gck->regmap, AT91_PMC_PCR,
272		     (gck->id & AT91_PMC_PCR_PID_MASK));
273	regmap_read(gck->regmap, AT91_PMC_PCR, &tmp);
274	spin_unlock_irqrestore(gck->lock, flags);
275
276	gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK)
277					>> AT91_PMC_PCR_GCKCSS_OFFSET;
278	gck->gckdiv = (tmp & AT91_PMC_PCR_GCKDIV_MASK)
279					>> AT91_PMC_PCR_GCKDIV_OFFSET;
280}
281
282static struct clk_hw * __init
283at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
284			    const char *name, const char **parent_names,
285			    u8 num_parents, u8 id,
286			    const struct clk_range *range)
287{
288	struct clk_generated *gck;
289	struct clk_init_data init;
290	struct clk_hw *hw;
291	int ret;
292
293	gck = kzalloc(sizeof(*gck), GFP_KERNEL);
294	if (!gck)
295		return ERR_PTR(-ENOMEM);
296
297	init.name = name;
298	init.ops = &generated_ops;
299	init.parent_names = parent_names;
300	init.num_parents = num_parents;
301	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
302		CLK_SET_RATE_PARENT;
303
304	gck->id = id;
305	gck->hw.init = &init;
306	gck->regmap = regmap;
307	gck->lock = lock;
308	gck->range = *range;
309
310	clk_generated_startup(gck);
311	hw = &gck->hw;
312	ret = clk_hw_register(NULL, &gck->hw);
313	if (ret) {
314		kfree(gck);
315		hw = ERR_PTR(ret);
316	} else {
317		pmc_register_id(id);
318	}
319
320	return hw;
321}
322
323static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
324{
325	int num;
326	u32 id;
327	const char *name;
328	struct clk_hw *hw;
329	unsigned int num_parents;
330	const char *parent_names[GENERATED_SOURCE_MAX];
331	struct device_node *gcknp;
332	struct clk_range range = CLK_RANGE(0, 0);
333	struct regmap *regmap;
334	struct clk_generated *gck;
335
336	num_parents = of_clk_get_parent_count(np);
337	if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)
338		return;
339
340	of_clk_parent_fill(np, parent_names, num_parents);
341
342	num = of_get_child_count(np);
343	if (!num || num > PERIPHERAL_MAX)
344		return;
345
346	regmap = syscon_node_to_regmap(of_get_parent(np));
347	if (IS_ERR(regmap))
348		return;
349
350	for_each_child_of_node(np, gcknp) {
351		if (of_property_read_u32(gcknp, "reg", &id))
352			continue;
353
354		if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX)
355			continue;
356
357		if (of_property_read_string(np, "clock-output-names", &name))
358			name = gcknp->name;
359
360		of_at91_get_clk_range(gcknp, "atmel,clk-output-range",
361				      &range);
362
363		hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
364						  parent_names, num_parents,
365						  id, &range);
366
367		gck = to_clk_generated(hw);
368
369		if (of_device_is_compatible(np,
370					    "atmel,sama5d2-clk-generated")) {
371			if (gck->id == GCK_ID_SSC0 || gck->id == GCK_ID_SSC1 ||
372			    gck->id == GCK_ID_I2S0 || gck->id == GCK_ID_I2S1 ||
373			    gck->id == GCK_ID_CLASSD)
374				gck->audio_pll_allowed = true;
375			else
376				gck->audio_pll_allowed = false;
377		} else {
378			gck->audio_pll_allowed = false;
379		}
380
381		if (IS_ERR(hw))
382			continue;
383
384		of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw);
385	}
386}
387CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated",
388	       of_sama5d2_clk_generated_setup);