diff mbox

[6/7] clk/samsung: add support for pll2650xx

Message ID 1386345391-23482-7-git-send-email-rahul.sharma@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Rahul Sharma Dec. 6, 2013, 3:56 p.m. UTC
Add support for pll2650xx in samsung pll file. This pll variant
is close to pll36xx but uses CON2 registers instead of CON1.

Aud_pll in Exynos5260 is pll2650xx and uses this code.

Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
---
 drivers/clk/samsung/clk-pll.c |  101 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/samsung/clk-pll.h |    2 +-
 2 files changed, 102 insertions(+), 1 deletion(-)

Comments

Sachin Kamat Dec. 9, 2013, 8:09 a.m. UTC | #1
Hi Rahul,

On 6 December 2013 21:26, Rahul Sharma <rahul.sharma@samsung.com> wrote:
> Add support for pll2650xx in samsung pll file. This pll variant
> is close to pll36xx but uses CON2 registers instead of CON1.
>
> Aud_pll in Exynos5260 is pll2650xx and uses this code.
>
> Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
> ---
>  drivers/clk/samsung/clk-pll.c |  101 +++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/samsung/clk-pll.h |    2 +-
>  2 files changed, 102 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
> index 237a889..60c5679 100644
> --- a/drivers/clk/samsung/clk-pll.c
> +++ b/drivers/clk/samsung/clk-pll.c
> @@ -811,6 +811,101 @@ static const struct clk_ops samsung_pll2550xx_clk_min_ops = {
>         .recalc_rate = samsung_pll2550xx_recalc_rate,
>  };
>
> +/*
> + * PLL2650XX Clock Type
> + */
> +
> +/* Maximum lock time can be 3000 * PDIV cycles */
> +#define PLL2650XX_LOCK_FACTOR (3000)
> +
> +#define PLL2650XX_MDIV_SHIFT           (9)
> +#define PLL2650XX_PDIV_SHIFT           (3)
> +#define PLL2650XX_SDIV_SHIFT           (0)
> +#define PLL2650XX_KDIV_SHIFT           (0)
> +#define PLL2650XX_MDIV_MASK            (0x1ff)
> +#define PLL2650XX_PDIV_MASK            (0x3f)
> +#define PLL2650XX_SDIV_MASK            (0x7)
> +#define PLL2650XX_KDIV_MASK            (0xffff)
> +#define PLL2650XX_PLL_ENABLE_SHIFT     (23)
> +#define PLL2650XX_PLL_LOCKTIME_SHIFT   (21)
> +#define PLL2650XX_PLL_FOUTMASK_SHIFT   (31)

nit: Braces are unnecessary.
Tomasz Figa Dec. 19, 2013, 11:45 a.m. UTC | #2
Hi Rahul,

On Friday 06 of December 2013 21:26:30 Rahul Sharma wrote:
> Add support for pll2650xx in samsung pll file. This pll variant
> is close to pll36xx but uses CON2 registers instead of CON1.

If the ops are otherwise idential, why not reuse the ops for pll36xx
and use CON1 or CON2 register conditionally based on pll->type field?
(Just as it is already done for pll4600, 4650 and 4650c.)

Best regards,
Tomasz
Rahul Sharma Jan. 6, 2014, 11:44 a.m. UTC | #3
Hi Tomasz,

On 19 December 2013 17:15, Tomasz Figa <t.figa@samsung.com> wrote:
> Hi Rahul,
>
> On Friday 06 of December 2013 21:26:30 Rahul Sharma wrote:
>> Add support for pll2650xx in samsung pll file. This pll variant
>> is close to pll36xx but uses CON2 registers instead of CON1.
>
> If the ops are otherwise idential, why not reuse the ops for pll36xx
> and use CON1 or CON2 register conditionally based on pll->type field?
> (Just as it is already done for pll4600, 4650 and 4650c.)
>

I verified the difference and found that  pll2650xx is fairly
different in terms of
Bit Fields, Con2 register, and additional PLL config bits than pll36xx. Due to
this, I have to add lot of if-else code based on pll type which
doesn't looks clean.

Regards,
Rahul Sharma.

> Best regards,
> Tomasz
>
Tomasz Figa Jan. 8, 2014, 12:37 a.m. UTC | #4
On Monday 06 of January 2014 17:14:48 Rahul Sharma wrote:
> Hi Tomasz,
> 
> On 19 December 2013 17:15, Tomasz Figa <t.figa@samsung.com> wrote:
> > Hi Rahul,
> >
> > On Friday 06 of December 2013 21:26:30 Rahul Sharma wrote:
> >> Add support for pll2650xx in samsung pll file. This pll variant
> >> is close to pll36xx but uses CON2 registers instead of CON1.
> >
> > If the ops are otherwise idential, why not reuse the ops for pll36xx
> > and use CON1 or CON2 register conditionally based on pll->type field?
> > (Just as it is already done for pll4600, 4650 and 4650c.)
> >
> 
> I verified the difference and found that  pll2650xx is fairly
> different in terms of
> Bit Fields, Con2 register, and additional PLL config bits than pll36xx. Due to
> this, I have to add lot of if-else code based on pll type which
> doesn't looks clean.

Fair enough.

Best regards,
Tomasz
diff mbox

Patch

diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 237a889..60c5679 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -811,6 +811,101 @@  static const struct clk_ops samsung_pll2550xx_clk_min_ops = {
 	.recalc_rate = samsung_pll2550xx_recalc_rate,
 };
 
+/*
+ * PLL2650XX Clock Type
+ */
+
+/* Maximum lock time can be 3000 * PDIV cycles */
+#define PLL2650XX_LOCK_FACTOR (3000)
+
+#define PLL2650XX_MDIV_SHIFT		(9)
+#define PLL2650XX_PDIV_SHIFT		(3)
+#define PLL2650XX_SDIV_SHIFT		(0)
+#define PLL2650XX_KDIV_SHIFT		(0)
+#define PLL2650XX_MDIV_MASK		(0x1ff)
+#define PLL2650XX_PDIV_MASK		(0x3f)
+#define PLL2650XX_SDIV_MASK		(0x7)
+#define PLL2650XX_KDIV_MASK		(0xffff)
+#define PLL2650XX_PLL_ENABLE_SHIFT	(23)
+#define PLL2650XX_PLL_LOCKTIME_SHIFT	(21)
+#define PLL2650XX_PLL_FOUTMASK_SHIFT	(31)
+
+static unsigned long samsung_pll2650xx_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct samsung_clk_pll *pll = to_clk_pll(hw);
+	u32 mdiv, pdiv, sdiv, pll_con0, pll_con2;
+	s16 kdiv;
+	u64 fvco = parent_rate;
+
+	pll_con0 = __raw_readl(pll->con_reg);
+	pll_con2 = __raw_readl(pll->con_reg + 8);
+	mdiv = (pll_con0 >> PLL2650XX_MDIV_SHIFT) & PLL2650XX_MDIV_MASK;
+	pdiv = (pll_con0 >> PLL2650XX_PDIV_SHIFT) & PLL2650XX_PDIV_MASK;
+	sdiv = (pll_con0 >> PLL2650XX_SDIV_SHIFT) & PLL2650XX_SDIV_MASK;
+	kdiv = (s16)(pll_con2 & PLL2650XX_KDIV_MASK);
+
+	fvco *= (mdiv << 16) + kdiv;
+	do_div(fvco, (pdiv << sdiv));
+	fvco >>= 16;
+
+	return (unsigned long)fvco;
+}
+
+static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
+					unsigned long parent_rate)
+{
+	struct samsung_clk_pll *pll = to_clk_pll(hw);
+	u32 tmp, pll_con0, pll_con2;
+	const struct samsung_pll_rate_table *rate;
+
+	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;
+	}
+
+	pll_con0 = __raw_readl(pll->con_reg);
+	pll_con2 = __raw_readl(pll->con_reg + 8);
+
+	 /* Change PLL PMS values */
+	pll_con0 &= ~(PLL2650XX_MDIV_MASK << PLL2650XX_MDIV_SHIFT |
+			PLL2650XX_PDIV_MASK << PLL2650XX_PDIV_SHIFT |
+			PLL2650XX_SDIV_MASK << PLL2650XX_SDIV_SHIFT);
+	pll_con0 |= rate->mdiv << PLL2650XX_MDIV_SHIFT;
+	pll_con0 |= rate->pdiv << PLL2650XX_PDIV_SHIFT;
+	pll_con0 |= rate->sdiv << PLL2650XX_SDIV_SHIFT;
+	pll_con0 |= 1 << PLL2650XX_PLL_ENABLE_SHIFT;
+	pll_con0 |= 1 << PLL2650XX_PLL_FOUTMASK_SHIFT;
+
+	pll_con2 &= ~(PLL2650XX_KDIV_MASK << PLL2650XX_KDIV_SHIFT);
+	pll_con2 |= ((~(rate->kdiv) + 1) & PLL2650XX_KDIV_MASK)
+			<< PLL2650XX_KDIV_SHIFT;
+
+	/* Set PLL lock time. */
+	__raw_writel(PLL2650XX_LOCK_FACTOR * rate->pdiv, pll->lock_reg);
+
+	__raw_writel(pll_con0, pll->con_reg);
+	__raw_writel(pll_con2, pll->con_reg + 8);
+
+	do {
+		tmp = __raw_readl(pll->con_reg);
+	} while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT)));
+
+	return 0;
+}
+
+static const struct clk_ops samsung_pll2650xx_clk_ops = {
+	.recalc_rate = samsung_pll2650xx_recalc_rate,
+	.set_rate = samsung_pll2650xx_set_rate,
+	.round_rate = samsung_pll_round_rate,
+};
+
+static const struct clk_ops samsung_pll2650xx_clk_min_ops = {
+	.recalc_rate = samsung_pll2650xx_recalc_rate,
+};
+
 static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
 				struct samsung_pll_clock *pll_clk,
 				void __iomem *base)
@@ -894,6 +989,12 @@  static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
 		else
 			init.ops = &samsung_pll2550xx_clk_ops;
 		break;
+	case pll_2650xx:
+		if (!pll->rate_table)
+			init.ops = &samsung_pll2650xx_clk_min_ops;
+		else
+			init.ops = &samsung_pll2650xx_clk_ops;
+		break;
 	default:
 		pr_warn("%s: Unknown pll type for pll clk %s\n",
 			__func__, pll_clk->name);
diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h
index e106470..b326e94 100644
--- a/drivers/clk/samsung/clk-pll.h
+++ b/drivers/clk/samsung/clk-pll.h
@@ -26,6 +26,7 @@  enum samsung_pll_type {
 	pll_6552,
 	pll_6553,
 	pll_2550xx,
+	pll_2650xx,
 };
 
 #define PLL_35XX_RATE(_rate, _m, _p, _s)			\
@@ -93,5 +94,4 @@  struct samsung_pll_rate_table {
 extern struct clk * __init samsung_clk_register_pll2550x(const char *name,
 			const char *pname, const void __iomem *reg_base,
 			const unsigned long offset);
-
 #endif /* __SAMSUNG_CLK_PLL_H */