[PATCH 10/16] clk: samsung: pll: Add support for rate configuration of PLL45xx

Yadwinder Singh Brar yadi.brar01 at gmail.com
Wed Aug 21 08:18:44 EDT 2013


Hi Tomasz,

On Tue, Aug 20, 2013 at 11:01 PM, Tomasz Figa <t.figa at samsung.com> 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 at samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
> ---
>  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



More information about the linux-arm-kernel mailing list