summaryrefslogtreecommitdiff
path: root/drivers/clk/samsung/clk-pll.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/samsung/clk-pll.c')
-rw-r--r--drivers/clk/samsung/clk-pll.c90
1 files changed, 82 insertions, 8 deletions
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 4bbdf5e91650..fe8abe442c51 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -206,6 +206,7 @@ static const struct clk_ops samsung_pll3000_clk_ops = {
*/
/* Maximum lock time can be 270 * PDIV cycles */
#define PLL35XX_LOCK_FACTOR (270)
+#define PLL142XX_LOCK_FACTOR (150)
#define PLL35XX_MDIV_MASK (0x3FF)
#define PLL35XX_PDIV_MASK (0x3F)
@@ -272,7 +273,11 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
}
/* Set PLL lock time. */
- writel_relaxed(rate->pdiv * PLL35XX_LOCK_FACTOR,
+ if (pll->type == pll_142xx)
+ writel_relaxed(rate->pdiv * PLL142XX_LOCK_FACTOR,
+ pll->lock_reg);
+ else
+ writel_relaxed(rate->pdiv * PLL35XX_LOCK_FACTOR,
pll->lock_reg);
/* Change PLL PMS values */
@@ -430,6 +435,12 @@ static const struct clk_ops samsung_pll36xx_clk_min_ops = {
#define PLL0822X_LOCK_STAT_SHIFT (29)
#define PLL0822X_ENABLE_SHIFT (31)
+/*
+ * PLL1418x, PLL0717x and PLL0718x are similar
+ * to PLL0822x, except that MDIV is one bit smaller
+ */
+#define PLL1418X_MDIV_MASK (0x1FF)
+
static unsigned long samsung_pll0822x_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -438,7 +449,14 @@ static unsigned long samsung_pll0822x_recalc_rate(struct clk_hw *hw,
u64 fvco = parent_rate;
pll_con3 = readl_relaxed(pll->con_reg);
- mdiv = (pll_con3 >> PLL0822X_MDIV_SHIFT) & PLL0822X_MDIV_MASK;
+
+ if (pll->type != pll_1418x &&
+ pll->type != pll_0717x &&
+ pll->type != pll_0718x)
+ mdiv = (pll_con3 >> PLL0822X_MDIV_SHIFT) & PLL0822X_MDIV_MASK;
+ else
+ mdiv = (pll_con3 >> PLL0822X_MDIV_SHIFT) & PLL1418X_MDIV_MASK;
+
pdiv = (pll_con3 >> PLL0822X_PDIV_SHIFT) & PLL0822X_PDIV_MASK;
sdiv = (pll_con3 >> PLL0822X_SDIV_SHIFT) & PLL0822X_SDIV_MASK;
@@ -456,7 +474,12 @@ static int samsung_pll0822x_set_rate(struct clk_hw *hw, unsigned long drate,
{
const struct samsung_pll_rate_table *rate;
struct samsung_clk_pll *pll = to_clk_pll(hw);
- u32 pll_con3;
+ u32 mdiv_mask, pll_con3;
+
+ if (pll->type != pll_1418x)
+ mdiv_mask = PLL0822X_MDIV_MASK;
+ else
+ mdiv_mask = PLL1418X_MDIV_MASK;
/* Get required rate settings from table */
rate = samsung_get_pll_settings(pll, drate);
@@ -468,7 +491,7 @@ static int samsung_pll0822x_set_rate(struct clk_hw *hw, unsigned long drate,
/* Change PLL PMS values */
pll_con3 = readl_relaxed(pll->con_reg);
- pll_con3 &= ~((PLL0822X_MDIV_MASK << PLL0822X_MDIV_SHIFT) |
+ pll_con3 &= ~((mdiv_mask << PLL0822X_MDIV_SHIFT) |
(PLL0822X_PDIV_MASK << PLL0822X_PDIV_SHIFT) |
(PLL0822X_SDIV_MASK << PLL0822X_SDIV_SHIFT));
pll_con3 |= (rate->mdiv << PLL0822X_MDIV_SHIFT) |
@@ -1261,6 +1284,47 @@ static const struct clk_ops samsung_pll2650xx_clk_min_ops = {
.recalc_rate = samsung_pll2650xx_recalc_rate,
};
+/*
+ * PLL531X Clock Type
+ */
+/* Maximum lock time can be 500 * PDIV cycles */
+#define PLL531X_LOCK_FACTOR (500)
+#define PLL531X_MDIV_MASK (0x3FF)
+#define PLL531X_PDIV_MASK (0x3F)
+#define PLL531X_SDIV_MASK (0x7)
+#define PLL531X_FDIV_MASK (0xFFFFFFFF)
+#define PLL531X_MDIV_SHIFT (16)
+#define PLL531X_PDIV_SHIFT (8)
+#define PLL531X_SDIV_SHIFT (0)
+
+static unsigned long samsung_pll531x_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ u32 pdiv, sdiv, fdiv, pll_con0, pll_con8;
+ u64 mdiv, fout = parent_rate;
+
+ pll_con0 = readl_relaxed(pll->con_reg);
+ pll_con8 = readl_relaxed(pll->con_reg + 20);
+ mdiv = (pll_con0 >> PLL531X_MDIV_SHIFT) & PLL531X_MDIV_MASK;
+ pdiv = (pll_con0 >> PLL531X_PDIV_SHIFT) & PLL531X_PDIV_MASK;
+ sdiv = (pll_con0 >> PLL531X_SDIV_SHIFT) & PLL531X_SDIV_MASK;
+ fdiv = (pll_con8 & PLL531X_FDIV_MASK);
+
+ if (fdiv >> 31)
+ mdiv--;
+
+ fout *= (mdiv << 24) + (fdiv >> 8);
+ do_div(fout, (pdiv << sdiv));
+ fout >>= 24;
+
+ return (unsigned long)fout;
+}
+
+static const struct clk_ops samsung_pll531x_clk_ops = {
+ .recalc_rate = samsung_pll531x_recalc_rate,
+};
+
static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
const struct samsung_pll_clock *pll_clk)
{
@@ -1286,10 +1350,10 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
len++;
pll->rate_count = len;
- pll->rate_table = kmemdup(pll_clk->rate_table,
- pll->rate_count *
- sizeof(struct samsung_pll_rate_table),
- GFP_KERNEL);
+ pll->rate_table = kmemdup_array(pll_clk->rate_table,
+ pll->rate_count,
+ sizeof(*pll->rate_table),
+ GFP_KERNEL);
WARN(!pll->rate_table,
"%s: could not allocate rate table for %s\n",
__func__, pll_clk->name);
@@ -1317,11 +1381,17 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
init.ops = &samsung_pll35xx_clk_ops;
break;
case pll_1417x:
+ case pll_1418x:
+ case pll_1051x:
+ case pll_1052x:
case pll_0818x:
case pll_0822x:
case pll_0516x:
case pll_0517x:
case pll_0518x:
+ case pll_0717x:
+ case pll_0718x:
+ case pll_0732x:
pll->enable_offs = PLL0822X_ENABLE_SHIFT;
pll->lock_offs = PLL0822X_LOCK_STAT_SHIFT;
if (!pll->rate_table)
@@ -1394,6 +1464,10 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
else
init.ops = &samsung_pll2650xx_clk_ops;
break;
+ case pll_531x:
+ case pll_4311:
+ init.ops = &samsung_pll531x_clk_ops;
+ break;
default:
pr_warn("%s: Unknown pll type for pll clk %s\n",
__func__, pll_clk->name);