Hi Tomasz, On Tue, Aug 20, 2013 at 11:01 PM, Tomasz Figa <t.figa@xxxxxxxxxxx> wrote: > This patch implements round_rate and set_rate callbacks of PLL45xx > driver to allow reconfiguration of PLL at runtime. > > Signed-off-by: Tomasz Figa <t.figa@xxxxxxxxxxx> > Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> > --- > drivers/clk/samsung/clk-pll.c | 109 +++++++++++++++++++++++++++++++++++++++++- > drivers/clk/samsung/clk-pll.h | 10 ++++ > 2 files changed, 118 insertions(+), 1 deletion(-) > > diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c > index b0398d2..cb971cb 100644 > --- a/drivers/clk/samsung/clk-pll.c > +++ b/drivers/clk/samsung/clk-pll.c > @@ -10,9 +10,12 @@ > */ > > #include <linux/errno.h> > +#include <linux/hrtimer.h> > #include "clk.h" > #include "clk-pll.h" > > +#define PLL_TIMEOUT_MS 10 > + > struct samsung_clk_pll { > struct clk_hw hw; > void __iomem *lock_reg; > @@ -272,13 +275,20 @@ static const struct clk_ops samsung_pll36xx_clk_min_ops = { > /* > * PLL45xx Clock Type > */ > +#define PLL4502_LOCK_FACTOR 400 > +#define PLL4508_LOCK_FACTOR 240 > > #define PLL45XX_MDIV_MASK (0x3FF) > #define PLL45XX_PDIV_MASK (0x3F) > #define PLL45XX_SDIV_MASK (0x7) > +#define PLL45XX_AFC_MASK (0x1F) > #define PLL45XX_MDIV_SHIFT (16) > #define PLL45XX_PDIV_SHIFT (8) > #define PLL45XX_SDIV_SHIFT (0) > +#define PLL45XX_AFC_SHIFT (0) > + > +#define PLL45XX_ENABLE BIT(31) > +#define PLL45XX_LOCKED BIT(29) > > static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw, > unsigned long parent_rate) > @@ -301,8 +311,100 @@ static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw, > return (unsigned long)fvco; > } > > +static bool samsung_pll45xx_mp_change(u32 pll_con0, u32 pll_con1, > + const struct samsung_pll_rate_table *rate) > +{ > + u32 old_mdiv, old_pdiv, old_afc; > + > + old_mdiv = (pll_con0 >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK; > + old_pdiv = (pll_con0 >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK; > + old_afc = (pll_con1 >> PLL45XX_AFC_SHIFT) & PLL45XX_AFC_MASK; old_afc doesn't required in this function. > + > + return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv); > +} > + > +static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate, > + unsigned long prate) > +{ > + struct samsung_clk_pll *pll = to_clk_pll(hw); > + const struct samsung_pll_rate_table *rate; > + u32 con0, con1; > + ktime_t start; > + > + /* Get required rate settings from table */ > + rate = samsung_get_pll_settings(pll, drate); > + if (!rate) { > + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, > + drate, __clk_get_name(hw->clk)); > + return -EINVAL; > + } > + > + con0 = __raw_readl(pll->con_reg); > + con1 = __raw_readl(pll->con_reg + 0x4); > + > + if (!(samsung_pll45xx_mp_change(con0, con1, rate))) { > + /* If only s change, change just s value only*/ > + con0 &= ~(PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT); > + con0 |= rate->sdiv << PLL45XX_SDIV_SHIFT; > + __raw_writel(con0, pll->con_reg); > + > + return 0; > + } > + > + /* Set PLL PMS values. */ > + con0 &= ~((PLL45XX_MDIV_MASK << PLL45XX_MDIV_SHIFT) | > + (PLL45XX_PDIV_MASK << PLL45XX_PDIV_SHIFT) | > + (PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT)); > + con0 |= (rate->mdiv << PLL45XX_MDIV_SHIFT) | > + (rate->pdiv << PLL45XX_PDIV_SHIFT) | > + (rate->sdiv << PLL45XX_SDIV_SHIFT); > + > + /* Set PLL AFC value. */ > + con1 = __raw_readl(pll->con_reg + 0x4); > + con1 &= ~(PLL45XX_AFC_MASK << PLL45XX_AFC_SHIFT); > + con1 |= (rate->afc << PLL45XX_AFC_SHIFT); > + Do we need to take care of AFC_ENB also, if we are using AFC ? Regards, Yadwinder -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html