mirror of
https://github.com/torvalds/linux.git
synced 2026-05-04 06:22:40 -04:00
This was done entirely with mindless brute force, using
git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'
to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.
Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.
For the same reason the 'flex' versions will be done as a separate
conversion.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
270 lines
6.3 KiB
C
270 lines
6.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
//
|
|
// Spreadtrum pll clock driver
|
|
//
|
|
// Copyright (C) 2015~2017 Spreadtrum, Inc.
|
|
// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/err.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "pll.h"
|
|
|
|
#define CLK_PLL_1M 1000000
|
|
#define CLK_PLL_10M (CLK_PLL_1M * 10)
|
|
|
|
#define pindex(pll, member) \
|
|
(pll->factors[member].shift / (8 * sizeof(pll->regs_num)))
|
|
|
|
#define pshift(pll, member) \
|
|
(pll->factors[member].shift % (8 * sizeof(pll->regs_num)))
|
|
|
|
#define pwidth(pll, member) \
|
|
pll->factors[member].width
|
|
|
|
#define pmask(pll, member) \
|
|
((pwidth(pll, member)) ? \
|
|
GENMASK(pwidth(pll, member) + pshift(pll, member) - 1, \
|
|
pshift(pll, member)) : 0)
|
|
|
|
#define pinternal(pll, cfg, member) \
|
|
(cfg[pindex(pll, member)] & pmask(pll, member))
|
|
|
|
#define pinternal_val(pll, cfg, member) \
|
|
(pinternal(pll, cfg, member) >> pshift(pll, member))
|
|
|
|
static inline unsigned int
|
|
sprd_pll_read(const struct sprd_pll *pll, u8 index)
|
|
{
|
|
const struct sprd_clk_common *common = &pll->common;
|
|
unsigned int val = 0;
|
|
|
|
if (WARN_ON(index >= pll->regs_num))
|
|
return 0;
|
|
|
|
regmap_read(common->regmap, common->reg + index * 4, &val);
|
|
|
|
return val;
|
|
}
|
|
|
|
static inline void
|
|
sprd_pll_write(const struct sprd_pll *pll, u8 index,
|
|
u32 msk, u32 val)
|
|
{
|
|
const struct sprd_clk_common *common = &pll->common;
|
|
unsigned int offset, reg;
|
|
int ret = 0;
|
|
|
|
if (WARN_ON(index >= pll->regs_num))
|
|
return;
|
|
|
|
offset = common->reg + index * 4;
|
|
ret = regmap_read(common->regmap, offset, ®);
|
|
if (!ret)
|
|
regmap_write(common->regmap, offset, (reg & ~msk) | val);
|
|
}
|
|
|
|
static unsigned long pll_get_refin(const struct sprd_pll *pll)
|
|
{
|
|
u32 shift, mask, index, refin_id = 3;
|
|
const unsigned long refin[4] = { 2, 4, 13, 26 };
|
|
|
|
if (pwidth(pll, PLL_REFIN)) {
|
|
index = pindex(pll, PLL_REFIN);
|
|
shift = pshift(pll, PLL_REFIN);
|
|
mask = pmask(pll, PLL_REFIN);
|
|
refin_id = (sprd_pll_read(pll, index) & mask) >> shift;
|
|
if (refin_id > 3)
|
|
refin_id = 3;
|
|
}
|
|
|
|
return refin[refin_id];
|
|
}
|
|
|
|
static u32 pll_get_ibias(u64 rate, const u64 *table)
|
|
{
|
|
u32 i, num = table[0];
|
|
|
|
/* table[0] indicates the number of items in this table */
|
|
for (i = 0; i < num; i++)
|
|
if (rate <= table[i + 1])
|
|
break;
|
|
|
|
return i == num ? num - 1 : i;
|
|
}
|
|
|
|
static unsigned long _sprd_pll_recalc_rate(const struct sprd_pll *pll,
|
|
unsigned long parent_rate)
|
|
{
|
|
u32 *cfg;
|
|
u32 i, mask, regs_num = pll->regs_num;
|
|
unsigned long rate, nint, kint = 0;
|
|
u64 refin;
|
|
u16 k1, k2;
|
|
|
|
cfg = kcalloc(regs_num, sizeof(*cfg), GFP_KERNEL);
|
|
if (!cfg)
|
|
return parent_rate;
|
|
|
|
for (i = 0; i < regs_num; i++)
|
|
cfg[i] = sprd_pll_read(pll, i);
|
|
|
|
refin = pll_get_refin(pll);
|
|
|
|
if (pinternal(pll, cfg, PLL_PREDIV))
|
|
refin = refin * 2;
|
|
|
|
if (pwidth(pll, PLL_POSTDIV) &&
|
|
((pll->fflag == 1 && pinternal(pll, cfg, PLL_POSTDIV)) ||
|
|
(!pll->fflag && !pinternal(pll, cfg, PLL_POSTDIV))))
|
|
refin = refin / 2;
|
|
|
|
if (!pinternal(pll, cfg, PLL_DIV_S)) {
|
|
rate = refin * pinternal_val(pll, cfg, PLL_N) * CLK_PLL_10M;
|
|
} else {
|
|
nint = pinternal_val(pll, cfg, PLL_NINT);
|
|
if (pinternal(pll, cfg, PLL_SDM_EN))
|
|
kint = pinternal_val(pll, cfg, PLL_KINT);
|
|
|
|
mask = pmask(pll, PLL_KINT);
|
|
|
|
k1 = pll->k1;
|
|
k2 = pll->k2;
|
|
rate = DIV_ROUND_CLOSEST_ULL(refin * kint * k1,
|
|
((mask >> __ffs(mask)) + 1)) *
|
|
k2 + refin * nint * CLK_PLL_1M;
|
|
}
|
|
|
|
kfree(cfg);
|
|
return rate;
|
|
}
|
|
|
|
#define SPRD_PLL_WRITE_CHECK(pll, i, mask, val) \
|
|
(((sprd_pll_read(pll, i) & mask) == val) ? 0 : (-EFAULT))
|
|
|
|
static int _sprd_pll_set_rate(const struct sprd_pll *pll,
|
|
unsigned long rate,
|
|
unsigned long parent_rate)
|
|
{
|
|
struct reg_cfg *cfg;
|
|
int ret = 0;
|
|
u32 mask, shift, width, ibias_val, index;
|
|
u32 regs_num = pll->regs_num, i = 0;
|
|
unsigned long kint, nint;
|
|
u64 tmp, refin, fvco = rate;
|
|
|
|
cfg = kzalloc_objs(*cfg, regs_num);
|
|
if (!cfg)
|
|
return -ENOMEM;
|
|
|
|
refin = pll_get_refin(pll);
|
|
|
|
mask = pmask(pll, PLL_PREDIV);
|
|
index = pindex(pll, PLL_PREDIV);
|
|
width = pwidth(pll, PLL_PREDIV);
|
|
if (width && (sprd_pll_read(pll, index) & mask))
|
|
refin = refin * 2;
|
|
|
|
mask = pmask(pll, PLL_POSTDIV);
|
|
index = pindex(pll, PLL_POSTDIV);
|
|
width = pwidth(pll, PLL_POSTDIV);
|
|
cfg[index].msk = mask;
|
|
if (width && ((pll->fflag == 1 && fvco <= pll->fvco) ||
|
|
(pll->fflag == 0 && fvco > pll->fvco)))
|
|
cfg[index].val |= mask;
|
|
|
|
if (width && fvco <= pll->fvco)
|
|
fvco = fvco * 2;
|
|
|
|
mask = pmask(pll, PLL_DIV_S);
|
|
index = pindex(pll, PLL_DIV_S);
|
|
cfg[index].val |= mask;
|
|
cfg[index].msk |= mask;
|
|
|
|
mask = pmask(pll, PLL_SDM_EN);
|
|
index = pindex(pll, PLL_SDM_EN);
|
|
cfg[index].val |= mask;
|
|
cfg[index].msk |= mask;
|
|
|
|
nint = do_div(fvco, refin * CLK_PLL_1M);
|
|
mask = pmask(pll, PLL_NINT);
|
|
index = pindex(pll, PLL_NINT);
|
|
shift = pshift(pll, PLL_NINT);
|
|
cfg[index].val |= (nint << shift) & mask;
|
|
cfg[index].msk |= mask;
|
|
|
|
mask = pmask(pll, PLL_KINT);
|
|
index = pindex(pll, PLL_KINT);
|
|
width = pwidth(pll, PLL_KINT);
|
|
shift = pshift(pll, PLL_KINT);
|
|
tmp = fvco - refin * nint * CLK_PLL_1M;
|
|
tmp = do_div(tmp, 10000) * ((mask >> shift) + 1);
|
|
kint = DIV_ROUND_CLOSEST_ULL(tmp, refin * 100);
|
|
cfg[index].val |= (kint << shift) & mask;
|
|
cfg[index].msk |= mask;
|
|
|
|
ibias_val = pll_get_ibias(fvco, pll->itable);
|
|
|
|
mask = pmask(pll, PLL_IBIAS);
|
|
index = pindex(pll, PLL_IBIAS);
|
|
shift = pshift(pll, PLL_IBIAS);
|
|
cfg[index].val |= ibias_val << shift & mask;
|
|
cfg[index].msk |= mask;
|
|
|
|
for (i = 0; i < regs_num; i++) {
|
|
if (cfg[i].msk) {
|
|
sprd_pll_write(pll, i, cfg[i].msk, cfg[i].val);
|
|
ret |= SPRD_PLL_WRITE_CHECK(pll, i, cfg[i].msk,
|
|
cfg[i].val);
|
|
}
|
|
}
|
|
|
|
if (!ret)
|
|
udelay(pll->udelay);
|
|
|
|
kfree(cfg);
|
|
return ret;
|
|
}
|
|
|
|
static unsigned long sprd_pll_recalc_rate(struct clk_hw *hw,
|
|
unsigned long parent_rate)
|
|
{
|
|
struct sprd_pll *pll = hw_to_sprd_pll(hw);
|
|
|
|
return _sprd_pll_recalc_rate(pll, parent_rate);
|
|
}
|
|
|
|
static int sprd_pll_set_rate(struct clk_hw *hw,
|
|
unsigned long rate,
|
|
unsigned long parent_rate)
|
|
{
|
|
struct sprd_pll *pll = hw_to_sprd_pll(hw);
|
|
|
|
return _sprd_pll_set_rate(pll, rate, parent_rate);
|
|
}
|
|
|
|
static int sprd_pll_clk_prepare(struct clk_hw *hw)
|
|
{
|
|
struct sprd_pll *pll = hw_to_sprd_pll(hw);
|
|
|
|
udelay(pll->udelay);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sprd_pll_determine_rate(struct clk_hw *hw,
|
|
struct clk_rate_request *req)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const struct clk_ops sprd_pll_ops = {
|
|
.prepare = sprd_pll_clk_prepare,
|
|
.recalc_rate = sprd_pll_recalc_rate,
|
|
.determine_rate = sprd_pll_determine_rate,
|
|
.set_rate = sprd_pll_set_rate,
|
|
};
|
|
EXPORT_SYMBOL_GPL(sprd_pll_ops);
|