270 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Spreadtrum pll clock driver4//5// Copyright (C) 2015~2017 Spreadtrum, Inc.6// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>7 8#include <linux/delay.h>9#include <linux/err.h>10#include <linux/regmap.h>11#include <linux/slab.h>12 13#include "pll.h"14 15#define CLK_PLL_1M 100000016#define CLK_PLL_10M (CLK_PLL_1M * 10)17 18#define pindex(pll, member) \19 (pll->factors[member].shift / (8 * sizeof(pll->regs_num)))20 21#define pshift(pll, member) \22 (pll->factors[member].shift % (8 * sizeof(pll->regs_num)))23 24#define pwidth(pll, member) \25 pll->factors[member].width26 27#define pmask(pll, member) \28 ((pwidth(pll, member)) ? \29 GENMASK(pwidth(pll, member) + pshift(pll, member) - 1, \30 pshift(pll, member)) : 0)31 32#define pinternal(pll, cfg, member) \33 (cfg[pindex(pll, member)] & pmask(pll, member))34 35#define pinternal_val(pll, cfg, member) \36 (pinternal(pll, cfg, member) >> pshift(pll, member))37 38static inline unsigned int39sprd_pll_read(const struct sprd_pll *pll, u8 index)40{41 const struct sprd_clk_common *common = &pll->common;42 unsigned int val = 0;43 44 if (WARN_ON(index >= pll->regs_num))45 return 0;46 47 regmap_read(common->regmap, common->reg + index * 4, &val);48 49 return val;50}51 52static inline void53sprd_pll_write(const struct sprd_pll *pll, u8 index,54 u32 msk, u32 val)55{56 const struct sprd_clk_common *common = &pll->common;57 unsigned int offset, reg;58 int ret = 0;59 60 if (WARN_ON(index >= pll->regs_num))61 return;62 63 offset = common->reg + index * 4;64 ret = regmap_read(common->regmap, offset, ®);65 if (!ret)66 regmap_write(common->regmap, offset, (reg & ~msk) | val);67}68 69static unsigned long pll_get_refin(const struct sprd_pll *pll)70{71 u32 shift, mask, index, refin_id = 3;72 const unsigned long refin[4] = { 2, 4, 13, 26 };73 74 if (pwidth(pll, PLL_REFIN)) {75 index = pindex(pll, PLL_REFIN);76 shift = pshift(pll, PLL_REFIN);77 mask = pmask(pll, PLL_REFIN);78 refin_id = (sprd_pll_read(pll, index) & mask) >> shift;79 if (refin_id > 3)80 refin_id = 3;81 }82 83 return refin[refin_id];84}85 86static u32 pll_get_ibias(u64 rate, const u64 *table)87{88 u32 i, num = table[0];89 90 /* table[0] indicates the number of items in this table */91 for (i = 0; i < num; i++)92 if (rate <= table[i + 1])93 break;94 95 return i == num ? num - 1 : i;96}97 98static unsigned long _sprd_pll_recalc_rate(const struct sprd_pll *pll,99 unsigned long parent_rate)100{101 u32 *cfg;102 u32 i, mask, regs_num = pll->regs_num;103 unsigned long rate, nint, kint = 0;104 u64 refin;105 u16 k1, k2;106 107 cfg = kcalloc(regs_num, sizeof(*cfg), GFP_KERNEL);108 if (!cfg)109 return parent_rate;110 111 for (i = 0; i < regs_num; i++)112 cfg[i] = sprd_pll_read(pll, i);113 114 refin = pll_get_refin(pll);115 116 if (pinternal(pll, cfg, PLL_PREDIV))117 refin = refin * 2;118 119 if (pwidth(pll, PLL_POSTDIV) &&120 ((pll->fflag == 1 && pinternal(pll, cfg, PLL_POSTDIV)) ||121 (!pll->fflag && !pinternal(pll, cfg, PLL_POSTDIV))))122 refin = refin / 2;123 124 if (!pinternal(pll, cfg, PLL_DIV_S)) {125 rate = refin * pinternal_val(pll, cfg, PLL_N) * CLK_PLL_10M;126 } else {127 nint = pinternal_val(pll, cfg, PLL_NINT);128 if (pinternal(pll, cfg, PLL_SDM_EN))129 kint = pinternal_val(pll, cfg, PLL_KINT);130 131 mask = pmask(pll, PLL_KINT);132 133 k1 = pll->k1;134 k2 = pll->k2;135 rate = DIV_ROUND_CLOSEST_ULL(refin * kint * k1,136 ((mask >> __ffs(mask)) + 1)) *137 k2 + refin * nint * CLK_PLL_1M;138 }139 140 kfree(cfg);141 return rate;142}143 144#define SPRD_PLL_WRITE_CHECK(pll, i, mask, val) \145 (((sprd_pll_read(pll, i) & mask) == val) ? 0 : (-EFAULT))146 147static int _sprd_pll_set_rate(const struct sprd_pll *pll,148 unsigned long rate,149 unsigned long parent_rate)150{151 struct reg_cfg *cfg;152 int ret = 0;153 u32 mask, shift, width, ibias_val, index;154 u32 regs_num = pll->regs_num, i = 0;155 unsigned long kint, nint;156 u64 tmp, refin, fvco = rate;157 158 cfg = kcalloc(regs_num, sizeof(*cfg), GFP_KERNEL);159 if (!cfg)160 return -ENOMEM;161 162 refin = pll_get_refin(pll);163 164 mask = pmask(pll, PLL_PREDIV);165 index = pindex(pll, PLL_PREDIV);166 width = pwidth(pll, PLL_PREDIV);167 if (width && (sprd_pll_read(pll, index) & mask))168 refin = refin * 2;169 170 mask = pmask(pll, PLL_POSTDIV);171 index = pindex(pll, PLL_POSTDIV);172 width = pwidth(pll, PLL_POSTDIV);173 cfg[index].msk = mask;174 if (width && ((pll->fflag == 1 && fvco <= pll->fvco) ||175 (pll->fflag == 0 && fvco > pll->fvco)))176 cfg[index].val |= mask;177 178 if (width && fvco <= pll->fvco)179 fvco = fvco * 2;180 181 mask = pmask(pll, PLL_DIV_S);182 index = pindex(pll, PLL_DIV_S);183 cfg[index].val |= mask;184 cfg[index].msk |= mask;185 186 mask = pmask(pll, PLL_SDM_EN);187 index = pindex(pll, PLL_SDM_EN);188 cfg[index].val |= mask;189 cfg[index].msk |= mask;190 191 nint = do_div(fvco, refin * CLK_PLL_1M);192 mask = pmask(pll, PLL_NINT);193 index = pindex(pll, PLL_NINT);194 shift = pshift(pll, PLL_NINT);195 cfg[index].val |= (nint << shift) & mask;196 cfg[index].msk |= mask;197 198 mask = pmask(pll, PLL_KINT);199 index = pindex(pll, PLL_KINT);200 width = pwidth(pll, PLL_KINT);201 shift = pshift(pll, PLL_KINT);202 tmp = fvco - refin * nint * CLK_PLL_1M;203 tmp = do_div(tmp, 10000) * ((mask >> shift) + 1);204 kint = DIV_ROUND_CLOSEST_ULL(tmp, refin * 100);205 cfg[index].val |= (kint << shift) & mask;206 cfg[index].msk |= mask;207 208 ibias_val = pll_get_ibias(fvco, pll->itable);209 210 mask = pmask(pll, PLL_IBIAS);211 index = pindex(pll, PLL_IBIAS);212 shift = pshift(pll, PLL_IBIAS);213 cfg[index].val |= ibias_val << shift & mask;214 cfg[index].msk |= mask;215 216 for (i = 0; i < regs_num; i++) {217 if (cfg[i].msk) {218 sprd_pll_write(pll, i, cfg[i].msk, cfg[i].val);219 ret |= SPRD_PLL_WRITE_CHECK(pll, i, cfg[i].msk,220 cfg[i].val);221 }222 }223 224 if (!ret)225 udelay(pll->udelay);226 227 kfree(cfg);228 return ret;229}230 231static unsigned long sprd_pll_recalc_rate(struct clk_hw *hw,232 unsigned long parent_rate)233{234 struct sprd_pll *pll = hw_to_sprd_pll(hw);235 236 return _sprd_pll_recalc_rate(pll, parent_rate);237}238 239static int sprd_pll_set_rate(struct clk_hw *hw,240 unsigned long rate,241 unsigned long parent_rate)242{243 struct sprd_pll *pll = hw_to_sprd_pll(hw);244 245 return _sprd_pll_set_rate(pll, rate, parent_rate);246}247 248static int sprd_pll_clk_prepare(struct clk_hw *hw)249{250 struct sprd_pll *pll = hw_to_sprd_pll(hw);251 252 udelay(pll->udelay);253 254 return 0;255}256 257static long sprd_pll_round_rate(struct clk_hw *hw, unsigned long rate,258 unsigned long *prate)259{260 return rate;261}262 263const struct clk_ops sprd_pll_ops = {264 .prepare = sprd_pll_clk_prepare,265 .recalc_rate = sprd_pll_recalc_rate,266 .round_rate = sprd_pll_round_rate,267 .set_rate = sprd_pll_set_rate,268};269EXPORT_SYMBOL_GPL(sprd_pll_ops);270