blob: f607ee702c838409b7923abe1288725cc7d0afc3 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Boris BREZILLON38d34c32013-10-11 10:44:49 +02002/*
3 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
Boris BREZILLON38d34c32013-10-11 10:44:49 +02004 */
5
6#include <linux/clk-provider.h>
7#include <linux/clkdev.h>
8#include <linux/clk/at91_pmc.h>
9#include <linux/delay.h>
Boris Brezillon1bdf0232014-09-07 08:14:29 +020010#include <linux/mfd/syscon.h>
11#include <linux/regmap.h>
Boris BREZILLON38d34c32013-10-11 10:44:49 +020012
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
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020022#define MOR_KEY_MASK (0xff << 16)
23
24struct clk_main_osc {
Boris BREZILLON38d34c32013-10-11 10:44:49 +020025 struct clk_hw hw;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020026 struct regmap *regmap;
Boris BREZILLON38d34c32013-10-11 10:44:49 +020027};
28
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020029#define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)
Boris BREZILLON38d34c32013-10-11 10:44:49 +020030
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020031struct clk_main_rc_osc {
32 struct clk_hw hw;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020033 struct regmap *regmap;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020034 unsigned long frequency;
35 unsigned long accuracy;
36};
37
38#define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw)
39
40struct clk_rm9200_main {
41 struct clk_hw hw;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020042 struct regmap *regmap;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020043};
44
45#define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw)
46
47struct clk_sam9x5_main {
48 struct clk_hw hw;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020049 struct regmap *regmap;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020050 u8 parent;
51};
52
53#define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw)
54
Boris Brezillon1bdf0232014-09-07 08:14:29 +020055static inline bool clk_main_osc_ready(struct regmap *regmap)
56{
57 unsigned int status;
58
59 regmap_read(regmap, AT91_PMC_SR, &status);
60
61 return status & AT91_PMC_MOSCS;
62}
63
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020064static int clk_main_osc_prepare(struct clk_hw *hw)
Boris BREZILLON38d34c32013-10-11 10:44:49 +020065{
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020066 struct clk_main_osc *osc = to_clk_main_osc(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +020067 struct regmap *regmap = osc->regmap;
Boris BREZILLON38d34c32013-10-11 10:44:49 +020068 u32 tmp;
69
Boris Brezillon1bdf0232014-09-07 08:14:29 +020070 regmap_read(regmap, AT91_CKGR_MOR, &tmp);
71 tmp &= ~MOR_KEY_MASK;
72
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020073 if (tmp & AT91_PMC_OSCBYPASS)
Boris BREZILLON38d34c32013-10-11 10:44:49 +020074 return 0;
75
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020076 if (!(tmp & AT91_PMC_MOSCEN)) {
77 tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020078 regmap_write(regmap, AT91_CKGR_MOR, tmp);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020079 }
80
Alexandre Belloni99a81702015-09-16 23:47:39 +020081 while (!clk_main_osc_ready(regmap))
82 cpu_relax();
Boris BREZILLON38d34c32013-10-11 10:44:49 +020083
84 return 0;
85}
86
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020087static void clk_main_osc_unprepare(struct clk_hw *hw)
Boris BREZILLON38d34c32013-10-11 10:44:49 +020088{
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020089 struct clk_main_osc *osc = to_clk_main_osc(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +020090 struct regmap *regmap = osc->regmap;
91 u32 tmp;
Boris BREZILLON38d34c32013-10-11 10:44:49 +020092
Boris Brezillon1bdf0232014-09-07 08:14:29 +020093 regmap_read(regmap, AT91_CKGR_MOR, &tmp);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +020094 if (tmp & AT91_PMC_OSCBYPASS)
95 return;
96
97 if (!(tmp & AT91_PMC_MOSCEN))
98 return;
99
100 tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200101 regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200102}
103
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200104static int clk_main_osc_is_prepared(struct clk_hw *hw)
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200105{
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200106 struct clk_main_osc *osc = to_clk_main_osc(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200107 struct regmap *regmap = osc->regmap;
108 u32 tmp, status;
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200109
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200110 regmap_read(regmap, AT91_CKGR_MOR, &tmp);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200111 if (tmp & AT91_PMC_OSCBYPASS)
112 return 1;
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200113
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200114 regmap_read(regmap, AT91_PMC_SR, &status);
115
116 return (status & AT91_PMC_MOSCS) && (tmp & AT91_PMC_MOSCEN);
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200117}
118
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200119static const struct clk_ops main_osc_ops = {
120 .prepare = clk_main_osc_prepare,
121 .unprepare = clk_main_osc_unprepare,
122 .is_prepared = clk_main_osc_is_prepared,
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200123};
124
Alexandre Bellonib2e39dc2018-10-16 16:21:44 +0200125struct clk_hw * __init
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200126at91_clk_register_main_osc(struct regmap *regmap,
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200127 const char *name,
128 const char *parent_name,
129 bool bypass)
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200130{
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200131 struct clk_main_osc *osc;
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200132 struct clk_init_data init;
Stephen Boydf5644f12016-06-01 14:31:22 -0700133 struct clk_hw *hw;
134 int ret;
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200135
Alexandre Belloni99a81702015-09-16 23:47:39 +0200136 if (!name || !parent_name)
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200137 return ERR_PTR(-EINVAL);
138
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200139 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
140 if (!osc)
141 return ERR_PTR(-ENOMEM);
142
143 init.name = name;
144 init.ops = &main_osc_ops;
145 init.parent_names = &parent_name;
146 init.num_parents = 1;
147 init.flags = CLK_IGNORE_UNUSED;
148
149 osc->hw.init = &init;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200150 osc->regmap = regmap;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200151
152 if (bypass)
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200153 regmap_update_bits(regmap,
154 AT91_CKGR_MOR, MOR_KEY_MASK |
155 AT91_PMC_MOSCEN,
156 AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200157
Stephen Boydf5644f12016-06-01 14:31:22 -0700158 hw = &osc->hw;
159 ret = clk_hw_register(NULL, &osc->hw);
160 if (ret) {
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200161 kfree(osc);
Stephen Boydf5644f12016-06-01 14:31:22 -0700162 hw = ERR_PTR(ret);
163 }
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200164
Stephen Boydf5644f12016-06-01 14:31:22 -0700165 return hw;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200166}
167
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200168static bool clk_main_rc_osc_ready(struct regmap *regmap)
169{
170 unsigned int status;
171
172 regmap_read(regmap, AT91_PMC_SR, &status);
173
174 return status & AT91_PMC_MOSCRCS;
175}
176
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200177static int clk_main_rc_osc_prepare(struct clk_hw *hw)
178{
179 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200180 struct regmap *regmap = osc->regmap;
181 unsigned int mor;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200182
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200183 regmap_read(regmap, AT91_CKGR_MOR, &mor);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200184
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200185 if (!(mor & AT91_PMC_MOSCRCEN))
186 regmap_update_bits(regmap, AT91_CKGR_MOR,
187 MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
188 AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200189
Alexandre Belloni99a81702015-09-16 23:47:39 +0200190 while (!clk_main_rc_osc_ready(regmap))
191 cpu_relax();
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200192
193 return 0;
194}
195
196static void clk_main_rc_osc_unprepare(struct clk_hw *hw)
197{
198 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200199 struct regmap *regmap = osc->regmap;
200 unsigned int mor;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200201
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200202 regmap_read(regmap, AT91_CKGR_MOR, &mor);
203
204 if (!(mor & AT91_PMC_MOSCRCEN))
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200205 return;
206
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200207 regmap_update_bits(regmap, AT91_CKGR_MOR,
208 MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200209}
210
211static int clk_main_rc_osc_is_prepared(struct clk_hw *hw)
212{
213 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200214 struct regmap *regmap = osc->regmap;
215 unsigned int mor, status;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200216
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200217 regmap_read(regmap, AT91_CKGR_MOR, &mor);
218 regmap_read(regmap, AT91_PMC_SR, &status);
219
220 return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200221}
222
223static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw,
224 unsigned long parent_rate)
225{
226 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
227
228 return osc->frequency;
229}
230
231static unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw,
232 unsigned long parent_acc)
233{
234 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
235
236 return osc->accuracy;
237}
238
239static const struct clk_ops main_rc_osc_ops = {
240 .prepare = clk_main_rc_osc_prepare,
241 .unprepare = clk_main_rc_osc_unprepare,
242 .is_prepared = clk_main_rc_osc_is_prepared,
243 .recalc_rate = clk_main_rc_osc_recalc_rate,
244 .recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
245};
246
Alexandre Bellonib2e39dc2018-10-16 16:21:44 +0200247struct clk_hw * __init
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200248at91_clk_register_main_rc_osc(struct regmap *regmap,
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200249 const char *name,
250 u32 frequency, u32 accuracy)
251{
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200252 struct clk_main_rc_osc *osc;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200253 struct clk_init_data init;
Stephen Boydf5644f12016-06-01 14:31:22 -0700254 struct clk_hw *hw;
255 int ret;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200256
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200257 if (!name || !frequency)
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200258 return ERR_PTR(-EINVAL);
259
260 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
261 if (!osc)
262 return ERR_PTR(-ENOMEM);
263
264 init.name = name;
265 init.ops = &main_rc_osc_ops;
266 init.parent_names = NULL;
267 init.num_parents = 0;
Stephen Boyda9bb2ef2016-03-01 10:59:46 -0800268 init.flags = CLK_IGNORE_UNUSED;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200269
270 osc->hw.init = &init;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200271 osc->regmap = regmap;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200272 osc->frequency = frequency;
273 osc->accuracy = accuracy;
274
Stephen Boydf5644f12016-06-01 14:31:22 -0700275 hw = &osc->hw;
276 ret = clk_hw_register(NULL, hw);
277 if (ret) {
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200278 kfree(osc);
Stephen Boydf5644f12016-06-01 14:31:22 -0700279 hw = ERR_PTR(ret);
280 }
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200281
Stephen Boydf5644f12016-06-01 14:31:22 -0700282 return hw;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200283}
284
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200285static int clk_main_probe_frequency(struct regmap *regmap)
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200286{
287 unsigned long prep_time, timeout;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200288 unsigned int mcfr;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200289
290 timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);
291 do {
292 prep_time = jiffies;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200293 regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
294 if (mcfr & AT91_PMC_MAINRDY)
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200295 return 0;
296 usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
297 } while (time_before(prep_time, timeout));
298
299 return -ETIMEDOUT;
300}
301
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200302static unsigned long clk_main_recalc_rate(struct regmap *regmap,
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200303 unsigned long parent_rate)
304{
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200305 unsigned int mcfr;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200306
307 if (parent_rate)
308 return parent_rate;
309
Alexandre Belloni4da66b62014-07-01 16:12:12 +0200310 pr_warn("Main crystal frequency not set, using approximate value\n");
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200311 regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
312 if (!(mcfr & AT91_PMC_MAINRDY))
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200313 return 0;
314
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200315 return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200316}
317
318static int clk_rm9200_main_prepare(struct clk_hw *hw)
319{
320 struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
321
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200322 return clk_main_probe_frequency(clkmain->regmap);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200323}
324
325static int clk_rm9200_main_is_prepared(struct clk_hw *hw)
326{
327 struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200328 unsigned int status;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200329
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200330 regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);
331
332 return status & AT91_PMC_MAINRDY ? 1 : 0;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200333}
334
335static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
336 unsigned long parent_rate)
337{
338 struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
339
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200340 return clk_main_recalc_rate(clkmain->regmap, parent_rate);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200341}
342
343static const struct clk_ops rm9200_main_ops = {
344 .prepare = clk_rm9200_main_prepare,
345 .is_prepared = clk_rm9200_main_is_prepared,
346 .recalc_rate = clk_rm9200_main_recalc_rate,
347};
348
Alexandre Bellonib2e39dc2018-10-16 16:21:44 +0200349struct clk_hw * __init
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200350at91_clk_register_rm9200_main(struct regmap *regmap,
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200351 const char *name,
352 const char *parent_name)
353{
354 struct clk_rm9200_main *clkmain;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200355 struct clk_init_data init;
Stephen Boydf5644f12016-06-01 14:31:22 -0700356 struct clk_hw *hw;
357 int ret;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200358
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200359 if (!name)
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200360 return ERR_PTR(-EINVAL);
361
362 if (!parent_name)
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200363 return ERR_PTR(-EINVAL);
364
365 clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
366 if (!clkmain)
367 return ERR_PTR(-ENOMEM);
368
369 init.name = name;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200370 init.ops = &rm9200_main_ops;
371 init.parent_names = &parent_name;
372 init.num_parents = 1;
373 init.flags = 0;
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200374
375 clkmain->hw.init = &init;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200376 clkmain->regmap = regmap;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200377
Stephen Boydf5644f12016-06-01 14:31:22 -0700378 hw = &clkmain->hw;
379 ret = clk_hw_register(NULL, &clkmain->hw);
380 if (ret) {
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200381 kfree(clkmain);
Stephen Boydf5644f12016-06-01 14:31:22 -0700382 hw = ERR_PTR(ret);
383 }
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200384
Stephen Boydf5644f12016-06-01 14:31:22 -0700385 return hw;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200386}
387
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200388static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
389{
390 unsigned int status;
391
392 regmap_read(regmap, AT91_PMC_SR, &status);
393
394 return status & AT91_PMC_MOSCSELS ? 1 : 0;
395}
396
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200397static int clk_sam9x5_main_prepare(struct clk_hw *hw)
398{
399 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200400 struct regmap *regmap = clkmain->regmap;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200401
Alexandre Belloni99a81702015-09-16 23:47:39 +0200402 while (!clk_sam9x5_main_ready(regmap))
403 cpu_relax();
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200404
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200405 return clk_main_probe_frequency(regmap);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200406}
407
408static int clk_sam9x5_main_is_prepared(struct clk_hw *hw)
409{
410 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
411
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200412 return clk_sam9x5_main_ready(clkmain->regmap);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200413}
414
415static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
416 unsigned long parent_rate)
417{
418 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
419
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200420 return clk_main_recalc_rate(clkmain->regmap, parent_rate);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200421}
422
423static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
424{
425 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200426 struct regmap *regmap = clkmain->regmap;
427 unsigned int tmp;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200428
429 if (index > 1)
430 return -EINVAL;
431
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200432 regmap_read(regmap, AT91_CKGR_MOR, &tmp);
433 tmp &= ~MOR_KEY_MASK;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200434
435 if (index && !(tmp & AT91_PMC_MOSCSEL))
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200436 regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200437 else if (!index && (tmp & AT91_PMC_MOSCSEL))
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200438 regmap_write(regmap, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200439
Alexandre Belloni99a81702015-09-16 23:47:39 +0200440 while (!clk_sam9x5_main_ready(regmap))
441 cpu_relax();
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200442
443 return 0;
444}
445
446static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)
447{
448 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200449 unsigned int status;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200450
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200451 regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
452
453 return status & AT91_PMC_MOSCEN ? 1 : 0;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200454}
455
456static const struct clk_ops sam9x5_main_ops = {
457 .prepare = clk_sam9x5_main_prepare,
458 .is_prepared = clk_sam9x5_main_is_prepared,
459 .recalc_rate = clk_sam9x5_main_recalc_rate,
460 .set_parent = clk_sam9x5_main_set_parent,
461 .get_parent = clk_sam9x5_main_get_parent,
462};
463
Alexandre Bellonib2e39dc2018-10-16 16:21:44 +0200464struct clk_hw * __init
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200465at91_clk_register_sam9x5_main(struct regmap *regmap,
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200466 const char *name,
467 const char **parent_names,
468 int num_parents)
469{
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200470 struct clk_sam9x5_main *clkmain;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200471 struct clk_init_data init;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200472 unsigned int status;
Stephen Boydf5644f12016-06-01 14:31:22 -0700473 struct clk_hw *hw;
474 int ret;
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200475
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200476 if (!name)
Boris BREZILLON27cb1c22014-05-07 18:00:08 +0200477 return ERR_PTR(-EINVAL);
478
479 if (!parent_names || !num_parents)
480 return ERR_PTR(-EINVAL);
481
482 clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
483 if (!clkmain)
484 return ERR_PTR(-ENOMEM);
485
486 init.name = name;
487 init.ops = &sam9x5_main_ops;
488 init.parent_names = parent_names;
489 init.num_parents = num_parents;
490 init.flags = CLK_SET_PARENT_GATE;
491
492 clkmain->hw.init = &init;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200493 clkmain->regmap = regmap;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200494 regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
495 clkmain->parent = status & AT91_PMC_MOSCEN ? 1 : 0;
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200496
Stephen Boydf5644f12016-06-01 14:31:22 -0700497 hw = &clkmain->hw;
498 ret = clk_hw_register(NULL, &clkmain->hw);
499 if (ret) {
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200500 kfree(clkmain);
Stephen Boydf5644f12016-06-01 14:31:22 -0700501 hw = ERR_PTR(ret);
502 }
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200503
Stephen Boydf5644f12016-06-01 14:31:22 -0700504 return hw;
Boris BREZILLON38d34c32013-10-11 10:44:49 +0200505}