clk: fractional-divider: Introduce POWER_OF_TWO_PS flag
The newly introduced POWER_OF_TWO_PS flag, when set, makes the flow to skip the assumption that the caller will use an additional 2^scale prescaler to get the desired clock rate. Reported-by: Liu Ying <victor.liu@nxp.com> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Link: https://lore.kernel.org/r/20210812170025.67074-3-andriy.shevchenko@linux.intel.com Signed-off-by: Stephen Boyd <sboyd@kernel.org>
This commit is contained in:
Родитель
928f9e2686
Коммит
82f53f9ee5
|
@ -434,8 +434,8 @@ static int register_device_clock(struct acpi_device *adev,
|
||||||
if (!clk_name)
|
if (!clk_name)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
clk = clk_register_fractional_divider(NULL, clk_name, parent,
|
clk = clk_register_fractional_divider(NULL, clk_name, parent,
|
||||||
0, prv_base,
|
CLK_FRAC_DIVIDER_POWER_OF_TWO_PS,
|
||||||
1, 15, 16, 15, 0, NULL);
|
prv_base, 1, 15, 16, 15, 0, NULL);
|
||||||
parent = clk_name;
|
parent = clk_name;
|
||||||
|
|
||||||
clk_name = kasprintf(GFP_KERNEL, "%s-update", devname);
|
clk_name = kasprintf(GFP_KERNEL, "%s-update", devname);
|
||||||
|
|
|
@ -76,16 +76,18 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw,
|
||||||
unsigned long *m, unsigned long *n)
|
unsigned long *m, unsigned long *n)
|
||||||
{
|
{
|
||||||
struct clk_fractional_divider *fd = to_clk_fd(hw);
|
struct clk_fractional_divider *fd = to_clk_fd(hw);
|
||||||
unsigned long scale;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get rate closer to *parent_rate to guarantee there is no overflow
|
* Get rate closer to *parent_rate to guarantee there is no overflow
|
||||||
* for m and n. In the result it will be the nearest rate left shifted
|
* for m and n. In the result it will be the nearest rate left shifted
|
||||||
* by (scale - fd->nwidth) bits.
|
* by (scale - fd->nwidth) bits.
|
||||||
*/
|
*/
|
||||||
scale = fls_long(*parent_rate / rate - 1);
|
if (fd->flags & CLK_FRAC_DIVIDER_POWER_OF_TWO_PS) {
|
||||||
if (scale > fd->nwidth)
|
unsigned long scale = fls_long(*parent_rate / rate - 1);
|
||||||
rate <<= scale - fd->nwidth;
|
|
||||||
|
if (scale > fd->nwidth)
|
||||||
|
rate <<= scale - fd->nwidth;
|
||||||
|
}
|
||||||
|
|
||||||
rational_best_approximation(rate, *parent_rate,
|
rational_best_approximation(rate, *parent_rate,
|
||||||
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
|
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
|
||||||
|
|
|
@ -301,7 +301,8 @@ static int intel_lpss_register_clock_divider(struct intel_lpss *lpss,
|
||||||
|
|
||||||
snprintf(name, sizeof(name), "%s-div", devname);
|
snprintf(name, sizeof(name), "%s-div", devname);
|
||||||
tmp = clk_register_fractional_divider(NULL, name, __clk_get_name(tmp),
|
tmp = clk_register_fractional_divider(NULL, name, __clk_get_name(tmp),
|
||||||
0, lpss->priv, 1, 15, 16, 15, 0,
|
CLK_FRAC_DIVIDER_POWER_OF_TWO_PS,
|
||||||
|
lpss->priv, 1, 15, 16, 15, 0,
|
||||||
NULL);
|
NULL);
|
||||||
if (IS_ERR(tmp))
|
if (IS_ERR(tmp))
|
||||||
return PTR_ERR(tmp);
|
return PTR_ERR(tmp);
|
||||||
|
|
|
@ -1001,6 +1001,12 @@ struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev,
|
||||||
* CLK_FRAC_DIVIDER_BIG_ENDIAN - By default little endian register accesses are
|
* CLK_FRAC_DIVIDER_BIG_ENDIAN - By default little endian register accesses are
|
||||||
* used for the divider register. Setting this flag makes the register
|
* used for the divider register. Setting this flag makes the register
|
||||||
* accesses big endian.
|
* accesses big endian.
|
||||||
|
* CLK_FRAC_DIVIDER_POWER_OF_TWO_PS - By default the resulting fraction might
|
||||||
|
* be saturated and the caller will get quite far from the good enough
|
||||||
|
* approximation. Instead the caller may require, by setting this flag,
|
||||||
|
* to shift left by a few bits in case, when the asked one is quite small
|
||||||
|
* to satisfy the desired range of denominator. It assumes that on the
|
||||||
|
* caller's side the power-of-two capable prescaler exists.
|
||||||
*/
|
*/
|
||||||
struct clk_fractional_divider {
|
struct clk_fractional_divider {
|
||||||
struct clk_hw hw;
|
struct clk_hw hw;
|
||||||
|
@ -1022,6 +1028,7 @@ struct clk_fractional_divider {
|
||||||
|
|
||||||
#define CLK_FRAC_DIVIDER_ZERO_BASED BIT(0)
|
#define CLK_FRAC_DIVIDER_ZERO_BASED BIT(0)
|
||||||
#define CLK_FRAC_DIVIDER_BIG_ENDIAN BIT(1)
|
#define CLK_FRAC_DIVIDER_BIG_ENDIAN BIT(1)
|
||||||
|
#define CLK_FRAC_DIVIDER_POWER_OF_TWO_PS BIT(2)
|
||||||
|
|
||||||
struct clk *clk_register_fractional_divider(struct device *dev,
|
struct clk *clk_register_fractional_divider(struct device *dev,
|
||||||
const char *name, const char *parent_name, unsigned long flags,
|
const char *name, const char *parent_name, unsigned long flags,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче