Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm/mach-omap1/clock.c
26292 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* linux/arch/arm/mach-omap1/clock.c
4
*
5
* Copyright (C) 2004 - 2005, 2009-2010 Nokia Corporation
6
* Written by Tuukka Tikkanen <[email protected]>
7
*
8
* Modified to use omap shared clock framework by
9
* Tony Lindgren <[email protected]>
10
*/
11
#include <linux/kernel.h>
12
#include <linux/export.h>
13
#include <linux/list.h>
14
#include <linux/errno.h>
15
#include <linux/err.h>
16
#include <linux/io.h>
17
#include <linux/clk.h>
18
#include <linux/clkdev.h>
19
#include <linux/clk-provider.h>
20
#include <linux/soc/ti/omap1-io.h>
21
#include <linux/spinlock.h>
22
23
#include <asm/mach-types.h>
24
25
#include "hardware.h"
26
#include "soc.h"
27
#include "iomap.h"
28
#include "clock.h"
29
#include "opp.h"
30
#include "sram.h"
31
32
__u32 arm_idlect1_mask;
33
/* provide direct internal access (not via clk API) to some clocks */
34
struct omap1_clk *api_ck_p, *ck_dpll1_p, *ck_ref_p;
35
36
/* protect registeres shared among clk_enable/disable() and clk_set_rate() operations */
37
static DEFINE_SPINLOCK(arm_ckctl_lock);
38
static DEFINE_SPINLOCK(arm_idlect2_lock);
39
static DEFINE_SPINLOCK(mod_conf_ctrl_0_lock);
40
static DEFINE_SPINLOCK(mod_conf_ctrl_1_lock);
41
static DEFINE_SPINLOCK(swd_clk_div_ctrl_sel_lock);
42
43
/*
44
* Omap1 specific clock functions
45
*/
46
47
unsigned long omap1_uart_recalc(struct omap1_clk *clk, unsigned long p_rate)
48
{
49
unsigned int val = __raw_readl(clk->enable_reg);
50
return val & 1 << clk->enable_bit ? 48000000 : 12000000;
51
}
52
53
unsigned long omap1_sossi_recalc(struct omap1_clk *clk, unsigned long p_rate)
54
{
55
u32 div = omap_readl(MOD_CONF_CTRL_1);
56
57
div = (div >> 17) & 0x7;
58
div++;
59
60
return p_rate / div;
61
}
62
63
static void omap1_clk_allow_idle(struct omap1_clk *clk)
64
{
65
struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk;
66
67
if (!(clk->flags & CLOCK_IDLE_CONTROL))
68
return;
69
70
if (iclk->no_idle_count > 0 && !(--iclk->no_idle_count))
71
arm_idlect1_mask |= 1 << iclk->idlect_shift;
72
}
73
74
static void omap1_clk_deny_idle(struct omap1_clk *clk)
75
{
76
struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk;
77
78
if (!(clk->flags & CLOCK_IDLE_CONTROL))
79
return;
80
81
if (iclk->no_idle_count++ == 0)
82
arm_idlect1_mask &= ~(1 << iclk->idlect_shift);
83
}
84
85
static __u16 verify_ckctl_value(__u16 newval)
86
{
87
/* This function checks for following limitations set
88
* by the hardware (all conditions must be true):
89
* DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2
90
* ARM_CK >= TC_CK
91
* DSP_CK >= TC_CK
92
* DSPMMU_CK >= TC_CK
93
*
94
* In addition following rules are enforced:
95
* LCD_CK <= TC_CK
96
* ARMPER_CK <= TC_CK
97
*
98
* However, maximum frequencies are not checked for!
99
*/
100
__u8 per_exp;
101
__u8 lcd_exp;
102
__u8 arm_exp;
103
__u8 dsp_exp;
104
__u8 tc_exp;
105
__u8 dspmmu_exp;
106
107
per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3;
108
lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3;
109
arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3;
110
dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3;
111
tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3;
112
dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3;
113
114
if (dspmmu_exp < dsp_exp)
115
dspmmu_exp = dsp_exp;
116
if (dspmmu_exp > dsp_exp+1)
117
dspmmu_exp = dsp_exp+1;
118
if (tc_exp < arm_exp)
119
tc_exp = arm_exp;
120
if (tc_exp < dspmmu_exp)
121
tc_exp = dspmmu_exp;
122
if (tc_exp > lcd_exp)
123
lcd_exp = tc_exp;
124
if (tc_exp > per_exp)
125
per_exp = tc_exp;
126
127
newval &= 0xf000;
128
newval |= per_exp << CKCTL_PERDIV_OFFSET;
129
newval |= lcd_exp << CKCTL_LCDDIV_OFFSET;
130
newval |= arm_exp << CKCTL_ARMDIV_OFFSET;
131
newval |= dsp_exp << CKCTL_DSPDIV_OFFSET;
132
newval |= tc_exp << CKCTL_TCDIV_OFFSET;
133
newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET;
134
135
return newval;
136
}
137
138
static int calc_dsor_exp(unsigned long rate, unsigned long realrate)
139
{
140
/* Note: If target frequency is too low, this function will return 4,
141
* which is invalid value. Caller must check for this value and act
142
* accordingly.
143
*
144
* Note: This function does not check for following limitations set
145
* by the hardware (all conditions must be true):
146
* DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2
147
* ARM_CK >= TC_CK
148
* DSP_CK >= TC_CK
149
* DSPMMU_CK >= TC_CK
150
*/
151
unsigned dsor_exp;
152
153
if (unlikely(realrate == 0))
154
return -EIO;
155
156
for (dsor_exp=0; dsor_exp<4; dsor_exp++) {
157
if (realrate <= rate)
158
break;
159
160
realrate /= 2;
161
}
162
163
return dsor_exp;
164
}
165
166
unsigned long omap1_ckctl_recalc(struct omap1_clk *clk, unsigned long p_rate)
167
{
168
/* Calculate divisor encoded as 2-bit exponent */
169
int dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
170
171
/* update locally maintained rate, required by arm_ck for omap1_show_rates() */
172
clk->rate = p_rate / dsor;
173
return clk->rate;
174
}
175
176
static int omap1_clk_is_enabled(struct clk_hw *hw)
177
{
178
struct omap1_clk *clk = to_omap1_clk(hw);
179
bool api_ck_was_enabled = true;
180
__u32 regval32;
181
int ret;
182
183
if (!clk->ops) /* no gate -- always enabled */
184
return 1;
185
186
if (clk->ops == &clkops_dspck) {
187
api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw);
188
if (!api_ck_was_enabled)
189
if (api_ck_p->ops->enable(api_ck_p) < 0)
190
return 0;
191
}
192
193
if (clk->flags & ENABLE_REG_32BIT)
194
regval32 = __raw_readl(clk->enable_reg);
195
else
196
regval32 = __raw_readw(clk->enable_reg);
197
198
ret = regval32 & (1 << clk->enable_bit);
199
200
if (!api_ck_was_enabled)
201
api_ck_p->ops->disable(api_ck_p);
202
203
return ret;
204
}
205
206
207
unsigned long omap1_ckctl_recalc_dsp_domain(struct omap1_clk *clk, unsigned long p_rate)
208
{
209
bool api_ck_was_enabled;
210
int dsor;
211
212
/* Calculate divisor encoded as 2-bit exponent
213
*
214
* The clock control bits are in DSP domain,
215
* so api_ck is needed for access.
216
* Note that DSP_CKCTL virt addr = phys addr, so
217
* we must use __raw_readw() instead of omap_readw().
218
*/
219
api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw);
220
if (!api_ck_was_enabled)
221
api_ck_p->ops->enable(api_ck_p);
222
dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
223
if (!api_ck_was_enabled)
224
api_ck_p->ops->disable(api_ck_p);
225
226
return p_rate / dsor;
227
}
228
229
/* MPU virtual clock functions */
230
int omap1_select_table_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate)
231
{
232
/* Find the highest supported frequency <= rate and switch to it */
233
struct mpu_rate * ptr;
234
unsigned long ref_rate;
235
236
ref_rate = ck_ref_p->rate;
237
238
for (ptr = omap1_rate_table; ptr->rate; ptr++) {
239
if (!(ptr->flags & cpu_mask))
240
continue;
241
242
if (ptr->xtal != ref_rate)
243
continue;
244
245
/* Can check only after xtal frequency check */
246
if (ptr->rate <= rate)
247
break;
248
}
249
250
if (!ptr->rate)
251
return -EINVAL;
252
253
/*
254
* In most cases we should not need to reprogram DPLL.
255
* Reprogramming the DPLL is tricky, it must be done from SRAM.
256
*/
257
omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
258
259
/* XXX Do we need to recalculate the tree below DPLL1 at this point? */
260
ck_dpll1_p->rate = ptr->pll_rate;
261
262
return 0;
263
}
264
265
int omap1_clk_set_rate_dsp_domain(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate)
266
{
267
int dsor_exp;
268
u16 regval;
269
270
dsor_exp = calc_dsor_exp(rate, p_rate);
271
if (dsor_exp > 3)
272
dsor_exp = -EINVAL;
273
if (dsor_exp < 0)
274
return dsor_exp;
275
276
regval = __raw_readw(DSP_CKCTL);
277
regval &= ~(3 << clk->rate_offset);
278
regval |= dsor_exp << clk->rate_offset;
279
__raw_writew(regval, DSP_CKCTL);
280
clk->rate = p_rate / (1 << dsor_exp);
281
282
return 0;
283
}
284
285
long omap1_clk_round_rate_ckctl_arm(struct omap1_clk *clk, unsigned long rate,
286
unsigned long *p_rate)
287
{
288
int dsor_exp = calc_dsor_exp(rate, *p_rate);
289
290
if (dsor_exp < 0)
291
return dsor_exp;
292
if (dsor_exp > 3)
293
dsor_exp = 3;
294
return *p_rate / (1 << dsor_exp);
295
}
296
297
int omap1_clk_set_rate_ckctl_arm(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate)
298
{
299
unsigned long flags;
300
int dsor_exp;
301
u16 regval;
302
303
dsor_exp = calc_dsor_exp(rate, p_rate);
304
if (dsor_exp > 3)
305
dsor_exp = -EINVAL;
306
if (dsor_exp < 0)
307
return dsor_exp;
308
309
/* protect ARM_CKCTL register from concurrent access via clk_enable/disable() */
310
spin_lock_irqsave(&arm_ckctl_lock, flags);
311
312
regval = omap_readw(ARM_CKCTL);
313
regval &= ~(3 << clk->rate_offset);
314
regval |= dsor_exp << clk->rate_offset;
315
regval = verify_ckctl_value(regval);
316
omap_writew(regval, ARM_CKCTL);
317
clk->rate = p_rate / (1 << dsor_exp);
318
319
spin_unlock_irqrestore(&arm_ckctl_lock, flags);
320
321
return 0;
322
}
323
324
long omap1_round_to_table_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate)
325
{
326
/* Find the highest supported frequency <= rate */
327
struct mpu_rate * ptr;
328
long highest_rate;
329
unsigned long ref_rate;
330
331
ref_rate = ck_ref_p->rate;
332
333
highest_rate = -EINVAL;
334
335
for (ptr = omap1_rate_table; ptr->rate; ptr++) {
336
if (!(ptr->flags & cpu_mask))
337
continue;
338
339
if (ptr->xtal != ref_rate)
340
continue;
341
342
highest_rate = ptr->rate;
343
344
/* Can check only after xtal frequency check */
345
if (ptr->rate <= rate)
346
break;
347
}
348
349
return highest_rate;
350
}
351
352
static unsigned calc_ext_dsor(unsigned long rate)
353
{
354
unsigned dsor;
355
356
/* MCLK and BCLK divisor selection is not linear:
357
* freq = 96MHz / dsor
358
*
359
* RATIO_SEL range: dsor <-> RATIO_SEL
360
* 0..6: (RATIO_SEL+2) <-> (dsor-2)
361
* 6..48: (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6)
362
* Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9
363
* can not be used.
364
*/
365
for (dsor = 2; dsor < 96; ++dsor) {
366
if ((dsor & 1) && dsor > 8)
367
continue;
368
if (rate >= 96000000 / dsor)
369
break;
370
}
371
return dsor;
372
}
373
374
/* XXX Only needed on 1510 */
375
long omap1_round_uart_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate)
376
{
377
return rate > 24000000 ? 48000000 : 12000000;
378
}
379
380
int omap1_set_uart_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate)
381
{
382
unsigned long flags;
383
unsigned int val;
384
385
if (rate == 12000000)
386
val = 0;
387
else if (rate == 48000000)
388
val = 1 << clk->enable_bit;
389
else
390
return -EINVAL;
391
392
/* protect MOD_CONF_CTRL_0 register from concurrent access via clk_enable/disable() */
393
spin_lock_irqsave(&mod_conf_ctrl_0_lock, flags);
394
395
val |= __raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit);
396
__raw_writel(val, clk->enable_reg);
397
398
spin_unlock_irqrestore(&mod_conf_ctrl_0_lock, flags);
399
400
clk->rate = rate;
401
402
return 0;
403
}
404
405
/* External clock (MCLK & BCLK) functions */
406
int omap1_set_ext_clk_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate)
407
{
408
unsigned long flags;
409
unsigned dsor;
410
__u16 ratio_bits;
411
412
dsor = calc_ext_dsor(rate);
413
clk->rate = 96000000 / dsor;
414
if (dsor > 8)
415
ratio_bits = ((dsor - 8) / 2 + 6) << 2;
416
else
417
ratio_bits = (dsor - 2) << 2;
418
419
/* protect SWD_CLK_DIV_CTRL_SEL register from concurrent access via clk_enable/disable() */
420
spin_lock_irqsave(&swd_clk_div_ctrl_sel_lock, flags);
421
422
ratio_bits |= __raw_readw(clk->enable_reg) & ~0xfd;
423
__raw_writew(ratio_bits, clk->enable_reg);
424
425
spin_unlock_irqrestore(&swd_clk_div_ctrl_sel_lock, flags);
426
427
return 0;
428
}
429
430
static int calc_div_sossi(unsigned long rate, unsigned long p_rate)
431
{
432
int div;
433
434
/* Round towards slower frequency */
435
div = (p_rate + rate - 1) / rate;
436
437
return --div;
438
}
439
440
long omap1_round_sossi_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate)
441
{
442
int div;
443
444
div = calc_div_sossi(rate, *p_rate);
445
if (div < 0)
446
div = 0;
447
else if (div > 7)
448
div = 7;
449
450
return *p_rate / (div + 1);
451
}
452
453
int omap1_set_sossi_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate)
454
{
455
unsigned long flags;
456
u32 l;
457
int div;
458
459
div = calc_div_sossi(rate, p_rate);
460
if (div < 0 || div > 7)
461
return -EINVAL;
462
463
/* protect MOD_CONF_CTRL_1 register from concurrent access via clk_enable/disable() */
464
spin_lock_irqsave(&mod_conf_ctrl_1_lock, flags);
465
466
l = omap_readl(MOD_CONF_CTRL_1);
467
l &= ~(7 << 17);
468
l |= div << 17;
469
omap_writel(l, MOD_CONF_CTRL_1);
470
471
clk->rate = p_rate / (div + 1);
472
473
spin_unlock_irqrestore(&mod_conf_ctrl_1_lock, flags);
474
475
return 0;
476
}
477
478
long omap1_round_ext_clk_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate)
479
{
480
return 96000000 / calc_ext_dsor(rate);
481
}
482
483
int omap1_init_ext_clk(struct omap1_clk *clk)
484
{
485
unsigned dsor;
486
__u16 ratio_bits;
487
488
/* Determine current rate and ensure clock is based on 96MHz APLL */
489
ratio_bits = __raw_readw(clk->enable_reg) & ~1;
490
__raw_writew(ratio_bits, clk->enable_reg);
491
492
ratio_bits = (ratio_bits & 0xfc) >> 2;
493
if (ratio_bits > 6)
494
dsor = (ratio_bits - 6) * 2 + 8;
495
else
496
dsor = ratio_bits + 2;
497
498
clk-> rate = 96000000 / dsor;
499
500
return 0;
501
}
502
503
static int omap1_clk_enable(struct clk_hw *hw)
504
{
505
struct omap1_clk *clk = to_omap1_clk(hw), *parent = to_omap1_clk(clk_hw_get_parent(hw));
506
int ret = 0;
507
508
if (parent && clk->flags & CLOCK_NO_IDLE_PARENT)
509
omap1_clk_deny_idle(parent);
510
511
if (clk->ops && !(WARN_ON(!clk->ops->enable)))
512
ret = clk->ops->enable(clk);
513
514
return ret;
515
}
516
517
static void omap1_clk_disable(struct clk_hw *hw)
518
{
519
struct omap1_clk *clk = to_omap1_clk(hw), *parent = to_omap1_clk(clk_hw_get_parent(hw));
520
521
if (clk->ops && !(WARN_ON(!clk->ops->disable)))
522
clk->ops->disable(clk);
523
524
if (likely(parent) && clk->flags & CLOCK_NO_IDLE_PARENT)
525
omap1_clk_allow_idle(parent);
526
}
527
528
static int omap1_clk_enable_generic(struct omap1_clk *clk)
529
{
530
unsigned long flags;
531
__u16 regval16;
532
__u32 regval32;
533
534
if (unlikely(clk->enable_reg == NULL)) {
535
printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
536
clk_hw_get_name(&clk->hw));
537
return -EINVAL;
538
}
539
540
/* protect clk->enable_reg from concurrent access via clk_set_rate() */
541
if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL))
542
spin_lock_irqsave(&arm_ckctl_lock, flags);
543
else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2))
544
spin_lock_irqsave(&arm_idlect2_lock, flags);
545
else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0))
546
spin_lock_irqsave(&mod_conf_ctrl_0_lock, flags);
547
else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1))
548
spin_lock_irqsave(&mod_conf_ctrl_1_lock, flags);
549
else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL))
550
spin_lock_irqsave(&swd_clk_div_ctrl_sel_lock, flags);
551
552
if (clk->flags & ENABLE_REG_32BIT) {
553
regval32 = __raw_readl(clk->enable_reg);
554
regval32 |= (1 << clk->enable_bit);
555
__raw_writel(regval32, clk->enable_reg);
556
} else {
557
regval16 = __raw_readw(clk->enable_reg);
558
regval16 |= (1 << clk->enable_bit);
559
__raw_writew(regval16, clk->enable_reg);
560
}
561
562
if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL))
563
spin_unlock_irqrestore(&arm_ckctl_lock, flags);
564
else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2))
565
spin_unlock_irqrestore(&arm_idlect2_lock, flags);
566
else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0))
567
spin_unlock_irqrestore(&mod_conf_ctrl_0_lock, flags);
568
else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1))
569
spin_unlock_irqrestore(&mod_conf_ctrl_1_lock, flags);
570
else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL))
571
spin_unlock_irqrestore(&swd_clk_div_ctrl_sel_lock, flags);
572
573
return 0;
574
}
575
576
static void omap1_clk_disable_generic(struct omap1_clk *clk)
577
{
578
unsigned long flags;
579
__u16 regval16;
580
__u32 regval32;
581
582
if (clk->enable_reg == NULL)
583
return;
584
585
/* protect clk->enable_reg from concurrent access via clk_set_rate() */
586
if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL))
587
spin_lock_irqsave(&arm_ckctl_lock, flags);
588
else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2))
589
spin_lock_irqsave(&arm_idlect2_lock, flags);
590
else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0))
591
spin_lock_irqsave(&mod_conf_ctrl_0_lock, flags);
592
else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1))
593
spin_lock_irqsave(&mod_conf_ctrl_1_lock, flags);
594
else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL))
595
spin_lock_irqsave(&swd_clk_div_ctrl_sel_lock, flags);
596
597
if (clk->flags & ENABLE_REG_32BIT) {
598
regval32 = __raw_readl(clk->enable_reg);
599
regval32 &= ~(1 << clk->enable_bit);
600
__raw_writel(regval32, clk->enable_reg);
601
} else {
602
regval16 = __raw_readw(clk->enable_reg);
603
regval16 &= ~(1 << clk->enable_bit);
604
__raw_writew(regval16, clk->enable_reg);
605
}
606
607
if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL))
608
spin_unlock_irqrestore(&arm_ckctl_lock, flags);
609
else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2))
610
spin_unlock_irqrestore(&arm_idlect2_lock, flags);
611
else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0))
612
spin_unlock_irqrestore(&mod_conf_ctrl_0_lock, flags);
613
else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1))
614
spin_unlock_irqrestore(&mod_conf_ctrl_1_lock, flags);
615
else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL))
616
spin_unlock_irqrestore(&swd_clk_div_ctrl_sel_lock, flags);
617
}
618
619
const struct clkops clkops_generic = {
620
.enable = omap1_clk_enable_generic,
621
.disable = omap1_clk_disable_generic,
622
};
623
624
static int omap1_clk_enable_dsp_domain(struct omap1_clk *clk)
625
{
626
bool api_ck_was_enabled;
627
int retval = 0;
628
629
api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw);
630
if (!api_ck_was_enabled)
631
retval = api_ck_p->ops->enable(api_ck_p);
632
633
if (!retval) {
634
retval = omap1_clk_enable_generic(clk);
635
636
if (!api_ck_was_enabled)
637
api_ck_p->ops->disable(api_ck_p);
638
}
639
640
return retval;
641
}
642
643
static void omap1_clk_disable_dsp_domain(struct omap1_clk *clk)
644
{
645
bool api_ck_was_enabled;
646
647
api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw);
648
if (!api_ck_was_enabled)
649
if (api_ck_p->ops->enable(api_ck_p) < 0)
650
return;
651
652
omap1_clk_disable_generic(clk);
653
654
if (!api_ck_was_enabled)
655
api_ck_p->ops->disable(api_ck_p);
656
}
657
658
const struct clkops clkops_dspck = {
659
.enable = omap1_clk_enable_dsp_domain,
660
.disable = omap1_clk_disable_dsp_domain,
661
};
662
663
/* XXX SYSC register handling does not belong in the clock framework */
664
static int omap1_clk_enable_uart_functional_16xx(struct omap1_clk *clk)
665
{
666
int ret;
667
struct uart_clk *uclk;
668
669
ret = omap1_clk_enable_generic(clk);
670
if (ret == 0) {
671
/* Set smart idle acknowledgement mode */
672
uclk = (struct uart_clk *)clk;
673
omap_writeb((omap_readb(uclk->sysc_addr) & ~0x10) | 8,
674
uclk->sysc_addr);
675
}
676
677
return ret;
678
}
679
680
/* XXX SYSC register handling does not belong in the clock framework */
681
static void omap1_clk_disable_uart_functional_16xx(struct omap1_clk *clk)
682
{
683
struct uart_clk *uclk;
684
685
/* Set force idle acknowledgement mode */
686
uclk = (struct uart_clk *)clk;
687
omap_writeb((omap_readb(uclk->sysc_addr) & ~0x18), uclk->sysc_addr);
688
689
omap1_clk_disable_generic(clk);
690
}
691
692
/* XXX SYSC register handling does not belong in the clock framework */
693
const struct clkops clkops_uart_16xx = {
694
.enable = omap1_clk_enable_uart_functional_16xx,
695
.disable = omap1_clk_disable_uart_functional_16xx,
696
};
697
698
static unsigned long omap1_clk_recalc_rate(struct clk_hw *hw, unsigned long p_rate)
699
{
700
struct omap1_clk *clk = to_omap1_clk(hw);
701
702
if (clk->recalc)
703
return clk->recalc(clk, p_rate);
704
705
return clk->rate;
706
}
707
708
static long omap1_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *p_rate)
709
{
710
struct omap1_clk *clk = to_omap1_clk(hw);
711
712
if (clk->round_rate != NULL)
713
return clk->round_rate(clk, rate, p_rate);
714
715
return omap1_clk_recalc_rate(hw, *p_rate);
716
}
717
718
static int omap1_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
719
{
720
struct omap1_clk *clk = to_omap1_clk(hw);
721
int ret = -EINVAL;
722
723
if (clk->set_rate)
724
ret = clk->set_rate(clk, rate, p_rate);
725
return ret;
726
}
727
728
/*
729
* Omap1 clock reset and init functions
730
*/
731
732
static int omap1_clk_init_op(struct clk_hw *hw)
733
{
734
struct omap1_clk *clk = to_omap1_clk(hw);
735
736
if (clk->init)
737
return clk->init(clk);
738
739
return 0;
740
}
741
742
#ifdef CONFIG_OMAP_RESET_CLOCKS
743
744
static void omap1_clk_disable_unused(struct clk_hw *hw)
745
{
746
struct omap1_clk *clk = to_omap1_clk(hw);
747
const char *name = clk_hw_get_name(hw);
748
749
/* Clocks in the DSP domain need api_ck. Just assume bootloader
750
* has not enabled any DSP clocks */
751
if (clk->enable_reg == DSP_IDLECT2) {
752
pr_info("Skipping reset check for DSP domain clock \"%s\"\n", name);
753
return;
754
}
755
756
pr_info("Disabling unused clock \"%s\"... ", name);
757
omap1_clk_disable(hw);
758
printk(" done\n");
759
}
760
761
#endif
762
763
const struct clk_ops omap1_clk_gate_ops = {
764
.enable = omap1_clk_enable,
765
.disable = omap1_clk_disable,
766
.is_enabled = omap1_clk_is_enabled,
767
#ifdef CONFIG_OMAP_RESET_CLOCKS
768
.disable_unused = omap1_clk_disable_unused,
769
#endif
770
};
771
772
const struct clk_ops omap1_clk_rate_ops = {
773
.recalc_rate = omap1_clk_recalc_rate,
774
.round_rate = omap1_clk_round_rate,
775
.set_rate = omap1_clk_set_rate,
776
.init = omap1_clk_init_op,
777
};
778
779
const struct clk_ops omap1_clk_full_ops = {
780
.enable = omap1_clk_enable,
781
.disable = omap1_clk_disable,
782
.is_enabled = omap1_clk_is_enabled,
783
#ifdef CONFIG_OMAP_RESET_CLOCKS
784
.disable_unused = omap1_clk_disable_unused,
785
#endif
786
.recalc_rate = omap1_clk_recalc_rate,
787
.round_rate = omap1_clk_round_rate,
788
.set_rate = omap1_clk_set_rate,
789
.init = omap1_clk_init_op,
790
};
791
792
/*
793
* OMAP specific clock functions shared between omap1 and omap2
794
*/
795
796
/* Used for clocks that always have same value as the parent clock */
797
unsigned long followparent_recalc(struct omap1_clk *clk, unsigned long p_rate)
798
{
799
return p_rate;
800
}
801
802
/*
803
* Used for clocks that have the same value as the parent clock,
804
* divided by some factor
805
*/
806
unsigned long omap_fixed_divisor_recalc(struct omap1_clk *clk, unsigned long p_rate)
807
{
808
WARN_ON(!clk->fixed_div);
809
810
return p_rate / clk->fixed_div;
811
}
812
813
/* Propagate rate to children */
814
void propagate_rate(struct omap1_clk *tclk)
815
{
816
struct clk *clkp;
817
818
/* depend on CCF ability to recalculate new rates across whole clock subtree */
819
if (WARN_ON(!(clk_hw_get_flags(&tclk->hw) & CLK_GET_RATE_NOCACHE)))
820
return;
821
822
clkp = clk_get_sys(NULL, clk_hw_get_name(&tclk->hw));
823
if (WARN_ON(!clkp))
824
return;
825
826
clk_get_rate(clkp);
827
clk_put(clkp);
828
}
829
830
const struct clk_ops omap1_clk_null_ops = {
831
};
832
833
/*
834
* Dummy clock
835
*
836
* Used for clock aliases that are needed on some OMAPs, but not others
837
*/
838
struct omap1_clk dummy_ck __refdata = {
839
.hw.init = CLK_HW_INIT_NO_PARENT("dummy", &omap1_clk_null_ops, 0),
840
};
841
842