blob: 0fe4d7f04225f6ae207a26e2b900c867e311f69b [file] [log] [blame]
Nicolas Ferredf70aee2015-07-31 11:43:12 +02001/*
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>
Boris Brezillon1bdf0232014-09-07 08:14:29 +020018#include <linux/mfd/syscon.h>
19#include <linux/regmap.h>
Nicolas Ferredf70aee2015-07-31 11:43:12 +020020
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
Quentin Schulz1a1a36d2017-08-10 08:34:05 +020029#define GCK_ID_I2S0 54
30#define GCK_ID_I2S1 55
31#define GCK_ID_CLASSD 59
32#define GCK_INDEX_DT_AUDIO_PLL 5
33
Nicolas Ferredf70aee2015-07-31 11:43:12 +020034struct clk_generated {
35 struct clk_hw hw;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020036 struct regmap *regmap;
Nicolas Ferredf70aee2015-07-31 11:43:12 +020037 struct clk_range range;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020038 spinlock_t *lock;
Nicolas Ferredf70aee2015-07-31 11:43:12 +020039 u32 id;
40 u32 gckdiv;
41 u8 parent_id;
Quentin Schulz1a1a36d2017-08-10 08:34:05 +020042 bool audio_pll_allowed;
Nicolas Ferredf70aee2015-07-31 11:43:12 +020043};
44
45#define to_clk_generated(hw) \
46 container_of(hw, struct clk_generated, hw)
47
48static int clk_generated_enable(struct clk_hw *hw)
49{
50 struct clk_generated *gck = to_clk_generated(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +020051 unsigned long flags;
Nicolas Ferredf70aee2015-07-31 11:43:12 +020052
53 pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n",
54 __func__, gck->gckdiv, gck->parent_id);
55
Boris Brezillon1bdf0232014-09-07 08:14:29 +020056 spin_lock_irqsave(gck->lock, flags);
57 regmap_write(gck->regmap, AT91_PMC_PCR,
58 (gck->id & AT91_PMC_PCR_PID_MASK));
59 regmap_update_bits(gck->regmap, AT91_PMC_PCR,
60 AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK |
61 AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
62 AT91_PMC_PCR_GCKCSS(gck->parent_id) |
63 AT91_PMC_PCR_CMD |
64 AT91_PMC_PCR_GCKDIV(gck->gckdiv) |
65 AT91_PMC_PCR_GCKEN);
66 spin_unlock_irqrestore(gck->lock, flags);
Nicolas Ferredf70aee2015-07-31 11:43:12 +020067 return 0;
68}
69
70static void clk_generated_disable(struct clk_hw *hw)
71{
72 struct clk_generated *gck = to_clk_generated(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +020073 unsigned long flags;
Nicolas Ferredf70aee2015-07-31 11:43:12 +020074
Boris Brezillon1bdf0232014-09-07 08:14:29 +020075 spin_lock_irqsave(gck->lock, flags);
76 regmap_write(gck->regmap, AT91_PMC_PCR,
77 (gck->id & AT91_PMC_PCR_PID_MASK));
78 regmap_update_bits(gck->regmap, AT91_PMC_PCR,
79 AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
80 AT91_PMC_PCR_CMD);
81 spin_unlock_irqrestore(gck->lock, flags);
Nicolas Ferredf70aee2015-07-31 11:43:12 +020082}
83
84static int clk_generated_is_enabled(struct clk_hw *hw)
85{
86 struct clk_generated *gck = to_clk_generated(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +020087 unsigned long flags;
88 unsigned int status;
Nicolas Ferredf70aee2015-07-31 11:43:12 +020089
Boris Brezillon1bdf0232014-09-07 08:14:29 +020090 spin_lock_irqsave(gck->lock, flags);
91 regmap_write(gck->regmap, AT91_PMC_PCR,
92 (gck->id & AT91_PMC_PCR_PID_MASK));
93 regmap_read(gck->regmap, AT91_PMC_PCR, &status);
94 spin_unlock_irqrestore(gck->lock, flags);
Nicolas Ferredf70aee2015-07-31 11:43:12 +020095
Boris Brezillon1bdf0232014-09-07 08:14:29 +020096 return status & AT91_PMC_PCR_GCKEN ? 1 : 0;
Nicolas Ferredf70aee2015-07-31 11:43:12 +020097}
98
99static unsigned long
100clk_generated_recalc_rate(struct clk_hw *hw,
101 unsigned long parent_rate)
102{
103 struct clk_generated *gck = to_clk_generated(hw);
104
105 return DIV_ROUND_CLOSEST(parent_rate, gck->gckdiv + 1);
106}
107
Quentin Schulz8a8f4bf2017-08-10 08:34:04 +0200108static void clk_generated_best_diff(struct clk_rate_request *req,
109 struct clk_hw *parent,
110 unsigned long parent_rate, u32 div,
111 int *best_diff, long *best_rate)
112{
113 unsigned long tmp_rate;
114 int tmp_diff;
115
116 if (!div)
117 tmp_rate = parent_rate;
118 else
119 tmp_rate = parent_rate / div;
120 tmp_diff = abs(req->rate - tmp_rate);
121
122 if (*best_diff < 0 || *best_diff > tmp_diff) {
123 *best_rate = tmp_rate;
124 *best_diff = tmp_diff;
125 req->best_parent_rate = parent_rate;
126 req->best_parent_hw = parent;
127 }
128}
129
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200130static int clk_generated_determine_rate(struct clk_hw *hw,
131 struct clk_rate_request *req)
132{
133 struct clk_generated *gck = to_clk_generated(hw);
134 struct clk_hw *parent = NULL;
Quentin Schulz1a1a36d2017-08-10 08:34:05 +0200135 struct clk_rate_request req_parent = *req;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200136 long best_rate = -EINVAL;
Quentin Schulz1a1a36d2017-08-10 08:34:05 +0200137 unsigned long min_rate, parent_rate;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200138 int best_diff = -1;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200139 int i;
Quentin Schulz1a1a36d2017-08-10 08:34:05 +0200140 u32 div;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200141
Quentin Schulz1a1a36d2017-08-10 08:34:05 +0200142 for (i = 0; i < clk_hw_get_num_parents(hw) - 1; i++) {
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200143 parent = clk_hw_get_parent_by_index(hw, i);
144 if (!parent)
145 continue;
146
147 parent_rate = clk_hw_get_rate(parent);
148 min_rate = DIV_ROUND_CLOSEST(parent_rate, GENERATED_MAX_DIV + 1);
149 if (!parent_rate ||
150 (gck->range.max && min_rate > gck->range.max))
151 continue;
152
Quentin Schulz8c7aa632017-08-10 08:34:01 +0200153 div = DIV_ROUND_CLOSEST(parent_rate, req->rate);
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200154
Quentin Schulz8a8f4bf2017-08-10 08:34:04 +0200155 clk_generated_best_diff(req, parent, parent_rate, div,
156 &best_diff, &best_rate);
157
Quentin Schulz1a1a36d2017-08-10 08:34:05 +0200158 if (!best_diff)
159 break;
160 }
161
162 /*
163 * The audio_pll rate can be modified, unlike the five others clocks
164 * that should never be altered.
165 * The audio_pll can technically be used by multiple consumers. However,
166 * with the rate locking, the first consumer to enable to clock will be
167 * the one definitely setting the rate of the clock.
168 * Since audio IPs are most likely to request the same rate, we enforce
169 * that the only clks able to modify gck rate are those of audio IPs.
170 */
171
172 if (!gck->audio_pll_allowed)
173 goto end;
174
175 parent = clk_hw_get_parent_by_index(hw, GCK_INDEX_DT_AUDIO_PLL);
176 if (!parent)
177 goto end;
178
179 for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
180 req_parent.rate = req->rate * div;
181 __clk_determine_rate(parent, &req_parent);
182 clk_generated_best_diff(req, parent, req_parent.rate, div,
183 &best_diff, &best_rate);
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200184
185 if (!best_diff)
186 break;
187 }
188
Quentin Schulz1a1a36d2017-08-10 08:34:05 +0200189end:
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200190 pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
191 __func__, best_rate,
192 __clk_get_name((req->best_parent_hw)->clk),
193 req->best_parent_rate);
194
195 if (best_rate < 0)
196 return best_rate;
197
198 req->rate = best_rate;
199 return 0;
200}
201
202/* No modification of hardware as we have the flag CLK_SET_PARENT_GATE set */
203static int clk_generated_set_parent(struct clk_hw *hw, u8 index)
204{
205 struct clk_generated *gck = to_clk_generated(hw);
206
207 if (index >= clk_hw_get_num_parents(hw))
208 return -EINVAL;
209
210 gck->parent_id = index;
211 return 0;
212}
213
214static u8 clk_generated_get_parent(struct clk_hw *hw)
215{
216 struct clk_generated *gck = to_clk_generated(hw);
217
218 return gck->parent_id;
219}
220
221/* No modification of hardware as we have the flag CLK_SET_RATE_GATE set */
222static int clk_generated_set_rate(struct clk_hw *hw,
223 unsigned long rate,
224 unsigned long parent_rate)
225{
226 struct clk_generated *gck = to_clk_generated(hw);
227 u32 div;
228
229 if (!rate)
230 return -EINVAL;
231
232 if (gck->range.max && rate > gck->range.max)
233 return -EINVAL;
234
235 div = DIV_ROUND_CLOSEST(parent_rate, rate);
236 if (div > GENERATED_MAX_DIV + 1 || !div)
237 return -EINVAL;
238
239 gck->gckdiv = div - 1;
240 return 0;
241}
242
243static const struct clk_ops generated_ops = {
244 .enable = clk_generated_enable,
245 .disable = clk_generated_disable,
246 .is_enabled = clk_generated_is_enabled,
247 .recalc_rate = clk_generated_recalc_rate,
248 .determine_rate = clk_generated_determine_rate,
249 .get_parent = clk_generated_get_parent,
250 .set_parent = clk_generated_set_parent,
251 .set_rate = clk_generated_set_rate,
252};
253
254/**
255 * clk_generated_startup - Initialize a given clock to its default parent and
256 * divisor parameter.
257 *
258 * @gck: Generated clock to set the startup parameters for.
259 *
260 * Take parameters from the hardware and update local clock configuration
261 * accordingly.
262 */
263static void clk_generated_startup(struct clk_generated *gck)
264{
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200265 u32 tmp;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200266 unsigned long flags;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200267
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200268 spin_lock_irqsave(gck->lock, flags);
269 regmap_write(gck->regmap, AT91_PMC_PCR,
270 (gck->id & AT91_PMC_PCR_PID_MASK));
271 regmap_read(gck->regmap, AT91_PMC_PCR, &tmp);
272 spin_unlock_irqrestore(gck->lock, flags);
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200273
274 gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK)
275 >> AT91_PMC_PCR_GCKCSS_OFFSET;
276 gck->gckdiv = (tmp & AT91_PMC_PCR_GCKDIV_MASK)
277 >> AT91_PMC_PCR_GCKDIV_OFFSET;
278}
279
Alexandre Bellonib2e39dc2018-10-16 16:21:44 +0200280struct clk_hw * __init
Stephen Boydf5644f12016-06-01 14:31:22 -0700281at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
282 const char *name, const char **parent_names,
Alexandre Bellonic1e45802018-10-16 16:21:43 +0200283 u8 num_parents, u8 id, bool pll_audio,
Stephen Boydf5644f12016-06-01 14:31:22 -0700284 const struct clk_range *range)
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200285{
286 struct clk_generated *gck;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200287 struct clk_init_data init;
Stephen Boydf5644f12016-06-01 14:31:22 -0700288 struct clk_hw *hw;
289 int ret;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200290
291 gck = kzalloc(sizeof(*gck), GFP_KERNEL);
292 if (!gck)
293 return ERR_PTR(-ENOMEM);
294
295 init.name = name;
296 init.ops = &generated_ops;
297 init.parent_names = parent_names;
298 init.num_parents = num_parents;
Quentin Schulz1a1a36d2017-08-10 08:34:05 +0200299 init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
300 CLK_SET_RATE_PARENT;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200301
302 gck->id = id;
303 gck->hw.init = &init;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200304 gck->regmap = regmap;
305 gck->lock = lock;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200306 gck->range = *range;
Alexandre Bellonic1e45802018-10-16 16:21:43 +0200307 gck->audio_pll_allowed = pll_audio;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200308
Alexandre Belloni8e561332017-05-12 16:25:30 +0200309 clk_generated_startup(gck);
Stephen Boydf5644f12016-06-01 14:31:22 -0700310 hw = &gck->hw;
311 ret = clk_hw_register(NULL, &gck->hw);
312 if (ret) {
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200313 kfree(gck);
Stephen Boydf5644f12016-06-01 14:31:22 -0700314 hw = ERR_PTR(ret);
Alexandre Bellonib3b02ea2017-06-08 02:36:47 +0200315 } else {
316 pmc_register_id(id);
Alexandre Belloni4a5f06a2017-06-05 00:02:57 +0200317 }
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200318
Stephen Boydf5644f12016-06-01 14:31:22 -0700319 return hw;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200320}
321
Ben Dooks14755542016-06-07 17:38:09 +0100322static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200323{
324 int num;
325 u32 id;
326 const char *name;
Stephen Boydf5644f12016-06-01 14:31:22 -0700327 struct clk_hw *hw;
Stephen Boyd8c1b1e52016-02-19 17:29:17 -0800328 unsigned int num_parents;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200329 const char *parent_names[GENERATED_SOURCE_MAX];
330 struct device_node *gcknp;
331 struct clk_range range = CLK_RANGE(0, 0);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200332 struct regmap *regmap;
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200333
334 num_parents = of_clk_get_parent_count(np);
Stephen Boyd8c1b1e52016-02-19 17:29:17 -0800335 if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200336 return;
337
338 of_clk_parent_fill(np, parent_names, num_parents);
339
340 num = of_get_child_count(np);
341 if (!num || num > PERIPHERAL_MAX)
342 return;
343
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200344 regmap = syscon_node_to_regmap(of_get_parent(np));
345 if (IS_ERR(regmap))
346 return;
347
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200348 for_each_child_of_node(np, gcknp) {
Alexandre Bellonic1e45802018-10-16 16:21:43 +0200349 bool pll_audio = false;
350
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200351 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
Alexandre Bellonic1e45802018-10-16 16:21:43 +0200363 if (of_device_is_compatible(np, "atmel,sama5d2-clk-generated") &&
364 (id == GCK_ID_I2S0 || id == GCK_ID_I2S1 ||
365 id == GCK_ID_CLASSD))
366 pll_audio = true;
367
Stephen Boydf5644f12016-06-01 14:31:22 -0700368 hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200369 parent_names, num_parents,
Alexandre Bellonic1e45802018-10-16 16:21:43 +0200370 id, pll_audio, &range);
Stephen Boydf5644f12016-06-01 14:31:22 -0700371 if (IS_ERR(hw))
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200372 continue;
373
Stephen Boydf5644f12016-06-01 14:31:22 -0700374 of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw);
Nicolas Ferredf70aee2015-07-31 11:43:12 +0200375 }
376}
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200377CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated",
378 of_sama5d2_clk_generated_setup);