clk: rockchip: Add support for clk compensation
Change-Id: I099261a5906dd72dca15cbbf6acea16179c471ad Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com> Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
This commit is contained in:
@ -1,3 +1,8 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
config ROCKCHIP_CLK_COMPENSATION
|
||||||
|
bool "Rockchip Clk Compensation"
|
||||||
|
help
|
||||||
|
Say y here to enable clk compensation(+/- 1000 ppm).
|
||||||
|
|
||||||
source "drivers/clk/rockchip/regmap/Kconfig"
|
source "drivers/clk/rockchip/regmap/Kconfig"
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/gcd.h>
|
#include <linux/gcd.h>
|
||||||
|
#include <linux/clk/rockchip.h>
|
||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
#include "clk.h"
|
#include "clk.h"
|
||||||
|
|
||||||
@ -1183,6 +1184,76 @@ static const struct clk_ops rockchip_rk3399_pll_clk_ops = {
|
|||||||
.init = rockchip_rk3399_pll_init,
|
.init = rockchip_rk3399_pll_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_ROCKCHIP_CLK_COMPENSATION
|
||||||
|
int rockchip_pll_clk_compensation(struct clk *clk, int ppm)
|
||||||
|
{
|
||||||
|
struct clk *parent = clk_get_parent(clk);
|
||||||
|
struct rockchip_clk_pll *pll;
|
||||||
|
static u32 frac, fbdiv;
|
||||||
|
unsigned long m, n;
|
||||||
|
bool negative;
|
||||||
|
u32 pllcon, pllcon0, pllcon2, fbdiv_mask, frac_mask, frac_shift;
|
||||||
|
u64 fracdiv;
|
||||||
|
|
||||||
|
if ((ppm > 1000) || (ppm < -1000))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(parent))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
pll = to_rockchip_clk_pll(__clk_get_hw(parent));
|
||||||
|
if (!pll)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (pll->type) {
|
||||||
|
case pll_rk3036:
|
||||||
|
case pll_rk3328:
|
||||||
|
pllcon0 = RK3036_PLLCON(0);
|
||||||
|
pllcon2 = RK3036_PLLCON(2);
|
||||||
|
fbdiv_mask = RK3036_PLLCON0_FBDIV_MASK;
|
||||||
|
frac_mask = RK3036_PLLCON2_FRAC_MASK;
|
||||||
|
frac_shift = RK3036_PLLCON2_FRAC_SHIFT;
|
||||||
|
break;
|
||||||
|
case pll_rk3066:
|
||||||
|
return -EINVAL;
|
||||||
|
case pll_rk3399:
|
||||||
|
pllcon0 = RK3399_PLLCON(0);
|
||||||
|
pllcon2 = RK3399_PLLCON(2);
|
||||||
|
fbdiv_mask = RK3399_PLLCON0_FBDIV_MASK;
|
||||||
|
frac_mask = RK3399_PLLCON2_FRAC_MASK;
|
||||||
|
frac_shift = RK3399_PLLCON2_FRAC_SHIFT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
negative = !!(ppm & BIT(31));
|
||||||
|
ppm = negative ? ~ppm + 1 : ppm;
|
||||||
|
|
||||||
|
if (!frac) {
|
||||||
|
frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask;
|
||||||
|
fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
m = frac * ppm;
|
||||||
|
n = ppm << 24;
|
||||||
|
|
||||||
|
fracdiv = negative ? frac - ((m / MHZ) + ((n / MHZ) * fbdiv)) :
|
||||||
|
frac + ((m / MHZ) + ((n / MHZ) * fbdiv));
|
||||||
|
|
||||||
|
if (fracdiv > frac_mask)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
pllcon = readl_relaxed(pll->reg_base + pllcon2);
|
||||||
|
pllcon &= ~(frac_mask << frac_shift);
|
||||||
|
pllcon |= fracdiv << frac_shift;
|
||||||
|
writel_relaxed(pllcon, pll->reg_base + pllcon2);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(rockchip_pll_clk_compensation);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Common registering of pll clocks
|
* Common registering of pll clocks
|
||||||
*/
|
*/
|
||||||
|
|||||||
18
include/linux/clk/rockchip.h
Normal file
18
include/linux/clk/rockchip.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINUX_CLK_ROCKCHIP_H_
|
||||||
|
#define __LINUX_CLK_ROCKCHIP_H_
|
||||||
|
|
||||||
|
#ifdef CONFIG_ROCKCHIP_CLK_COMPENSATION
|
||||||
|
int rockchip_pll_clk_compensation(struct clk *clk, int ppm);
|
||||||
|
#else
|
||||||
|
static inline int rockchip_pll_clk_compensation(struct clk *clk, int ppm)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __LINUX_CLK_ROCKCHIP_H_ */
|
||||||
Reference in New Issue
Block a user