192 lines
4.1 KiB
C
Executable File
192 lines
4.1 KiB
C
Executable File
// SPDX-License-Identifier: GPL-2.0
|
|
//
|
|
// Spreadtrum pll clock driver
|
|
//
|
|
// Copyright (C) 2015~2017 Spreadtrum, Inc.
|
|
// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
|
|
|
|
#ifndef _SPRD_PLL_H_
|
|
#define _SPRD_PLL_H_
|
|
|
|
#include <common.h>
|
|
#include <asm/io.h>
|
|
#include <timer.h>
|
|
#include <asm/sizes.h>
|
|
#include <asm/arch/sprd_reg.h>
|
|
#include <config.h>
|
|
#include <malloc.h>
|
|
|
|
|
|
#define INVALID_MAX_IBIAS 0xFF
|
|
#define INVALID_MAX_FREQ 0xFFFFFFFF
|
|
#define INVALID_MAX_VCO_SEL 0xFF
|
|
|
|
/*
|
|
* Divide positive or negative dividend by positive or negative divisor
|
|
* and round to closest integer. Result is undefined for negative
|
|
* divisors if the dividend variable type is unsigned and for negative
|
|
* dividends if the divisor variable type is unsigned.
|
|
*/
|
|
/*
|
|
* Same as above but for u64 dividends. divisor must be a 32-bit
|
|
* number.
|
|
*/
|
|
#define DIV_ROUND_CLOSEST_ULL(x, divisor)( \
|
|
{ \
|
|
typeof(divisor) __d = divisor; \
|
|
unsigned long long _tmp = (x) + (__d) / 2; \
|
|
do_div(_tmp, __d); \
|
|
_tmp; \
|
|
} \
|
|
)
|
|
|
|
#define GENMASK(h, l) \
|
|
(((~0U) << (l)) & (~0U >> (BITS_PER_LONG - 1 - (h))))
|
|
|
|
/*
|
|
* ffs: find first bit set. This is defined the same way as
|
|
* the libc and compiler builtin ffs routines, therefore
|
|
* differs in spirit from the above ffz (man ffs).
|
|
*/
|
|
|
|
static inline int generic_ffs(int x)
|
|
{
|
|
int r = 1;
|
|
|
|
if (!x)
|
|
return 0;
|
|
if (!(x & 0xffff)) {
|
|
x >>= 16;
|
|
r += 16;
|
|
}
|
|
if (!(x & 0xff)) {
|
|
x >>= 8;
|
|
r += 8;
|
|
}
|
|
if (!(x & 0xf)) {
|
|
x >>= 4;
|
|
r += 4;
|
|
}
|
|
if (!(x & 3)) {
|
|
x >>= 2;
|
|
r += 2;
|
|
}
|
|
if (!(x & 1)) {
|
|
x >>= 1;
|
|
r += 1;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
#define __ffs(x) generic_ffs(x)
|
|
|
|
struct reg_cfg {
|
|
u32 val; /* reg value */
|
|
u32 msk; /* mask */
|
|
};
|
|
|
|
struct clk_bit_field {
|
|
u8 shift; /* shift */
|
|
u8 width; /* width */
|
|
};
|
|
|
|
struct freq_table {
|
|
u32 ibias;
|
|
u64 max_freq; /* max frequecy*/
|
|
u32 vco_sel;
|
|
};
|
|
|
|
enum {
|
|
PLL_LOCK_DONE, /* 0 */
|
|
PLL_DIV_S, /* 1 */
|
|
PLL_MOD_EN,
|
|
PLL_SDM_EN,
|
|
PLL_REFIN, /* 4 */
|
|
PLL_IBIAS,
|
|
PLL_N,
|
|
PLL_NINT,
|
|
PLL_KINT, /* 8 */
|
|
PLL_PREDIV,
|
|
PLL_POSTDIV, /* 10 */
|
|
PLL_REFDIV,
|
|
PLL_VCOSEL,
|
|
|
|
PLL_FACT_MAX
|
|
};
|
|
|
|
struct sprd_clk_common {
|
|
u32 reg_base;
|
|
union {
|
|
u32 reg;
|
|
u32 id;
|
|
};
|
|
const char *name;
|
|
const char *parent_name;
|
|
};
|
|
|
|
/*
|
|
* struct sprd_pll - definition of adjustable pll clock
|
|
*
|
|
* @reg: it is registers used to set the configuration of pll clock,
|
|
* and reg[0] shows how many registers this pll clock uses.
|
|
* @ftable: it is pll freq table
|
|
* @udelay it is delay time after setting rate
|
|
* @factors it is used to calculate the pll clock rate
|
|
* @fvco: it is the fvco threshold rate
|
|
* @fflag: it is the fvco flag
|
|
*/
|
|
struct sprd_pll {
|
|
u32 regs_num;
|
|
const struct freq_table *ftable;
|
|
const struct clk_bit_field *factors;
|
|
u16 udelay;
|
|
u16 k1;
|
|
u16 k2;
|
|
u16 fflag;
|
|
u64 fvco;
|
|
|
|
struct sprd_clk_common common;
|
|
};
|
|
|
|
#define SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg_base, \
|
|
_reg, _regs_num, _ftable, _factors, \
|
|
_udelay, _k_1, _k_2, _fflag, _fvco) \
|
|
struct sprd_pll _struct = { \
|
|
.regs_num = _regs_num, \
|
|
.ftable = _ftable, \
|
|
.factors = _factors, \
|
|
.udelay = _udelay, \
|
|
.k1 = _k_1, \
|
|
.k2 = _k_2, \
|
|
.fflag = _fflag, \
|
|
.fvco = _fvco, \
|
|
.common = { \
|
|
.reg_base = _reg_base, \
|
|
.reg = _reg, \
|
|
.name = _name, \
|
|
.parent_name = _parent, \
|
|
}, \
|
|
}
|
|
|
|
#define SPRD_PLL_WITH_ITABLE_K(_struct, _name, _parent, _reg_base, \
|
|
_reg, _regs_num, _ftable, _factors, \
|
|
_udelay, _k_1, _k_2) \
|
|
SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg_base, \
|
|
_reg, _regs_num, _ftable, _factors,\
|
|
_udelay, _k_1, _k_2, 0, 0)
|
|
|
|
#define SPRD_PLL_WITH_ITABLE_1K(_struct, _name, _parent, _reg_base, \
|
|
_reg, _regs_num, _ftable, _factors, _udelay) \
|
|
SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg_base, \
|
|
_reg, _regs_num, _ftable, _factors, \
|
|
_udelay, 1000, 1000, 0, 0)
|
|
|
|
unsigned long sprd_pll_recalc_rate(const struct sprd_pll *pll,
|
|
unsigned long parent_rate);
|
|
|
|
int sprd_pll_set_rate(const struct sprd_pll *pll,
|
|
unsigned long rate,
|
|
unsigned long parent_rate);
|
|
|
|
#endif /* _SPRD_PLL_H_ */
|