diff options
Diffstat (limited to 'drivers/clk/mediatek/clk-pll.c')
| -rw-r--r-- | drivers/clk/mediatek/clk-pll.c | 69 |
1 files changed, 58 insertions, 11 deletions
diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index a4eca5fd539c..cd2b6ce551c6 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -23,7 +23,7 @@ #define CON0_BASE_EN BIT(0) #define CON0_PWR_ON BIT(0) #define CON0_ISO_EN BIT(1) -#define PCW_CHG_MASK BIT(31) +#define PCW_CHG_BIT 31 #define AUDPLL_TUNER_EN BIT(31) @@ -37,6 +37,13 @@ int mtk_pll_is_prepared(struct clk_hw *hw) return (readl(pll->en_addr) & BIT(pll->data->pll_en_bit)) != 0; } +static int mtk_pll_fenc_is_prepared(struct clk_hw *hw) +{ + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); + + return !!(readl(pll->fenc_addr) & BIT(pll->data->fenc_sta_bit)); +} + static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin, u32 pcw, int postdiv) { @@ -114,7 +121,8 @@ static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw, pll->data->pcw_shift); val |= pcw << pll->data->pcw_shift; writel(val, pll->pcw_addr); - chg = readl(pll->pcw_chg_addr) | PCW_CHG_MASK; + chg = readl(pll->pcw_chg_addr) | + BIT(pll->data->pcw_chg_bit ? : PCW_CHG_BIT); writel(chg, pll->pcw_chg_addr); if (pll->tuner_addr) writel(val + 1, pll->tuner_addr); @@ -199,16 +207,19 @@ unsigned long mtk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) return __mtk_pll_recalc_rate(pll, parent_rate, pcw, postdiv); } -long mtk_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +int mtk_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); u32 pcw = 0; int postdiv; - mtk_pll_calc_values(pll, &pcw, &postdiv, rate, *prate); + mtk_pll_calc_values(pll, &pcw, &postdiv, req->rate, + req->best_parent_rate); + + req->rate = __mtk_pll_recalc_rate(pll, req->best_parent_rate, pcw, + postdiv); - return __mtk_pll_recalc_rate(pll, *prate, pcw, postdiv); + return 0; } int mtk_pll_prepare(struct clk_hw *hw) @@ -273,14 +284,43 @@ void mtk_pll_unprepare(struct clk_hw *hw) writel(r, pll->pwr_addr); } +static int mtk_pll_prepare_setclr(struct clk_hw *hw) +{ + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); + + writel(BIT(pll->data->pll_en_bit), pll->en_set_addr); + + /* Wait 20us after enable for the PLL to stabilize */ + udelay(20); + + return 0; +} + +static void mtk_pll_unprepare_setclr(struct clk_hw *hw) +{ + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); + + writel(BIT(pll->data->pll_en_bit), pll->en_clr_addr); +} + const struct clk_ops mtk_pll_ops = { .is_prepared = mtk_pll_is_prepared, .prepare = mtk_pll_prepare, .unprepare = mtk_pll_unprepare, .recalc_rate = mtk_pll_recalc_rate, - .round_rate = mtk_pll_round_rate, + .determine_rate = mtk_pll_determine_rate, + .set_rate = mtk_pll_set_rate, +}; + +const struct clk_ops mtk_pll_fenc_clr_set_ops = { + .is_prepared = mtk_pll_fenc_is_prepared, + .prepare = mtk_pll_prepare_setclr, + .unprepare = mtk_pll_unprepare_setclr, + .recalc_rate = mtk_pll_recalc_rate, + .determine_rate = mtk_pll_determine_rate, .set_rate = mtk_pll_set_rate, }; +EXPORT_SYMBOL_GPL(mtk_pll_fenc_clr_set_ops); struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, const struct mtk_pll_data *data, @@ -307,9 +347,15 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, pll->en_addr = base + data->en_reg; else pll->en_addr = pll->base_addr + REG_CON0; + if (data->en_set_reg) + pll->en_set_addr = base + data->en_set_reg; + if (data->en_clr_reg) + pll->en_clr_addr = base + data->en_clr_reg; pll->hw.init = &init; pll->data = data; + pll->fenc_addr = base + data->fenc_sta_ofs; + init.name = data->name; init.flags = (data->flags & PLL_AO) ? CLK_IS_CRITICAL : 0; init.ops = pll_ops; @@ -321,10 +367,8 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, ret = clk_hw_register(NULL, &pll->hw); - if (ret) { - kfree(pll); + if (ret) return ERR_PTR(ret); - } return &pll->hw; } @@ -334,12 +378,15 @@ struct clk_hw *mtk_clk_register_pll(const struct mtk_pll_data *data, { struct mtk_clk_pll *pll; struct clk_hw *hw; + const struct clk_ops *pll_ops = data->ops ? data->ops : &mtk_pll_ops; pll = kzalloc(sizeof(*pll), GFP_KERNEL); if (!pll) return ERR_PTR(-ENOMEM); - hw = mtk_clk_register_pll_ops(pll, data, base, &mtk_pll_ops); + hw = mtk_clk_register_pll_ops(pll, data, base, pll_ops); + if (IS_ERR(hw)) + kfree(pll); return hw; } |
