Skip to content

Commit ab27eb4

Browse files
pcercueiamalon
authored andcommitted
clk: ingenic: Add code to enable/disable PLLs
This commit permits the PLLs to be dynamically enabled and disabled when their children clocks are enabled and disabled. Signed-off-by: Paul Cercueil <paul@crapouillou.net> Acked-by: Stephen Boyd <sboyd@codeaurora.org> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Maarten ter Huurne <maarten@treewalker.org> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/18480/ Signed-off-by: James Hogan <jhogan@kernel.org>
1 parent 268db07 commit ab27eb4

File tree

1 file changed

+74
-15
lines changed

1 file changed

+74
-15
lines changed

drivers/clk/ingenic/cgu.c

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,6 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
107107
if (bypass)
108108
return parent_rate;
109109

110-
if (!enable)
111-
return 0;
112-
113110
for (od = 0; od < pll_info->od_max; od++) {
114111
if (pll_info->od_encoding[od] == od_enc)
115112
break;
@@ -153,37 +150,40 @@ ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
153150
return div_u64((u64)parent_rate * m, n * od);
154151
}
155152

156-
static long
157-
ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
158-
unsigned long *prate)
153+
static inline const struct ingenic_cgu_clk_info *to_clk_info(
154+
struct ingenic_clk *ingenic_clk)
159155
{
160-
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
161156
struct ingenic_cgu *cgu = ingenic_clk->cgu;
162157
const struct ingenic_cgu_clk_info *clk_info;
163158

164159
clk_info = &cgu->clock_info[ingenic_clk->idx];
165160
BUG_ON(clk_info->type != CGU_CLK_PLL);
166161

162+
return clk_info;
163+
}
164+
165+
static long
166+
ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
167+
unsigned long *prate)
168+
{
169+
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
170+
const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
171+
167172
return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
168173
}
169174

170175
static int
171176
ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
172177
unsigned long parent_rate)
173178
{
174-
const unsigned timeout = 100;
175179
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
176180
struct ingenic_cgu *cgu = ingenic_clk->cgu;
177-
const struct ingenic_cgu_clk_info *clk_info;
178-
const struct ingenic_cgu_pll_info *pll_info;
181+
const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
182+
const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
179183
unsigned long rate, flags;
180-
unsigned m, n, od, i;
184+
unsigned int m, n, od;
181185
u32 ctl;
182186

183-
clk_info = &cgu->clock_info[ingenic_clk->idx];
184-
BUG_ON(clk_info->type != CGU_CLK_PLL);
185-
pll_info = &clk_info->pll;
186-
187187
rate = ingenic_pll_calc(clk_info, req_rate, parent_rate,
188188
&m, &n, &od);
189189
if (rate != req_rate)
@@ -202,6 +202,26 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
202202
ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
203203
ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;
204204

205+
writel(ctl, cgu->base + pll_info->reg);
206+
spin_unlock_irqrestore(&cgu->lock, flags);
207+
208+
return 0;
209+
}
210+
211+
static int ingenic_pll_enable(struct clk_hw *hw)
212+
{
213+
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
214+
struct ingenic_cgu *cgu = ingenic_clk->cgu;
215+
const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
216+
const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
217+
const unsigned int timeout = 100;
218+
unsigned long flags;
219+
unsigned int i;
220+
u32 ctl;
221+
222+
spin_lock_irqsave(&cgu->lock, flags);
223+
ctl = readl(cgu->base + pll_info->reg);
224+
205225
ctl &= ~BIT(pll_info->bypass_bit);
206226
ctl |= BIT(pll_info->enable_bit);
207227

@@ -223,10 +243,48 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
223243
return 0;
224244
}
225245

246+
static void ingenic_pll_disable(struct clk_hw *hw)
247+
{
248+
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
249+
struct ingenic_cgu *cgu = ingenic_clk->cgu;
250+
const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
251+
const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
252+
unsigned long flags;
253+
u32 ctl;
254+
255+
spin_lock_irqsave(&cgu->lock, flags);
256+
ctl = readl(cgu->base + pll_info->reg);
257+
258+
ctl &= ~BIT(pll_info->enable_bit);
259+
260+
writel(ctl, cgu->base + pll_info->reg);
261+
spin_unlock_irqrestore(&cgu->lock, flags);
262+
}
263+
264+
static int ingenic_pll_is_enabled(struct clk_hw *hw)
265+
{
266+
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
267+
struct ingenic_cgu *cgu = ingenic_clk->cgu;
268+
const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
269+
const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
270+
unsigned long flags;
271+
u32 ctl;
272+
273+
spin_lock_irqsave(&cgu->lock, flags);
274+
ctl = readl(cgu->base + pll_info->reg);
275+
spin_unlock_irqrestore(&cgu->lock, flags);
276+
277+
return !!(ctl & BIT(pll_info->enable_bit));
278+
}
279+
226280
static const struct clk_ops ingenic_pll_ops = {
227281
.recalc_rate = ingenic_pll_recalc_rate,
228282
.round_rate = ingenic_pll_round_rate,
229283
.set_rate = ingenic_pll_set_rate,
284+
285+
.enable = ingenic_pll_enable,
286+
.disable = ingenic_pll_disable,
287+
.is_enabled = ingenic_pll_is_enabled,
230288
};
231289

232290
/*
@@ -601,6 +659,7 @@ static int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx)
601659
}
602660
} else if (caps & CGU_CLK_PLL) {
603661
clk_init.ops = &ingenic_pll_ops;
662+
clk_init.flags |= CLK_SET_RATE_GATE;
604663

605664
caps &= ~CGU_CLK_PLL;
606665

0 commit comments

Comments
 (0)