aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRahul Sharma <rahul.sharma@samsung.com>2014-03-12 10:56:46 -0400
committerTomasz Figa <t.figa@samsung.com>2014-05-14 13:16:54 -0400
commiteefe119b81eb1afb6e815818ad119cdd2d442fd3 (patch)
tree69e37fd063f6563a4c1522797b9bd74704272ca5
parent8432984732b59b333706fceb4cfb5123140be827 (diff)
clk/samsung: add support for pll2650xx
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> Reviewed-by: Pankaj Dubey <pankaj.dubey@samsung.com> Signed-off-by: Tomasz Figa <t.figa@samsung.com>
-rw-r--r--drivers/clk/samsung/clk-pll.c101
-rw-r--r--drivers/clk/samsung/clk-pll.h1
2 files changed, 102 insertions, 0 deletions
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 18e42ef56ea6..b07fad2a9167 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -1049,6 +1049,101 @@ static const struct clk_ops samsung_pll2550xx_clk_min_ops = {
1049 .recalc_rate = samsung_pll2550xx_recalc_rate, 1049 .recalc_rate = samsung_pll2550xx_recalc_rate,
1050}; 1050};
1051 1051
1052/*
1053 * PLL2650XX Clock Type
1054 */
1055
1056/* Maximum lock time can be 3000 * PDIV cycles */
1057#define PLL2650XX_LOCK_FACTOR 3000
1058
1059#define PLL2650XX_MDIV_SHIFT 9
1060#define PLL2650XX_PDIV_SHIFT 3
1061#define PLL2650XX_SDIV_SHIFT 0
1062#define PLL2650XX_KDIV_SHIFT 0
1063#define PLL2650XX_MDIV_MASK 0x1ff
1064#define PLL2650XX_PDIV_MASK 0x3f
1065#define PLL2650XX_SDIV_MASK 0x7
1066#define PLL2650XX_KDIV_MASK 0xffff
1067#define PLL2650XX_PLL_ENABLE_SHIFT 23
1068#define PLL2650XX_PLL_LOCKTIME_SHIFT 21
1069#define PLL2650XX_PLL_FOUTMASK_SHIFT 31
1070
1071static unsigned long samsung_pll2650xx_recalc_rate(struct clk_hw *hw,
1072 unsigned long parent_rate)
1073{
1074 struct samsung_clk_pll *pll = to_clk_pll(hw);
1075 u32 mdiv, pdiv, sdiv, pll_con0, pll_con2;
1076 s16 kdiv;
1077 u64 fvco = parent_rate;
1078
1079 pll_con0 = __raw_readl(pll->con_reg);
1080 pll_con2 = __raw_readl(pll->con_reg + 8);
1081 mdiv = (pll_con0 >> PLL2650XX_MDIV_SHIFT) & PLL2650XX_MDIV_MASK;
1082 pdiv = (pll_con0 >> PLL2650XX_PDIV_SHIFT) & PLL2650XX_PDIV_MASK;
1083 sdiv = (pll_con0 >> PLL2650XX_SDIV_SHIFT) & PLL2650XX_SDIV_MASK;
1084 kdiv = (s16)(pll_con2 & PLL2650XX_KDIV_MASK);
1085
1086 fvco *= (mdiv << 16) + kdiv;
1087 do_div(fvco, (pdiv << sdiv));
1088 fvco >>= 16;
1089
1090 return (unsigned long)fvco;
1091}
1092
1093static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
1094 unsigned long parent_rate)
1095{
1096 struct samsung_clk_pll *pll = to_clk_pll(hw);
1097 u32 tmp, pll_con0, pll_con2;
1098 const struct samsung_pll_rate_table *rate;
1099
1100 rate = samsung_get_pll_settings(pll, drate);
1101 if (!rate) {
1102 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1103 drate, __clk_get_name(hw->clk));
1104 return -EINVAL;
1105 }
1106
1107 pll_con0 = __raw_readl(pll->con_reg);
1108 pll_con2 = __raw_readl(pll->con_reg + 8);
1109
1110 /* Change PLL PMS values */
1111 pll_con0 &= ~(PLL2650XX_MDIV_MASK << PLL2650XX_MDIV_SHIFT |
1112 PLL2650XX_PDIV_MASK << PLL2650XX_PDIV_SHIFT |
1113 PLL2650XX_SDIV_MASK << PLL2650XX_SDIV_SHIFT);
1114 pll_con0 |= rate->mdiv << PLL2650XX_MDIV_SHIFT;
1115 pll_con0 |= rate->pdiv << PLL2650XX_PDIV_SHIFT;
1116 pll_con0 |= rate->sdiv << PLL2650XX_SDIV_SHIFT;
1117 pll_con0 |= 1 << PLL2650XX_PLL_ENABLE_SHIFT;
1118 pll_con0 |= 1 << PLL2650XX_PLL_FOUTMASK_SHIFT;
1119
1120 pll_con2 &= ~(PLL2650XX_KDIV_MASK << PLL2650XX_KDIV_SHIFT);
1121 pll_con2 |= ((~(rate->kdiv) + 1) & PLL2650XX_KDIV_MASK)
1122 << PLL2650XX_KDIV_SHIFT;
1123
1124 /* Set PLL lock time. */
1125 __raw_writel(PLL2650XX_LOCK_FACTOR * rate->pdiv, pll->lock_reg);
1126
1127 __raw_writel(pll_con0, pll->con_reg);
1128 __raw_writel(pll_con2, pll->con_reg + 8);
1129
1130 do {
1131 tmp = __raw_readl(pll->con_reg);
1132 } while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT)));
1133
1134 return 0;
1135}
1136
1137static const struct clk_ops samsung_pll2650xx_clk_ops = {
1138 .recalc_rate = samsung_pll2650xx_recalc_rate,
1139 .set_rate = samsung_pll2650xx_set_rate,
1140 .round_rate = samsung_pll_round_rate,
1141};
1142
1143static const struct clk_ops samsung_pll2650xx_clk_min_ops = {
1144 .recalc_rate = samsung_pll2650xx_recalc_rate,
1145};
1146
1052static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, 1147static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
1053 struct samsung_pll_clock *pll_clk, 1148 struct samsung_pll_clock *pll_clk,
1054 void __iomem *base) 1149 void __iomem *base)
@@ -1157,6 +1252,12 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
1157 else 1252 else
1158 init.ops = &samsung_pll2550xx_clk_ops; 1253 init.ops = &samsung_pll2550xx_clk_ops;
1159 break; 1254 break;
1255 case pll_2650xx:
1256 if (!pll->rate_table)
1257 init.ops = &samsung_pll2650xx_clk_min_ops;
1258 else
1259 init.ops = &samsung_pll2650xx_clk_ops;
1260 break;
1160 default: 1261 default:
1161 pr_warn("%s: Unknown pll type for pll clk %s\n", 1262 pr_warn("%s: Unknown pll type for pll clk %s\n",
1162 __func__, pll_clk->name); 1263 __func__, pll_clk->name);
diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h
index ec4bc1d45e31..c0ed4d41fd90 100644
--- a/drivers/clk/samsung/clk-pll.h
+++ b/drivers/clk/samsung/clk-pll.h
@@ -32,6 +32,7 @@ enum samsung_pll_type {
32 pll_s3c2410_upll, 32 pll_s3c2410_upll,
33 pll_s3c2440_mpll, 33 pll_s3c2440_mpll,
34 pll_2550xx, 34 pll_2550xx,
35 pll_2650xx,
35}; 36};
36 37
37#define PLL_35XX_RATE(_rate, _m, _p, _s) \ 38#define PLL_35XX_RATE(_rate, _m, _p, _s) \