forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-10 37f49e37ab4cb5d0bc4c60eb5c6d4dd57db767bb
kernel/drivers/clk/at91/clk-peripheral.c
....@@ -1,13 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
3
- *
4
- * This program is free software; you can redistribute it and/or modify
5
- * it under the terms of the GNU General Public License as published by
6
- * the Free Software Foundation; either version 2 of the License, or
7
- * (at your option) any later version.
8
- *
94 */
105
6
+#include <linux/bitops.h>
117 #include <linux/clk-provider.h>
128 #include <linux/clkdev.h>
139 #include <linux/clk/at91_pmc.h>
....@@ -19,17 +15,9 @@
1915
2016 DEFINE_SPINLOCK(pmc_pcr_lock);
2117
22
-#define PERIPHERAL_MAX 64
23
-
24
-#define PERIPHERAL_AT91RM9200 0
25
-#define PERIPHERAL_AT91SAM9X5 1
26
-
2718 #define PERIPHERAL_ID_MIN 2
2819 #define PERIPHERAL_ID_MAX 31
2920 #define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
30
-
31
-#define PERIPHERAL_RSHIFT_MASK 0x3
32
-#define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK)
3321
3422 #define PERIPHERAL_MAX_SHIFT 3
3523
....@@ -48,7 +36,9 @@
4836 spinlock_t *lock;
4937 u32 id;
5038 u32 div;
39
+ const struct clk_pcr_layout *layout;
5140 bool auto_div;
41
+ int chg_pid;
5242 };
5343
5444 #define to_clk_sam9x5_peripheral(hw) \
....@@ -104,12 +94,12 @@
10494 .is_enabled = clk_peripheral_is_enabled,
10595 };
10696
107
-static struct clk_hw * __init
97
+struct clk_hw * __init
10898 at91_clk_register_peripheral(struct regmap *regmap, const char *name,
10999 const char *parent_name, u32 id)
110100 {
111101 struct clk_peripheral *periph;
112
- struct clk_init_data init = {};
102
+ struct clk_init_data init;
113103 struct clk_hw *hw;
114104 int ret;
115105
....@@ -122,8 +112,8 @@
122112
123113 init.name = name;
124114 init.ops = &peripheral_ops;
125
- init.parent_names = (parent_name ? &parent_name : NULL);
126
- init.num_parents = (parent_name ? 1 : 0);
115
+ init.parent_names = &parent_name;
116
+ init.num_parents = 1;
127117 init.flags = 0;
128118
129119 periph->id = id;
....@@ -174,13 +164,13 @@
174164 return 0;
175165
176166 spin_lock_irqsave(periph->lock, flags);
177
- regmap_write(periph->regmap, AT91_PMC_PCR,
178
- (periph->id & AT91_PMC_PCR_PID_MASK));
179
- regmap_update_bits(periph->regmap, AT91_PMC_PCR,
180
- AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD |
167
+ regmap_write(periph->regmap, periph->layout->offset,
168
+ (periph->id & periph->layout->pid_mask));
169
+ regmap_update_bits(periph->regmap, periph->layout->offset,
170
+ periph->layout->div_mask | periph->layout->cmd |
181171 AT91_PMC_PCR_EN,
182
- AT91_PMC_PCR_DIV(periph->div) |
183
- AT91_PMC_PCR_CMD |
172
+ field_prep(periph->layout->div_mask, periph->div) |
173
+ periph->layout->cmd |
184174 AT91_PMC_PCR_EN);
185175 spin_unlock_irqrestore(periph->lock, flags);
186176
....@@ -196,11 +186,11 @@
196186 return;
197187
198188 spin_lock_irqsave(periph->lock, flags);
199
- regmap_write(periph->regmap, AT91_PMC_PCR,
200
- (periph->id & AT91_PMC_PCR_PID_MASK));
201
- regmap_update_bits(periph->regmap, AT91_PMC_PCR,
202
- AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD,
203
- AT91_PMC_PCR_CMD);
189
+ regmap_write(periph->regmap, periph->layout->offset,
190
+ (periph->id & periph->layout->pid_mask));
191
+ regmap_update_bits(periph->regmap, periph->layout->offset,
192
+ AT91_PMC_PCR_EN | periph->layout->cmd,
193
+ periph->layout->cmd);
204194 spin_unlock_irqrestore(periph->lock, flags);
205195 }
206196
....@@ -214,12 +204,12 @@
214204 return 1;
215205
216206 spin_lock_irqsave(periph->lock, flags);
217
- regmap_write(periph->regmap, AT91_PMC_PCR,
218
- (periph->id & AT91_PMC_PCR_PID_MASK));
219
- regmap_read(periph->regmap, AT91_PMC_PCR, &status);
207
+ regmap_write(periph->regmap, periph->layout->offset,
208
+ (periph->id & periph->layout->pid_mask));
209
+ regmap_read(periph->regmap, periph->layout->offset, &status);
220210 spin_unlock_irqrestore(periph->lock, flags);
221211
222
- return status & AT91_PMC_PCR_EN ? 1 : 0;
212
+ return !!(status & AT91_PMC_PCR_EN);
223213 }
224214
225215 static unsigned long
....@@ -234,19 +224,100 @@
234224 return parent_rate;
235225
236226 spin_lock_irqsave(periph->lock, flags);
237
- regmap_write(periph->regmap, AT91_PMC_PCR,
238
- (periph->id & AT91_PMC_PCR_PID_MASK));
239
- regmap_read(periph->regmap, AT91_PMC_PCR, &status);
227
+ regmap_write(periph->regmap, periph->layout->offset,
228
+ (periph->id & periph->layout->pid_mask));
229
+ regmap_read(periph->regmap, periph->layout->offset, &status);
240230 spin_unlock_irqrestore(periph->lock, flags);
241231
242232 if (status & AT91_PMC_PCR_EN) {
243
- periph->div = PERIPHERAL_RSHIFT(status);
233
+ periph->div = field_get(periph->layout->div_mask, status);
244234 periph->auto_div = false;
245235 } else {
246236 clk_sam9x5_peripheral_autodiv(periph);
247237 }
248238
249239 return parent_rate >> periph->div;
240
+}
241
+
242
+static void clk_sam9x5_peripheral_best_diff(struct clk_rate_request *req,
243
+ struct clk_hw *parent,
244
+ unsigned long parent_rate,
245
+ u32 shift, long *best_diff,
246
+ long *best_rate)
247
+{
248
+ unsigned long tmp_rate = parent_rate >> shift;
249
+ unsigned long tmp_diff = abs(req->rate - tmp_rate);
250
+
251
+ if (*best_diff < 0 || *best_diff >= tmp_diff) {
252
+ *best_rate = tmp_rate;
253
+ *best_diff = tmp_diff;
254
+ req->best_parent_rate = parent_rate;
255
+ req->best_parent_hw = parent;
256
+ }
257
+}
258
+
259
+static int clk_sam9x5_peripheral_determine_rate(struct clk_hw *hw,
260
+ struct clk_rate_request *req)
261
+{
262
+ struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
263
+ struct clk_hw *parent = clk_hw_get_parent(hw);
264
+ struct clk_rate_request req_parent = *req;
265
+ unsigned long parent_rate = clk_hw_get_rate(parent);
266
+ unsigned long tmp_rate;
267
+ long best_rate = LONG_MIN;
268
+ long best_diff = LONG_MIN;
269
+ u32 shift;
270
+
271
+ if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max)
272
+ return parent_rate;
273
+
274
+ /* Fist step: check the available dividers. */
275
+ for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
276
+ tmp_rate = parent_rate >> shift;
277
+
278
+ if (periph->range.max && tmp_rate > periph->range.max)
279
+ continue;
280
+
281
+ clk_sam9x5_peripheral_best_diff(req, parent, parent_rate,
282
+ shift, &best_diff, &best_rate);
283
+
284
+ if (!best_diff || best_rate <= req->rate)
285
+ break;
286
+ }
287
+
288
+ if (periph->chg_pid < 0)
289
+ goto end;
290
+
291
+ /* Step two: try to request rate from parent. */
292
+ parent = clk_hw_get_parent_by_index(hw, periph->chg_pid);
293
+ if (!parent)
294
+ goto end;
295
+
296
+ for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
297
+ req_parent.rate = req->rate << shift;
298
+
299
+ if (__clk_determine_rate(parent, &req_parent))
300
+ continue;
301
+
302
+ clk_sam9x5_peripheral_best_diff(req, parent, req_parent.rate,
303
+ shift, &best_diff, &best_rate);
304
+
305
+ if (!best_diff)
306
+ break;
307
+ }
308
+end:
309
+ if (best_rate < 0 ||
310
+ (periph->range.max && best_rate > periph->range.max))
311
+ return -EINVAL;
312
+
313
+ pr_debug("PCK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
314
+ __func__, best_rate,
315
+ __clk_get_name((req->best_parent_hw)->clk),
316
+ req->best_parent_rate);
317
+
318
+ req->rate = best_rate;
319
+
320
+ return 0;
250321 }
251322
252323 static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
....@@ -331,13 +402,24 @@
331402 .set_rate = clk_sam9x5_peripheral_set_rate,
332403 };
333404
334
-static struct clk_hw * __init
405
+static const struct clk_ops sam9x5_peripheral_chg_ops = {
406
+ .enable = clk_sam9x5_peripheral_enable,
407
+ .disable = clk_sam9x5_peripheral_disable,
408
+ .is_enabled = clk_sam9x5_peripheral_is_enabled,
409
+ .recalc_rate = clk_sam9x5_peripheral_recalc_rate,
410
+ .determine_rate = clk_sam9x5_peripheral_determine_rate,
411
+ .set_rate = clk_sam9x5_peripheral_set_rate,
412
+};
413
+
414
+struct clk_hw * __init
335415 at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
416
+ const struct clk_pcr_layout *layout,
336417 const char *name, const char *parent_name,
337
- u32 id, const struct clk_range *range)
418
+ u32 id, const struct clk_range *range,
419
+ int chg_pid)
338420 {
339421 struct clk_sam9x5_peripheral *periph;
340
- struct clk_init_data init = {};
422
+ struct clk_init_data init;
341423 struct clk_hw *hw;
342424 int ret;
343425
....@@ -349,18 +431,27 @@
349431 return ERR_PTR(-ENOMEM);
350432
351433 init.name = name;
352
- init.ops = &sam9x5_peripheral_ops;
353
- init.parent_names = (parent_name ? &parent_name : NULL);
354
- init.num_parents = (parent_name ? 1 : 0);
355
- init.flags = 0;
434
+ init.parent_names = &parent_name;
435
+ init.num_parents = 1;
436
+ if (chg_pid < 0) {
437
+ init.flags = 0;
438
+ init.ops = &sam9x5_peripheral_ops;
439
+ } else {
440
+ init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
441
+ CLK_SET_RATE_PARENT;
442
+ init.ops = &sam9x5_peripheral_chg_ops;
443
+ }
356444
357445 periph->id = id;
358446 periph->hw.init = &init;
359447 periph->div = 0;
360448 periph->regmap = regmap;
361449 periph->lock = lock;
362
- periph->auto_div = true;
450
+ if (layout->div_mask)
451
+ periph->auto_div = true;
452
+ periph->layout = layout;
363453 periph->range = *range;
454
+ periph->chg_pid = chg_pid;
364455
365456 hw = &periph->hw;
366457 ret = clk_hw_register(NULL, &periph->hw);
....@@ -374,75 +465,3 @@
374465
375466 return hw;
376467 }
377
-
378
-static void __init
379
-of_at91_clk_periph_setup(struct device_node *np, u8 type)
380
-{
381
- int num;
382
- u32 id;
383
- struct clk_hw *hw;
384
- const char *parent_name;
385
- const char *name;
386
- struct device_node *periphclknp;
387
- struct regmap *regmap;
388
-
389
- parent_name = of_clk_get_parent_name(np, 0);
390
- if (!parent_name)
391
- return;
392
-
393
- num = of_get_child_count(np);
394
- if (!num || num > PERIPHERAL_MAX)
395
- return;
396
-
397
- regmap = syscon_node_to_regmap(of_get_parent(np));
398
- if (IS_ERR(regmap))
399
- return;
400
-
401
- for_each_child_of_node(np, periphclknp) {
402
- if (of_property_read_u32(periphclknp, "reg", &id))
403
- continue;
404
-
405
- if (id >= PERIPHERAL_MAX)
406
- continue;
407
-
408
- if (of_property_read_string(np, "clock-output-names", &name))
409
- name = periphclknp->name;
410
-
411
- if (type == PERIPHERAL_AT91RM9200) {
412
- hw = at91_clk_register_peripheral(regmap, name,
413
- parent_name, id);
414
- } else {
415
- struct clk_range range = CLK_RANGE(0, 0);
416
-
417
- of_at91_get_clk_range(periphclknp,
418
- "atmel,clk-output-range",
419
- &range);
420
-
421
- hw = at91_clk_register_sam9x5_peripheral(regmap,
422
- &pmc_pcr_lock,
423
- name,
424
- parent_name,
425
- id, &range);
426
- }
427
-
428
- if (IS_ERR(hw))
429
- continue;
430
-
431
- of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw);
432
- }
433
-}
434
-
435
-static void __init of_at91rm9200_clk_periph_setup(struct device_node *np)
436
-{
437
- of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200);
438
-}
439
-CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral",
440
- of_at91rm9200_clk_periph_setup);
441
-
442
-static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np)
443
-{
444
- of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5);
445
-}
446
-CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral",
447
- of_at91sam9x5_clk_periph_setup);
448
-