summaryrefslogtreecommitdiff
path: root/drivers/clk/ingenic/cgu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/ingenic/cgu.c')
-rw-r--r--drivers/clk/ingenic/cgu.c42
1 files changed, 33 insertions, 9 deletions
diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index 861c50d6cb24..1f7ba30f5a1b 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -83,7 +83,7 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
const struct ingenic_cgu_pll_info *pll_info;
- unsigned m, n, od_enc, od;
+ unsigned m, n, od, od_enc = 0;
bool bypass;
u32 ctl;
@@ -96,8 +96,11 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
m += pll_info->m_offset;
n = (ctl >> pll_info->n_shift) & GENMASK(pll_info->n_bits - 1, 0);
n += pll_info->n_offset;
- od_enc = ctl >> pll_info->od_shift;
- od_enc &= GENMASK(pll_info->od_bits - 1, 0);
+
+ if (pll_info->od_bits > 0) {
+ od_enc = ctl >> pll_info->od_shift;
+ od_enc &= GENMASK(pll_info->od_bits - 1, 0);
+ }
if (pll_info->bypass_bit >= 0) {
ctl = readl(cgu->base + pll_info->bypass_reg);
@@ -108,11 +111,15 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
return parent_rate;
}
- for (od = 0; od < pll_info->od_max; od++) {
+ for (od = 0; od < pll_info->od_max; od++)
if (pll_info->od_encoding[od] == od_enc)
break;
- }
- BUG_ON(od == pll_info->od_max);
+
+ /* if od_max = 0, od_bits should be 0 and od is fixed to 1. */
+ if (pll_info->od_max == 0)
+ BUG_ON(pll_info->od_bits != 0);
+ else
+ BUG_ON(od == pll_info->od_max);
od++;
return div_u64((u64)parent_rate * m * pll_info->rate_multiplier,
@@ -182,6 +189,9 @@ static inline int ingenic_pll_check_stable(struct ingenic_cgu *cgu,
{
u32 ctl;
+ if (pll_info->stable_bit < 0)
+ return 0;
+
return readl_poll_timeout(cgu->base + pll_info->reg, ctl,
ctl & BIT(pll_info->stable_bit),
0, 100 * USEC_PER_MSEC);
@@ -215,13 +225,18 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
ctl &= ~(GENMASK(pll_info->n_bits - 1, 0) << pll_info->n_shift);
ctl |= (n - pll_info->n_offset) << pll_info->n_shift;
- ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
- ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;
+ if (pll_info->od_bits > 0) {
+ ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
+ ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;
+ }
writel(ctl, cgu->base + pll_info->reg);
+ if (pll_info->set_rate_hook)
+ pll_info->set_rate_hook(pll_info, rate, parent_rate);
+
/* If the PLL is enabled, verify that it's stable */
- if (ctl & BIT(pll_info->enable_bit))
+ if (pll_info->enable_bit >= 0 && (ctl & BIT(pll_info->enable_bit)))
ret = ingenic_pll_check_stable(cgu, pll_info);
spin_unlock_irqrestore(&cgu->lock, flags);
@@ -239,6 +254,9 @@ static int ingenic_pll_enable(struct clk_hw *hw)
int ret;
u32 ctl;
+ if (pll_info->enable_bit < 0)
+ return 0;
+
spin_lock_irqsave(&cgu->lock, flags);
if (pll_info->bypass_bit >= 0) {
ctl = readl(cgu->base + pll_info->bypass_reg);
@@ -269,6 +287,9 @@ static void ingenic_pll_disable(struct clk_hw *hw)
unsigned long flags;
u32 ctl;
+ if (pll_info->enable_bit < 0)
+ return;
+
spin_lock_irqsave(&cgu->lock, flags);
ctl = readl(cgu->base + pll_info->reg);
@@ -286,6 +307,9 @@ static int ingenic_pll_is_enabled(struct clk_hw *hw)
const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
u32 ctl;
+ if (pll_info->enable_bit < 0)
+ return true;
+
ctl = readl(cgu->base + pll_info->reg);
return !!(ctl & BIT(pll_info->enable_bit));