Fix iProc PLL output clock frequency calculation
Subsystems (3)
Ray Jui
maintainerPATCH v2 1/1 Fix iProc PLL output clock frequency calculation
This patch fixes incorrect iProc PLL clock frequency calculation. The issue is exposed when Cygnus audio PLL was being added.
This patch is based on v4.3-rc5 and has been tested on Cygnus bcm958305k wirelss audio board
This full tree is available here:
repo: https://github.com/Broadcom/cygnus-linux.git
branch: iproc-clk-pll-fix-v2
Changes from v1:
- Added "Fixes: ..." tag so the patch is merged back to stable kernel
Simran Rai (1):
clk: iproc: Fix PLL output frequency calculation
drivers/clk/bcm/clk-iproc-pll.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
Signature · 1 line
1.9.1
Ray Jui
maintainerPATCH v2 1/1 clk: iproc: Fix PLL output frequency calculation
From: Simran Rai <[email protected]>
This patch affects the clocks that use fractional ndivider in their PLL output frequency calculation. Instead of 2^20 divide factor, the clock's ndiv integer shift was used. Fixed the bug by replacing ndiv integer shift with 2^20 factor.
--- drivers/clk/bcm/clk-iproc-pll.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
drivers/clk/bcm/clk-iproc-pll.c +5 -8
@@ -345,8 +345,8 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw,struct iproc_pll *pll = clk->pll;const struct iproc_pll_ctrl *ctrl = pll->ctrl;u32 val; -u64 ndiv; -unsigned int ndiv_int, ndiv_frac, pdiv; +u64 ndiv, ndiv_int, ndiv_frac; +unsigned int pdiv;if (parent_rate ==0 )return 0 ;
@@ -366,22 +366,19 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw, val =readl (pll->pll_base + ctrl->ndiv_int.offset); ndiv_int = (val >> ctrl->ndiv_int.shift) &bit_mask (ctrl->ndiv_int.width); - ndiv = (u64 )ndiv_int << ctrl->ndiv_int.shift; + ndiv = ndiv_int <<20 ;if (ctrl->flags &IPROC_CLK_PLL_HAS_NDIV_FRAC ) { val =readl (pll->pll_base + ctrl->ndiv_frac.offset); ndiv_frac = (val >> ctrl->ndiv_frac.shift) &bit_mask (ctrl->ndiv_frac.width); - -if (ndiv_frac !=0 ) - ndiv = ((u64 )ndiv_int << ctrl->ndiv_int.shift) | - ndiv_frac; + ndiv += ndiv_frac; } val =readl (pll->pll_base + ctrl->pdiv.offset); pdiv = (val >> ctrl->pdiv.shift) &bit_mask (ctrl->pdiv.width); - clk->rate = (ndiv * parent_rate) >> ctrl->ndiv_int.shift; + clk->rate = (ndiv * parent_rate) >>20 ;if (pdiv ==0 ) clk->rate *=2 ;
Signature · 1 line
1.9.1
Michael Turquette
AppliedRe: [PATCH v2] clk: iproc: Fix PLL output frequency calculation
Quoting Ray Jui (2015-10-19 15:27:19)
Quoted 9 lines
From: Simran Rai <[email protected]>
=This patch affects the clocks that use fractional ndivider in their PLL output frequency calculation. Instead of 2^20 divide factor, the clock's ndiv integer shift was used. Fixed the bug by replacing ndiv integer shift with 2^20 factor.
=
Quoted 4 lines
Signed-off-by Simran Rai <[email protected]>Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>Fixes 5fe225c105fd ("clk: iproc: add initial common clock support")
Applied to clk-next.
Regards,
Mike
drivers/clk/bcm/clk-iproc-=
Quoted 6 lines
--- drivers/clk/bcm/clk-iproc-pll.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)=
drivers/clk/bcm/clk-iproc-= renamed from drivers/clk/bcm/clk-iproc-pll.c +0
-0
pll.c
drivers/clk/bcm/clk-iproc-pll.c static unsigned long iproc_pll_recalc_rate(struct clk=
Quoted 4 lines
index 2dda4e8..d679ab8 100644
drivers/clk/bcm/clk-iproc-pll.c +0
-0@@ -345,8 +345,8 @@ static unsigned long iproc_pll_recalc_rate(struct clk=
_hw *hw,
drivers/clk/bcm/clk-iproc-pll.c static unsigned long iproc_pll_recalc_rate(struct c=
Quoted 12 lines
drivers/clk/bcm/clk-iproc-pll.c +2
-2struct iproc_pll *pll =3D clk->pll; const struct iproc_pll_ctrl *ctrl =3D pll->ctrl;u32 val; -u64 ndiv; -unsigned int ndiv_int, ndiv_frac, pdiv; +u64 ndiv, ndiv_int, ndiv_frac; +unsigned int pdiv; = if (parent_rate =3D=3D 0)return 0;drivers/clk/bcm/clk-iproc-pll.c +0
-0@@ -366,22 +366,19 @@ static unsigned long iproc_pll_recalc_rate(struct c=
lk_hw *hw,
Quoted 33 lines
drivers/clk/bcm/clk-iproc-pll.c +3
-6val =3D readl(pll->pll_base + ctrl->ndiv_int.offset); ndiv_int =3D (val >> ctrl->ndiv_int.shift) &bit_mask (ctrl->ndiv_int.width); - ndiv =3D (u64)ndiv_int << ctrl->ndiv_int.shift; + ndiv =3D ndiv_int << 20; =if (ctrl->flags &IPROC_CLK_PLL_HAS_NDIV_FRAC ) { val =3D readl(pll->pll_base + ctrl->ndiv_frac.offset); ndiv_frac =3D (val >> ctrl->ndiv_frac.shift) &bit_mask (ctrl->ndiv_frac.width); - - if (ndiv_frac !=3D 0) - ndiv =3D ((u64 )ndiv_int << ctrl->ndiv_int.shift) | - ndiv_frac; + ndiv +=3D ndiv_frac; } = val =3D readl(pll->pll_base + ctrl->pdiv.offset); pdiv =3D (val >> ctrl->pdiv.shift) &bit_mask (ctrl->pdiv.width); = - clk->rate =3D (ndiv * parent_rate) >> ctrl->ndiv_int.shift; + clk->rate =3D (ndiv * parent_rate) >>20 ;=
if (pdiv =3D=3D 0) clk->rate *=3D 2;-- =
1.9.1
=20