aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPankaj Dubey <pankaj.dubey@samsung.com>2014-03-12 10:56:45 -0400
committerTomasz Figa <t.figa@samsung.com>2014-05-14 13:16:54 -0400
commit8432984732b59b333706fceb4cfb5123140be827 (patch)
tree35e490c270a68d9bbce7ceadcfaf0de03b31f572
parent976face4b46ab36b04312b4e404d160296716d46 (diff)
clk/samsung: add support for pll2550xx
exynos5260 use pll2550xx and it has different bit fields for P,M,S values as compared to pll2550. Support for pll2550xx is added here. Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com> Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com> Signed-off-by: Arun Kumar K <arun.kk@samsung.com> Signed-off-by: Tomasz Figa <t.figa@samsung.com>
-rw-r--r--drivers/clk/samsung/clk-pll.c108
-rw-r--r--drivers/clk/samsung/clk-pll.h1
2 files changed, 109 insertions, 0 deletions
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 1f310be17742..18e42ef56ea6 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -947,6 +947,108 @@ struct clk * __init samsung_clk_register_pll2550x(const char *name,
947 return clk; 947 return clk;
948} 948}
949 949
950/*
951 * PLL2550xx Clock Type
952 */
953
954/* Maximum lock time can be 270 * PDIV cycles */
955#define PLL2550XX_LOCK_FACTOR 270
956
957#define PLL2550XX_M_MASK 0x3FF
958#define PLL2550XX_P_MASK 0x3F
959#define PLL2550XX_S_MASK 0x7
960#define PLL2550XX_LOCK_STAT_MASK 0x1
961#define PLL2550XX_M_SHIFT 9
962#define PLL2550XX_P_SHIFT 3
963#define PLL2550XX_S_SHIFT 0
964#define PLL2550XX_LOCK_STAT_SHIFT 21
965
966static unsigned long samsung_pll2550xx_recalc_rate(struct clk_hw *hw,
967 unsigned long parent_rate)
968{
969 struct samsung_clk_pll *pll = to_clk_pll(hw);
970 u32 mdiv, pdiv, sdiv, pll_con;
971 u64 fvco = parent_rate;
972
973 pll_con = __raw_readl(pll->con_reg);
974 mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
975 pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
976 sdiv = (pll_con >> PLL2550XX_S_SHIFT) & PLL2550XX_S_MASK;
977
978 fvco *= mdiv;
979 do_div(fvco, (pdiv << sdiv));
980
981 return (unsigned long)fvco;
982}
983
984static inline bool samsung_pll2550xx_mp_change(u32 mdiv, u32 pdiv, u32 pll_con)
985{
986 u32 old_mdiv, old_pdiv;
987
988 old_mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
989 old_pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
990
991 return mdiv != old_mdiv || pdiv != old_pdiv;
992}
993
994static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
995 unsigned long prate)
996{
997 struct samsung_clk_pll *pll = to_clk_pll(hw);
998 const struct samsung_pll_rate_table *rate;
999 u32 tmp;
1000
1001 /* Get required rate settings from table */
1002 rate = samsung_get_pll_settings(pll, drate);
1003 if (!rate) {
1004 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1005 drate, __clk_get_name(hw->clk));
1006 return -EINVAL;
1007 }
1008
1009 tmp = __raw_readl(pll->con_reg);
1010
1011 if (!(samsung_pll2550xx_mp_change(rate->mdiv, rate->pdiv, tmp))) {
1012 /* If only s change, change just s value only*/
1013 tmp &= ~(PLL2550XX_S_MASK << PLL2550XX_S_SHIFT);
1014 tmp |= rate->sdiv << PLL2550XX_S_SHIFT;
1015 __raw_writel(tmp, pll->con_reg);
1016
1017 return 0;
1018 }
1019
1020 /* Set PLL lock time. */
1021 __raw_writel(rate->pdiv * PLL2550XX_LOCK_FACTOR, pll->lock_reg);
1022
1023 /* Change PLL PMS values */
1024 tmp &= ~((PLL2550XX_M_MASK << PLL2550XX_M_SHIFT) |
1025 (PLL2550XX_P_MASK << PLL2550XX_P_SHIFT) |
1026 (PLL2550XX_S_MASK << PLL2550XX_S_SHIFT));
1027 tmp |= (rate->mdiv << PLL2550XX_M_SHIFT) |
1028 (rate->pdiv << PLL2550XX_P_SHIFT) |
1029 (rate->sdiv << PLL2550XX_S_SHIFT);
1030 __raw_writel(tmp, pll->con_reg);
1031
1032 /* wait_lock_time */
1033 do {
1034 cpu_relax();
1035 tmp = __raw_readl(pll->con_reg);
1036 } while (!(tmp & (PLL2550XX_LOCK_STAT_MASK
1037 << PLL2550XX_LOCK_STAT_SHIFT)));
1038
1039 return 0;
1040}
1041
1042static const struct clk_ops samsung_pll2550xx_clk_ops = {
1043 .recalc_rate = samsung_pll2550xx_recalc_rate,
1044 .round_rate = samsung_pll_round_rate,
1045 .set_rate = samsung_pll2550xx_set_rate,
1046};
1047
1048static const struct clk_ops samsung_pll2550xx_clk_min_ops = {
1049 .recalc_rate = samsung_pll2550xx_recalc_rate,
1050};
1051
950static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, 1052static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
951 struct samsung_pll_clock *pll_clk, 1053 struct samsung_pll_clock *pll_clk,
952 void __iomem *base) 1054 void __iomem *base)
@@ -1049,6 +1151,12 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
1049 else 1151 else
1050 init.ops = &samsung_s3c2440_mpll_clk_ops; 1152 init.ops = &samsung_s3c2440_mpll_clk_ops;
1051 break; 1153 break;
1154 case pll_2550xx:
1155 if (!pll->rate_table)
1156 init.ops = &samsung_pll2550xx_clk_min_ops;
1157 else
1158 init.ops = &samsung_pll2550xx_clk_ops;
1159 break;
1052 default: 1160 default:
1053 pr_warn("%s: Unknown pll type for pll clk %s\n", 1161 pr_warn("%s: Unknown pll type for pll clk %s\n",
1054 __func__, pll_clk->name); 1162 __func__, pll_clk->name);
diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h
index 6428bcc6df6f..ec4bc1d45e31 100644
--- a/drivers/clk/samsung/clk-pll.h
+++ b/drivers/clk/samsung/clk-pll.h
@@ -31,6 +31,7 @@ enum samsung_pll_type {
31 pll_s3c2410_mpll, 31 pll_s3c2410_mpll,
32 pll_s3c2410_upll, 32 pll_s3c2410_upll,
33 pll_s3c2440_mpll, 33 pll_s3c2440_mpll,
34 pll_2550xx,
34}; 35};
35 36
36#define PLL_35XX_RATE(_rate, _m, _p, _s) \ 37#define PLL_35XX_RATE(_rate, _m, _p, _s) \