diff options
| -rw-r--r-- | drivers/clk/samsung/clk-pll.c | 108 | ||||
| -rw-r--r-- | drivers/clk/samsung/clk-pll.h | 1 |
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 | |||
| 966 | static 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 | |||
| 984 | static 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 | |||
| 994 | static 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 | |||
| 1042 | static 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 | |||
| 1048 | static const struct clk_ops samsung_pll2550xx_clk_min_ops = { | ||
| 1049 | .recalc_rate = samsung_pll2550xx_recalc_rate, | ||
| 1050 | }; | ||
| 1051 | |||
| 950 | static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, | 1052 | static 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) \ |
