17
17
#define MASTER_DIV_SHIFT 8
18
18
#define MASTER_DIV_MASK 0x3
19
19
20
+ #define PMC_MCR 0x30
21
+ #define PMC_MCR_ID_MSK GENMASK(3, 0)
22
+ #define PMC_MCR_CMD BIT(7)
23
+ #define PMC_MCR_DIV GENMASK(10, 8)
24
+ #define PMC_MCR_CSS GENMASK(20, 16)
25
+ #define PMC_MCR_CSS_SHIFT (16)
26
+ #define PMC_MCR_EN BIT(28)
27
+
28
+ #define PMC_MCR_ID (x ) ((x) & PMC_MCR_ID_MSK)
29
+
30
+ #define MASTER_MAX_ID 4
31
+
20
32
#define to_clk_master (hw ) container_of(hw, struct clk_master, hw)
21
33
22
34
struct clk_master {
23
35
struct clk_hw hw ;
24
36
struct regmap * regmap ;
37
+ spinlock_t * lock ;
25
38
const struct clk_master_layout * layout ;
26
39
const struct clk_master_characteristics * characteristics ;
40
+ u32 * mux_table ;
27
41
u32 mckr ;
42
+ int chg_pid ;
43
+ u8 id ;
44
+ u8 parent ;
45
+ u8 div ;
28
46
};
29
47
30
- static inline bool clk_master_ready (struct regmap * regmap )
48
+ static inline bool clk_master_ready (struct clk_master * master )
31
49
{
50
+ unsigned int bit = master -> id ? AT91_PMC_MCKXRDY : AT91_PMC_MCKRDY ;
32
51
unsigned int status ;
33
52
34
- regmap_read (regmap , AT91_PMC_SR , & status );
53
+ regmap_read (master -> regmap , AT91_PMC_SR , & status );
35
54
36
- return !!(status & AT91_PMC_MCKRDY );
55
+ return !!(status & bit );
37
56
}
38
57
39
58
static int clk_master_prepare (struct clk_hw * hw )
40
59
{
41
60
struct clk_master * master = to_clk_master (hw );
42
61
43
- while (!clk_master_ready (master -> regmap ))
62
+ while (!clk_master_ready (master ))
44
63
cpu_relax ();
45
64
46
65
return 0 ;
@@ -50,7 +69,7 @@ static int clk_master_is_prepared(struct clk_hw *hw)
50
69
{
51
70
struct clk_master * master = to_clk_master (hw );
52
71
53
- return clk_master_ready (master -> regmap );
72
+ return clk_master_ready (master );
54
73
}
55
74
56
75
static unsigned long clk_master_recalc_rate (struct clk_hw * hw ,
@@ -143,6 +162,287 @@ at91_clk_register_master(struct regmap *regmap,
143
162
return hw ;
144
163
}
145
164
165
+ static unsigned long
166
+ clk_sama7g5_master_recalc_rate (struct clk_hw * hw ,
167
+ unsigned long parent_rate )
168
+ {
169
+ struct clk_master * master = to_clk_master (hw );
170
+
171
+ return DIV_ROUND_CLOSEST_ULL (parent_rate , (1 << master -> div ));
172
+ }
173
+
174
+ static void clk_sama7g5_master_best_diff (struct clk_rate_request * req ,
175
+ struct clk_hw * parent ,
176
+ unsigned long parent_rate ,
177
+ long * best_rate ,
178
+ long * best_diff ,
179
+ u32 div )
180
+ {
181
+ unsigned long tmp_rate , tmp_diff ;
182
+
183
+ if (div == MASTER_PRES_MAX )
184
+ tmp_rate = parent_rate / 3 ;
185
+ else
186
+ tmp_rate = parent_rate >> div ;
187
+
188
+ tmp_diff = abs (req -> rate - tmp_rate );
189
+
190
+ if (* best_diff < 0 || * best_diff >= tmp_diff ) {
191
+ * best_rate = tmp_rate ;
192
+ * best_diff = tmp_diff ;
193
+ req -> best_parent_rate = parent_rate ;
194
+ req -> best_parent_hw = parent ;
195
+ }
196
+ }
197
+
198
+ static int clk_sama7g5_master_determine_rate (struct clk_hw * hw ,
199
+ struct clk_rate_request * req )
200
+ {
201
+ struct clk_master * master = to_clk_master (hw );
202
+ struct clk_rate_request req_parent = * req ;
203
+ struct clk_hw * parent ;
204
+ long best_rate = LONG_MIN , best_diff = LONG_MIN ;
205
+ unsigned long parent_rate ;
206
+ unsigned int div , i ;
207
+
208
+ /* First: check the dividers of MCR. */
209
+ for (i = 0 ; i < clk_hw_get_num_parents (hw ); i ++ ) {
210
+ parent = clk_hw_get_parent_by_index (hw , i );
211
+ if (!parent )
212
+ continue ;
213
+
214
+ parent_rate = clk_hw_get_rate (parent );
215
+ if (!parent_rate )
216
+ continue ;
217
+
218
+ for (div = 0 ; div < MASTER_PRES_MAX + 1 ; div ++ ) {
219
+ clk_sama7g5_master_best_diff (req , parent , parent_rate ,
220
+ & best_rate , & best_diff ,
221
+ div );
222
+ if (!best_diff )
223
+ break ;
224
+ }
225
+
226
+ if (!best_diff )
227
+ break ;
228
+ }
229
+
230
+ /* Second: try to request rate form changeable parent. */
231
+ if (master -> chg_pid < 0 )
232
+ goto end ;
233
+
234
+ parent = clk_hw_get_parent_by_index (hw , master -> chg_pid );
235
+ if (!parent )
236
+ goto end ;
237
+
238
+ for (div = 0 ; div < MASTER_PRES_MAX + 1 ; div ++ ) {
239
+ if (div == MASTER_PRES_MAX )
240
+ req_parent .rate = req -> rate * 3 ;
241
+ else
242
+ req_parent .rate = req -> rate << div ;
243
+
244
+ if (__clk_determine_rate (parent , & req_parent ))
245
+ continue ;
246
+
247
+ clk_sama7g5_master_best_diff (req , parent , req_parent .rate ,
248
+ & best_rate , & best_diff , div );
249
+
250
+ if (!best_diff )
251
+ break ;
252
+ }
253
+
254
+ end :
255
+ pr_debug ("MCK: %s, best_rate = %ld, parent clk: %s @ %ld\n" ,
256
+ __func__ , best_rate ,
257
+ __clk_get_name ((req -> best_parent_hw )-> clk ),
258
+ req -> best_parent_rate );
259
+
260
+ if (best_rate < 0 )
261
+ return - EINVAL ;
262
+
263
+ req -> rate = best_rate ;
264
+
265
+ return 0 ;
266
+ }
267
+
268
+ static u8 clk_sama7g5_master_get_parent (struct clk_hw * hw )
269
+ {
270
+ struct clk_master * master = to_clk_master (hw );
271
+ unsigned long flags ;
272
+ u8 index ;
273
+
274
+ spin_lock_irqsave (master -> lock , flags );
275
+ index = clk_mux_val_to_index (& master -> hw , master -> mux_table , 0 ,
276
+ master -> parent );
277
+ spin_unlock_irqrestore (master -> lock , flags );
278
+
279
+ return index ;
280
+ }
281
+
282
+ static int clk_sama7g5_master_set_parent (struct clk_hw * hw , u8 index )
283
+ {
284
+ struct clk_master * master = to_clk_master (hw );
285
+ unsigned long flags ;
286
+
287
+ if (index >= clk_hw_get_num_parents (hw ))
288
+ return - EINVAL ;
289
+
290
+ spin_lock_irqsave (master -> lock , flags );
291
+ master -> parent = clk_mux_index_to_val (master -> mux_table , 0 , index );
292
+ spin_unlock_irqrestore (master -> lock , flags );
293
+
294
+ return 0 ;
295
+ }
296
+
297
+ static int clk_sama7g5_master_enable (struct clk_hw * hw )
298
+ {
299
+ struct clk_master * master = to_clk_master (hw );
300
+ unsigned long flags ;
301
+ unsigned int val , cparent ;
302
+
303
+ spin_lock_irqsave (master -> lock , flags );
304
+
305
+ regmap_write (master -> regmap , PMC_MCR , PMC_MCR_ID (master -> id ));
306
+ regmap_read (master -> regmap , PMC_MCR , & val );
307
+ regmap_update_bits (master -> regmap , PMC_MCR ,
308
+ PMC_MCR_EN | PMC_MCR_CSS | PMC_MCR_DIV |
309
+ PMC_MCR_CMD | PMC_MCR_ID_MSK ,
310
+ PMC_MCR_EN | (master -> parent << PMC_MCR_CSS_SHIFT ) |
311
+ (master -> div << MASTER_DIV_SHIFT ) |
312
+ PMC_MCR_CMD | PMC_MCR_ID (master -> id ));
313
+
314
+ cparent = (val & PMC_MCR_CSS ) >> PMC_MCR_CSS_SHIFT ;
315
+
316
+ /* Wait here only if parent is being changed. */
317
+ while ((cparent != master -> parent ) && !clk_master_ready (master ))
318
+ cpu_relax ();
319
+
320
+ spin_unlock_irqrestore (master -> lock , flags );
321
+
322
+ return 0 ;
323
+ }
324
+
325
+ static void clk_sama7g5_master_disable (struct clk_hw * hw )
326
+ {
327
+ struct clk_master * master = to_clk_master (hw );
328
+ unsigned long flags ;
329
+
330
+ spin_lock_irqsave (master -> lock , flags );
331
+
332
+ regmap_write (master -> regmap , PMC_MCR , master -> id );
333
+ regmap_update_bits (master -> regmap , PMC_MCR ,
334
+ PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID_MSK ,
335
+ PMC_MCR_CMD | PMC_MCR_ID (master -> id ));
336
+
337
+ spin_unlock_irqrestore (master -> lock , flags );
338
+ }
339
+
340
+ static int clk_sama7g5_master_is_enabled (struct clk_hw * hw )
341
+ {
342
+ struct clk_master * master = to_clk_master (hw );
343
+ unsigned long flags ;
344
+ unsigned int val ;
345
+
346
+ spin_lock_irqsave (master -> lock , flags );
347
+
348
+ regmap_write (master -> regmap , PMC_MCR , master -> id );
349
+ regmap_read (master -> regmap , PMC_MCR , & val );
350
+
351
+ spin_unlock_irqrestore (master -> lock , flags );
352
+
353
+ return !!(val & PMC_MCR_EN );
354
+ }
355
+
356
+ static int clk_sama7g5_master_set_rate (struct clk_hw * hw , unsigned long rate ,
357
+ unsigned long parent_rate )
358
+ {
359
+ struct clk_master * master = to_clk_master (hw );
360
+ unsigned long div , flags ;
361
+
362
+ div = DIV_ROUND_CLOSEST (parent_rate , rate );
363
+ if ((div > (1 << (MASTER_PRES_MAX - 1 ))) || (div & (div - 1 )))
364
+ return - EINVAL ;
365
+
366
+ if (div == 3 )
367
+ div = MASTER_PRES_MAX ;
368
+ else
369
+ div = ffs (div ) - 1 ;
370
+
371
+ spin_lock_irqsave (master -> lock , flags );
372
+ master -> div = div ;
373
+ spin_unlock_irqrestore (master -> lock , flags );
374
+
375
+ return 0 ;
376
+ }
377
+
378
+ static const struct clk_ops sama7g5_master_ops = {
379
+ .enable = clk_sama7g5_master_enable ,
380
+ .disable = clk_sama7g5_master_disable ,
381
+ .is_enabled = clk_sama7g5_master_is_enabled ,
382
+ .recalc_rate = clk_sama7g5_master_recalc_rate ,
383
+ .determine_rate = clk_sama7g5_master_determine_rate ,
384
+ .set_rate = clk_sama7g5_master_set_rate ,
385
+ .get_parent = clk_sama7g5_master_get_parent ,
386
+ .set_parent = clk_sama7g5_master_set_parent ,
387
+ };
388
+
389
+ struct clk_hw * __init
390
+ at91_clk_sama7g5_register_master (struct regmap * regmap ,
391
+ const char * name , int num_parents ,
392
+ const char * * parent_names ,
393
+ u32 * mux_table ,
394
+ spinlock_t * lock , u8 id ,
395
+ bool critical , int chg_pid )
396
+ {
397
+ struct clk_master * master ;
398
+ struct clk_hw * hw ;
399
+ struct clk_init_data init ;
400
+ unsigned long flags ;
401
+ unsigned int val ;
402
+ int ret ;
403
+
404
+ if (!name || !num_parents || !parent_names || !mux_table ||
405
+ !lock || id > MASTER_MAX_ID )
406
+ return ERR_PTR (- EINVAL );
407
+
408
+ master = kzalloc (sizeof (* master ), GFP_KERNEL );
409
+ if (!master )
410
+ return ERR_PTR (- ENOMEM );
411
+
412
+ init .name = name ;
413
+ init .ops = & sama7g5_master_ops ;
414
+ init .parent_names = parent_names ;
415
+ init .num_parents = num_parents ;
416
+ init .flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE ;
417
+ if (chg_pid >= 0 )
418
+ init .flags |= CLK_SET_RATE_PARENT ;
419
+ if (critical )
420
+ init .flags |= CLK_IS_CRITICAL ;
421
+
422
+ master -> hw .init = & init ;
423
+ master -> regmap = regmap ;
424
+ master -> id = id ;
425
+ master -> chg_pid = chg_pid ;
426
+ master -> lock = lock ;
427
+ master -> mux_table = mux_table ;
428
+
429
+ spin_lock_irqsave (master -> lock , flags );
430
+ regmap_write (master -> regmap , PMC_MCR , master -> id );
431
+ regmap_read (master -> regmap , PMC_MCR , & val );
432
+ master -> parent = (val & PMC_MCR_CSS ) >> PMC_MCR_CSS_SHIFT ;
433
+ master -> div = (val & PMC_MCR_DIV ) >> MASTER_DIV_SHIFT ;
434
+ spin_unlock_irqrestore (master -> lock , flags );
435
+
436
+ hw = & master -> hw ;
437
+ ret = clk_hw_register (NULL , & master -> hw );
438
+ if (ret ) {
439
+ kfree (master );
440
+ hw = ERR_PTR (ret );
441
+ }
442
+
443
+ return hw ;
444
+ }
445
+
146
446
const struct clk_master_layout at91rm9200_master_layout = {
147
447
.mask = 0x31F ,
148
448
.pres_shift = 2 ,
0 commit comments