2014-07-03 03:59:10 +04:00
/*
* Copyright ( c ) 2014 MundoReader S . L .
* Author : Heiko Stuebner < heiko @ sntech . de >
*
2015-11-05 10:33:57 +03:00
* Copyright ( c ) 2015 Rockchip Electronics Co . Ltd .
* Author : Xing Zheng < zhengxing @ rock - chips . com >
*
2014-07-03 03:59:10 +04:00
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <asm/div64.h>
# include <linux/slab.h>
# include <linux/io.h>
# include <linux/delay.h>
# include <linux/clk-provider.h>
# include <linux/regmap.h>
2015-11-05 10:33:57 +03:00
# include <linux/clk.h>
2014-07-03 03:59:10 +04:00
# include "clk.h"
# define PLL_MODE_MASK 0x3
# define PLL_MODE_SLOW 0x0
# define PLL_MODE_NORM 0x1
# define PLL_MODE_DEEP 0x2
struct rockchip_clk_pll {
struct clk_hw hw ;
struct clk_mux pll_mux ;
const struct clk_ops * pll_mux_ops ;
struct notifier_block clk_nb ;
void __iomem * reg_base ;
int lock_offset ;
unsigned int lock_shift ;
enum rockchip_pll_type type ;
2014-11-20 22:38:50 +03:00
u8 flags ;
2014-07-03 03:59:10 +04:00
const struct rockchip_pll_rate_table * rate_table ;
unsigned int rate_count ;
spinlock_t * lock ;
2016-03-09 05:37:04 +03:00
struct rockchip_clk_provider * ctx ;
2014-07-03 03:59:10 +04:00
} ;
# define to_rockchip_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw)
# define to_rockchip_clk_pll_nb(nb) \
container_of ( nb , struct rockchip_clk_pll , clk_nb )
static const struct rockchip_pll_rate_table * rockchip_get_pll_settings (
struct rockchip_clk_pll * pll , unsigned long rate )
{
const struct rockchip_pll_rate_table * rate_table = pll - > rate_table ;
int i ;
for ( i = 0 ; i < pll - > rate_count ; i + + ) {
if ( rate = = rate_table [ i ] . rate )
return & rate_table [ i ] ;
}
return NULL ;
}
static long rockchip_pll_round_rate ( struct clk_hw * hw ,
unsigned long drate , unsigned long * prate )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
const struct rockchip_pll_rate_table * rate_table = pll - > rate_table ;
int i ;
/* Assumming rate_table is in descending order */
for ( i = 0 ; i < pll - > rate_count ; i + + ) {
if ( drate > = rate_table [ i ] . rate )
return rate_table [ i ] . rate ;
}
/* return minimum supported value */
return rate_table [ i - 1 ] . rate ;
}
/*
* Wait for the pll to reach the locked state .
* The calling set_rate function is responsible for making sure the
* grf regmap is available .
*/
static int rockchip_pll_wait_lock ( struct rockchip_clk_pll * pll )
{
2016-03-15 18:55:41 +03:00
struct regmap * grf = pll - > ctx - > grf ;
2014-07-03 03:59:10 +04:00
unsigned int val ;
int delay = 24000000 , ret ;
while ( delay > 0 ) {
ret = regmap_read ( grf , pll - > lock_offset , & val ) ;
if ( ret ) {
pr_err ( " %s: failed to read pll lock status: %d \n " ,
__func__ , ret ) ;
return ret ;
}
if ( val & BIT ( pll - > lock_shift ) )
return 0 ;
delay - - ;
}
pr_err ( " %s: timeout waiting for pll to lock \n " , __func__ ) ;
return - ETIMEDOUT ;
}
2015-11-05 10:33:57 +03:00
/**
* PLL used in RK3036
*/
# define RK3036_PLLCON(i) (i * 0x4)
# define RK3036_PLLCON0_FBDIV_MASK 0xfff
# define RK3036_PLLCON0_FBDIV_SHIFT 0
# define RK3036_PLLCON0_POSTDIV1_MASK 0x7
# define RK3036_PLLCON0_POSTDIV1_SHIFT 12
# define RK3036_PLLCON1_REFDIV_MASK 0x3f
# define RK3036_PLLCON1_REFDIV_SHIFT 0
# define RK3036_PLLCON1_POSTDIV2_MASK 0x7
# define RK3036_PLLCON1_POSTDIV2_SHIFT 6
# define RK3036_PLLCON1_DSMPD_MASK 0x1
# define RK3036_PLLCON1_DSMPD_SHIFT 12
# define RK3036_PLLCON2_FRAC_MASK 0xffffff
# define RK3036_PLLCON2_FRAC_SHIFT 0
# define RK3036_PLLCON1_PWRDOWN (1 << 13)
static void rockchip_rk3036_pll_get_params ( struct rockchip_clk_pll * pll ,
struct rockchip_pll_rate_table * rate )
{
u32 pllcon ;
pllcon = readl_relaxed ( pll - > reg_base + RK3036_PLLCON ( 0 ) ) ;
rate - > fbdiv = ( ( pllcon > > RK3036_PLLCON0_FBDIV_SHIFT )
& RK3036_PLLCON0_FBDIV_MASK ) ;
rate - > postdiv1 = ( ( pllcon > > RK3036_PLLCON0_POSTDIV1_SHIFT )
& RK3036_PLLCON0_POSTDIV1_MASK ) ;
pllcon = readl_relaxed ( pll - > reg_base + RK3036_PLLCON ( 1 ) ) ;
rate - > refdiv = ( ( pllcon > > RK3036_PLLCON1_REFDIV_SHIFT )
& RK3036_PLLCON1_REFDIV_MASK ) ;
rate - > postdiv2 = ( ( pllcon > > RK3036_PLLCON1_POSTDIV2_SHIFT )
& RK3036_PLLCON1_POSTDIV2_MASK ) ;
rate - > dsmpd = ( ( pllcon > > RK3036_PLLCON1_DSMPD_SHIFT )
& RK3036_PLLCON1_DSMPD_MASK ) ;
pllcon = readl_relaxed ( pll - > reg_base + RK3036_PLLCON ( 2 ) ) ;
rate - > frac = ( ( pllcon > > RK3036_PLLCON2_FRAC_SHIFT )
& RK3036_PLLCON2_FRAC_MASK ) ;
}
static unsigned long rockchip_rk3036_pll_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
struct rockchip_pll_rate_table cur ;
u64 rate64 = prate ;
rockchip_rk3036_pll_get_params ( pll , & cur ) ;
rate64 * = cur . fbdiv ;
do_div ( rate64 , cur . refdiv ) ;
if ( cur . dsmpd = = 0 ) {
/* fractional mode */
u64 frac_rate64 = prate * cur . frac ;
do_div ( frac_rate64 , cur . refdiv ) ;
rate64 + = frac_rate64 > > 24 ;
}
do_div ( rate64 , cur . postdiv1 ) ;
do_div ( rate64 , cur . postdiv2 ) ;
return ( unsigned long ) rate64 ;
}
static int rockchip_rk3036_pll_set_params ( struct rockchip_clk_pll * pll ,
const struct rockchip_pll_rate_table * rate )
{
const struct clk_ops * pll_mux_ops = pll - > pll_mux_ops ;
struct clk_mux * pll_mux = & pll - > pll_mux ;
struct rockchip_pll_rate_table cur ;
u32 pllcon ;
int rate_change_remuxed = 0 ;
int cur_parent ;
int ret ;
pr_debug ( " %s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d \n " ,
__func__ , rate - > rate , rate - > fbdiv , rate - > postdiv1 , rate - > refdiv ,
rate - > postdiv2 , rate - > dsmpd , rate - > frac ) ;
rockchip_rk3036_pll_get_params ( pll , & cur ) ;
cur . rate = 0 ;
cur_parent = pll_mux_ops - > get_parent ( & pll_mux - > hw ) ;
if ( cur_parent = = PLL_MODE_NORM ) {
pll_mux_ops - > set_parent ( & pll_mux - > hw , PLL_MODE_SLOW ) ;
rate_change_remuxed = 1 ;
}
/* update pll values */
writel_relaxed ( HIWORD_UPDATE ( rate - > fbdiv , RK3036_PLLCON0_FBDIV_MASK ,
RK3036_PLLCON0_FBDIV_SHIFT ) |
HIWORD_UPDATE ( rate - > postdiv1 , RK3036_PLLCON0_POSTDIV1_MASK ,
RK3036_PLLCON0_POSTDIV1_SHIFT ) ,
pll - > reg_base + RK3036_PLLCON ( 0 ) ) ;
writel_relaxed ( HIWORD_UPDATE ( rate - > refdiv , RK3036_PLLCON1_REFDIV_MASK ,
RK3036_PLLCON1_REFDIV_SHIFT ) |
HIWORD_UPDATE ( rate - > postdiv2 , RK3036_PLLCON1_POSTDIV2_MASK ,
RK3036_PLLCON1_POSTDIV2_SHIFT ) |
HIWORD_UPDATE ( rate - > dsmpd , RK3036_PLLCON1_DSMPD_MASK ,
RK3036_PLLCON1_DSMPD_SHIFT ) ,
pll - > reg_base + RK3036_PLLCON ( 1 ) ) ;
/* GPLL CON2 is not HIWORD_MASK */
pllcon = readl_relaxed ( pll - > reg_base + RK3036_PLLCON ( 2 ) ) ;
pllcon & = ~ ( RK3036_PLLCON2_FRAC_MASK < < RK3036_PLLCON2_FRAC_SHIFT ) ;
pllcon | = rate - > frac < < RK3036_PLLCON2_FRAC_SHIFT ;
writel_relaxed ( pllcon , pll - > reg_base + RK3036_PLLCON ( 2 ) ) ;
/* wait for the pll to lock */
ret = rockchip_pll_wait_lock ( pll ) ;
if ( ret ) {
2016-04-25 01:44:13 +03:00
pr_warn ( " %s: pll update unsuccessful, trying to restore old params \n " ,
2015-11-05 10:33:57 +03:00
__func__ ) ;
rockchip_rk3036_pll_set_params ( pll , & cur ) ;
}
if ( rate_change_remuxed )
pll_mux_ops - > set_parent ( & pll_mux - > hw , PLL_MODE_NORM ) ;
return ret ;
}
static int rockchip_rk3036_pll_set_rate ( struct clk_hw * hw , unsigned long drate ,
unsigned long prate )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
const struct rockchip_pll_rate_table * rate ;
2016-03-15 19:34:56 +03:00
pr_debug ( " %s: changing %s to %lu with a parent rate of %lu \n " ,
__func__ , __clk_get_name ( hw - > clk ) , drate , prate ) ;
2015-11-05 10:33:57 +03:00
/* Get required rate settings from table */
rate = rockchip_get_pll_settings ( pll , drate ) ;
if ( ! rate ) {
pr_err ( " %s: Invalid rate : %lu for pll clk %s \n " , __func__ ,
drate , __clk_get_name ( hw - > clk ) ) ;
return - EINVAL ;
}
return rockchip_rk3036_pll_set_params ( pll , rate ) ;
}
static int rockchip_rk3036_pll_enable ( struct clk_hw * hw )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
writel ( HIWORD_UPDATE ( 0 , RK3036_PLLCON1_PWRDOWN , 0 ) ,
pll - > reg_base + RK3036_PLLCON ( 1 ) ) ;
return 0 ;
}
static void rockchip_rk3036_pll_disable ( struct clk_hw * hw )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
writel ( HIWORD_UPDATE ( RK3036_PLLCON1_PWRDOWN ,
RK3036_PLLCON1_PWRDOWN , 0 ) ,
pll - > reg_base + RK3036_PLLCON ( 1 ) ) ;
}
static int rockchip_rk3036_pll_is_enabled ( struct clk_hw * hw )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
u32 pllcon = readl ( pll - > reg_base + RK3036_PLLCON ( 1 ) ) ;
return ! ( pllcon & RK3036_PLLCON1_PWRDOWN ) ;
}
static void rockchip_rk3036_pll_init ( struct clk_hw * hw )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
const struct rockchip_pll_rate_table * rate ;
struct rockchip_pll_rate_table cur ;
unsigned long drate ;
if ( ! ( pll - > flags & ROCKCHIP_PLL_SYNC_RATE ) )
return ;
drate = clk_hw_get_rate ( hw ) ;
rate = rockchip_get_pll_settings ( pll , drate ) ;
/* when no rate setting for the current rate, rely on clk_set_rate */
if ( ! rate )
return ;
rockchip_rk3036_pll_get_params ( pll , & cur ) ;
pr_debug ( " %s: pll %s@%lu: Hz \n " , __func__ , __clk_get_name ( hw - > clk ) ,
drate ) ;
pr_debug ( " old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d \n " ,
cur . fbdiv , cur . postdiv1 , cur . refdiv , cur . postdiv2 ,
cur . dsmpd , cur . frac ) ;
pr_debug ( " new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d \n " ,
rate - > fbdiv , rate - > postdiv1 , rate - > refdiv , rate - > postdiv2 ,
rate - > dsmpd , rate - > frac ) ;
if ( rate - > fbdiv ! = cur . fbdiv | | rate - > postdiv1 ! = cur . postdiv1 | |
rate - > refdiv ! = cur . refdiv | | rate - > postdiv2 ! = cur . postdiv2 | |
rate - > dsmpd ! = cur . dsmpd | | rate - > frac ! = cur . frac ) {
struct clk * parent = clk_get_parent ( hw - > clk ) ;
if ( ! parent ) {
pr_warn ( " %s: parent of %s not available \n " ,
__func__ , __clk_get_name ( hw - > clk ) ) ;
return ;
}
pr_debug ( " %s: pll %s: rate params do not match rate table, adjusting \n " ,
__func__ , __clk_get_name ( hw - > clk ) ) ;
rockchip_rk3036_pll_set_params ( pll , rate ) ;
}
}
static const struct clk_ops rockchip_rk3036_pll_clk_norate_ops = {
. recalc_rate = rockchip_rk3036_pll_recalc_rate ,
. enable = rockchip_rk3036_pll_enable ,
. disable = rockchip_rk3036_pll_disable ,
. is_enabled = rockchip_rk3036_pll_is_enabled ,
} ;
static const struct clk_ops rockchip_rk3036_pll_clk_ops = {
. recalc_rate = rockchip_rk3036_pll_recalc_rate ,
. round_rate = rockchip_pll_round_rate ,
. set_rate = rockchip_rk3036_pll_set_rate ,
. enable = rockchip_rk3036_pll_enable ,
. disable = rockchip_rk3036_pll_disable ,
. is_enabled = rockchip_rk3036_pll_is_enabled ,
. init = rockchip_rk3036_pll_init ,
} ;
2014-07-03 03:59:10 +04:00
/**
* PLL used in RK3066 , RK3188 and RK3288
*/
# define RK3066_PLL_RESET_DELAY(nr) ((nr * 500) / 24 + 1)
# define RK3066_PLLCON(i) (i * 0x4)
# define RK3066_PLLCON0_OD_MASK 0xf
# define RK3066_PLLCON0_OD_SHIFT 0
# define RK3066_PLLCON0_NR_MASK 0x3f
# define RK3066_PLLCON0_NR_SHIFT 8
# define RK3066_PLLCON1_NF_MASK 0x1fff
# define RK3066_PLLCON1_NF_SHIFT 0
clk: rockchip: Fix PLL bandwidth
In the TRM we see that BWADJ is "a 12-bit bus that selects the values
1-4096 for the bandwidth divider (NB)":
NB = BWADJ[11:0] + 1
The recommended setting of NB: NB = NF / 2.
So:
NB = NF / 2
BWADJ[11:0] + 1 = NF / 2
BWADJ[11:0] = NF / 2 - 1
Right now, we have:
{ \
.rate = _rate##U, \
.nr = _nr, \
.nf = _nf, \
.no = _no, \
.bwadj = (_nf >> 1), \
}
That means we set bwadj to NF / 2, not NF / 2 - 1
All of this is a bit confusing because we specify "NR" (the 1-based
value), "NF" (the 1-based value), "NO" (the 1-based value), but
"BWADJ" (the 0-based value) instead of "NB" (the 1-based value).
Let's change to working with "NB" and fix the off by one error. This
may affect PLL jitter in a small way (hopefully for the better).
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
2015-07-21 23:41:23 +03:00
# define RK3066_PLLCON2_NB_MASK 0xfff
# define RK3066_PLLCON2_NB_SHIFT 0
2014-07-03 03:59:10 +04:00
# define RK3066_PLLCON3_RESET (1 << 5)
# define RK3066_PLLCON3_PWRDOWN (1 << 1)
# define RK3066_PLLCON3_BYPASS (1 << 0)
2015-10-01 12:38:35 +03:00
static void rockchip_rk3066_pll_get_params ( struct rockchip_clk_pll * pll ,
struct rockchip_pll_rate_table * rate )
{
u32 pllcon ;
pllcon = readl_relaxed ( pll - > reg_base + RK3066_PLLCON ( 0 ) ) ;
rate - > nr = ( ( pllcon > > RK3066_PLLCON0_NR_SHIFT )
& RK3066_PLLCON0_NR_MASK ) + 1 ;
rate - > no = ( ( pllcon > > RK3066_PLLCON0_OD_SHIFT )
& RK3066_PLLCON0_OD_MASK ) + 1 ;
pllcon = readl_relaxed ( pll - > reg_base + RK3066_PLLCON ( 1 ) ) ;
rate - > nf = ( ( pllcon > > RK3066_PLLCON1_NF_SHIFT )
& RK3066_PLLCON1_NF_MASK ) + 1 ;
pllcon = readl_relaxed ( pll - > reg_base + RK3066_PLLCON ( 2 ) ) ;
rate - > nb = ( ( pllcon > > RK3066_PLLCON2_NB_SHIFT )
& RK3066_PLLCON2_NB_MASK ) + 1 ;
}
2014-07-03 03:59:10 +04:00
static unsigned long rockchip_rk3066_pll_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
2015-10-01 12:38:35 +03:00
struct rockchip_pll_rate_table cur ;
u64 rate64 = prate ;
2014-07-03 03:59:10 +04:00
u32 pllcon ;
pllcon = readl_relaxed ( pll - > reg_base + RK3066_PLLCON ( 3 ) ) ;
if ( pllcon & RK3066_PLLCON3_BYPASS ) {
pr_debug ( " %s: pll %s is bypassed \n " , __func__ ,
2015-07-31 03:20:57 +03:00
clk_hw_get_name ( hw ) ) ;
2014-07-03 03:59:10 +04:00
return prate ;
}
2015-10-01 12:38:35 +03:00
rockchip_rk3066_pll_get_params ( pll , & cur ) ;
2014-07-03 03:59:10 +04:00
2015-10-01 12:38:35 +03:00
rate64 * = cur . nf ;
do_div ( rate64 , cur . nr ) ;
do_div ( rate64 , cur . no ) ;
2014-07-03 03:59:10 +04:00
return ( unsigned long ) rate64 ;
}
2015-10-01 12:38:35 +03:00
static int rockchip_rk3066_pll_set_params ( struct rockchip_clk_pll * pll ,
const struct rockchip_pll_rate_table * rate )
2014-07-03 03:59:10 +04:00
{
2014-09-16 08:07:57 +04:00
const struct clk_ops * pll_mux_ops = pll - > pll_mux_ops ;
2015-10-01 12:38:35 +03:00
struct clk_mux * pll_mux = & pll - > pll_mux ;
struct rockchip_pll_rate_table cur ;
2014-09-16 08:07:57 +04:00
int rate_change_remuxed = 0 ;
int cur_parent ;
2014-07-03 03:59:10 +04:00
int ret ;
pr_debug ( " %s: rate settings for %lu (nr, no, nf): (%d, %d, %d) \n " ,
__func__ , rate - > rate , rate - > nr , rate - > no , rate - > nf ) ;
2015-10-01 12:38:35 +03:00
rockchip_rk3066_pll_get_params ( pll , & cur ) ;
cur . rate = 0 ;
2014-09-16 08:07:57 +04:00
cur_parent = pll_mux_ops - > get_parent ( & pll_mux - > hw ) ;
if ( cur_parent = = PLL_MODE_NORM ) {
pll_mux_ops - > set_parent ( & pll_mux - > hw , PLL_MODE_SLOW ) ;
rate_change_remuxed = 1 ;
}
2014-07-03 03:59:10 +04:00
/* enter reset mode */
writel ( HIWORD_UPDATE ( RK3066_PLLCON3_RESET , RK3066_PLLCON3_RESET , 0 ) ,
pll - > reg_base + RK3066_PLLCON ( 3 ) ) ;
/* update pll values */
writel ( HIWORD_UPDATE ( rate - > nr - 1 , RK3066_PLLCON0_NR_MASK ,
RK3066_PLLCON0_NR_SHIFT ) |
HIWORD_UPDATE ( rate - > no - 1 , RK3066_PLLCON0_OD_MASK ,
RK3066_PLLCON0_OD_SHIFT ) ,
pll - > reg_base + RK3066_PLLCON ( 0 ) ) ;
writel_relaxed ( HIWORD_UPDATE ( rate - > nf - 1 , RK3066_PLLCON1_NF_MASK ,
RK3066_PLLCON1_NF_SHIFT ) ,
pll - > reg_base + RK3066_PLLCON ( 1 ) ) ;
clk: rockchip: Fix PLL bandwidth
In the TRM we see that BWADJ is "a 12-bit bus that selects the values
1-4096 for the bandwidth divider (NB)":
NB = BWADJ[11:0] + 1
The recommended setting of NB: NB = NF / 2.
So:
NB = NF / 2
BWADJ[11:0] + 1 = NF / 2
BWADJ[11:0] = NF / 2 - 1
Right now, we have:
{ \
.rate = _rate##U, \
.nr = _nr, \
.nf = _nf, \
.no = _no, \
.bwadj = (_nf >> 1), \
}
That means we set bwadj to NF / 2, not NF / 2 - 1
All of this is a bit confusing because we specify "NR" (the 1-based
value), "NF" (the 1-based value), "NO" (the 1-based value), but
"BWADJ" (the 0-based value) instead of "NB" (the 1-based value).
Let's change to working with "NB" and fix the off by one error. This
may affect PLL jitter in a small way (hopefully for the better).
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
2015-07-21 23:41:23 +03:00
writel_relaxed ( HIWORD_UPDATE ( rate - > nb - 1 , RK3066_PLLCON2_NB_MASK ,
RK3066_PLLCON2_NB_SHIFT ) ,
2014-07-03 03:59:10 +04:00
pll - > reg_base + RK3066_PLLCON ( 2 ) ) ;
/* leave reset and wait the reset_delay */
writel ( HIWORD_UPDATE ( 0 , RK3066_PLLCON3_RESET , 0 ) ,
pll - > reg_base + RK3066_PLLCON ( 3 ) ) ;
udelay ( RK3066_PLL_RESET_DELAY ( rate - > nr ) ) ;
/* wait for the pll to lock */
ret = rockchip_pll_wait_lock ( pll ) ;
if ( ret ) {
2016-04-25 01:44:13 +03:00
pr_warn ( " %s: pll update unsuccessful, trying to restore old params \n " ,
2015-10-01 12:38:35 +03:00
__func__ ) ;
rockchip_rk3066_pll_set_params ( pll , & cur ) ;
2014-07-03 03:59:10 +04:00
}
2014-09-16 08:07:57 +04:00
if ( rate_change_remuxed )
pll_mux_ops - > set_parent ( & pll_mux - > hw , PLL_MODE_NORM ) ;
2014-07-03 03:59:10 +04:00
return ret ;
}
2015-10-01 12:38:35 +03:00
static int rockchip_rk3066_pll_set_rate ( struct clk_hw * hw , unsigned long drate ,
unsigned long prate )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
const struct rockchip_pll_rate_table * rate ;
2016-03-15 19:34:56 +03:00
pr_debug ( " %s: changing %s to %lu with a parent rate of %lu \n " ,
__func__ , clk_hw_get_name ( hw ) , drate , prate ) ;
2015-10-01 12:38:35 +03:00
/* Get required rate settings from table */
rate = rockchip_get_pll_settings ( pll , drate ) ;
if ( ! rate ) {
pr_err ( " %s: Invalid rate : %lu for pll clk %s \n " , __func__ ,
drate , clk_hw_get_name ( hw ) ) ;
return - EINVAL ;
}
return rockchip_rk3066_pll_set_params ( pll , rate ) ;
}
2014-07-03 03:59:10 +04:00
static int rockchip_rk3066_pll_enable ( struct clk_hw * hw )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
writel ( HIWORD_UPDATE ( 0 , RK3066_PLLCON3_PWRDOWN , 0 ) ,
pll - > reg_base + RK3066_PLLCON ( 3 ) ) ;
return 0 ;
}
static void rockchip_rk3066_pll_disable ( struct clk_hw * hw )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
writel ( HIWORD_UPDATE ( RK3066_PLLCON3_PWRDOWN ,
RK3066_PLLCON3_PWRDOWN , 0 ) ,
pll - > reg_base + RK3066_PLLCON ( 3 ) ) ;
}
static int rockchip_rk3066_pll_is_enabled ( struct clk_hw * hw )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
u32 pllcon = readl ( pll - > reg_base + RK3066_PLLCON ( 3 ) ) ;
return ! ( pllcon & RK3066_PLLCON3_PWRDOWN ) ;
}
2014-11-20 22:38:52 +03:00
static void rockchip_rk3066_pll_init ( struct clk_hw * hw )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
const struct rockchip_pll_rate_table * rate ;
2015-10-01 12:38:35 +03:00
struct rockchip_pll_rate_table cur ;
2014-11-20 22:38:52 +03:00
unsigned long drate ;
if ( ! ( pll - > flags & ROCKCHIP_PLL_SYNC_RATE ) )
return ;
2015-07-31 03:20:57 +03:00
drate = clk_hw_get_rate ( hw ) ;
2014-11-20 22:38:52 +03:00
rate = rockchip_get_pll_settings ( pll , drate ) ;
/* when no rate setting for the current rate, rely on clk_set_rate */
if ( ! rate )
return ;
2015-10-01 12:38:35 +03:00
rockchip_rk3066_pll_get_params ( pll , & cur ) ;
2014-11-20 22:38:52 +03:00
clk: rockchip: Fix PLL bandwidth
In the TRM we see that BWADJ is "a 12-bit bus that selects the values
1-4096 for the bandwidth divider (NB)":
NB = BWADJ[11:0] + 1
The recommended setting of NB: NB = NF / 2.
So:
NB = NF / 2
BWADJ[11:0] + 1 = NF / 2
BWADJ[11:0] = NF / 2 - 1
Right now, we have:
{ \
.rate = _rate##U, \
.nr = _nr, \
.nf = _nf, \
.no = _no, \
.bwadj = (_nf >> 1), \
}
That means we set bwadj to NF / 2, not NF / 2 - 1
All of this is a bit confusing because we specify "NR" (the 1-based
value), "NF" (the 1-based value), "NO" (the 1-based value), but
"BWADJ" (the 0-based value) instead of "NB" (the 1-based value).
Let's change to working with "NB" and fix the off by one error. This
may affect PLL jitter in a small way (hopefully for the better).
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
2015-07-21 23:41:23 +03:00
pr_debug ( " %s: pll %s@%lu: nr (%d:%d); no (%d:%d); nf(%d:%d), nb(%d:%d) \n " ,
2015-10-01 12:38:35 +03:00
__func__ , clk_hw_get_name ( hw ) , drate , rate - > nr , cur . nr ,
rate - > no , cur . no , rate - > nf , cur . nf , rate - > nb , cur . nb ) ;
if ( rate - > nr ! = cur . nr | | rate - > no ! = cur . no | | rate - > nf ! = cur . nf
| | rate - > nb ! = cur . nb ) {
2014-11-20 22:38:52 +03:00
pr_debug ( " %s: pll %s: rate params do not match rate table, adjusting \n " ,
2015-07-31 03:20:57 +03:00
__func__ , clk_hw_get_name ( hw ) ) ;
2015-10-01 12:38:35 +03:00
rockchip_rk3066_pll_set_params ( pll , rate ) ;
2014-11-20 22:38:52 +03:00
}
}
2014-07-03 03:59:10 +04:00
static const struct clk_ops rockchip_rk3066_pll_clk_norate_ops = {
. recalc_rate = rockchip_rk3066_pll_recalc_rate ,
. enable = rockchip_rk3066_pll_enable ,
. disable = rockchip_rk3066_pll_disable ,
. is_enabled = rockchip_rk3066_pll_is_enabled ,
} ;
static const struct clk_ops rockchip_rk3066_pll_clk_ops = {
. recalc_rate = rockchip_rk3066_pll_recalc_rate ,
. round_rate = rockchip_pll_round_rate ,
. set_rate = rockchip_rk3066_pll_set_rate ,
. enable = rockchip_rk3066_pll_enable ,
. disable = rockchip_rk3066_pll_disable ,
. is_enabled = rockchip_rk3066_pll_is_enabled ,
2014-11-20 22:38:52 +03:00
. init = rockchip_rk3066_pll_init ,
2014-07-03 03:59:10 +04:00
} ;
2016-03-10 06:47:01 +03:00
/**
* PLL used in RK3399
*/
# define RK3399_PLLCON(i) (i * 0x4)
# define RK3399_PLLCON0_FBDIV_MASK 0xfff
# define RK3399_PLLCON0_FBDIV_SHIFT 0
# define RK3399_PLLCON1_REFDIV_MASK 0x3f
# define RK3399_PLLCON1_REFDIV_SHIFT 0
# define RK3399_PLLCON1_POSTDIV1_MASK 0x7
# define RK3399_PLLCON1_POSTDIV1_SHIFT 8
# define RK3399_PLLCON1_POSTDIV2_MASK 0x7
# define RK3399_PLLCON1_POSTDIV2_SHIFT 12
# define RK3399_PLLCON2_FRAC_MASK 0xffffff
# define RK3399_PLLCON2_FRAC_SHIFT 0
# define RK3399_PLLCON2_LOCK_STATUS BIT(31)
# define RK3399_PLLCON3_PWRDOWN BIT(0)
# define RK3399_PLLCON3_DSMPD_MASK 0x1
# define RK3399_PLLCON3_DSMPD_SHIFT 3
static int rockchip_rk3399_pll_wait_lock ( struct rockchip_clk_pll * pll )
{
u32 pllcon ;
int delay = 24000000 ;
/* poll check the lock status in rk3399 xPLLCON2 */
while ( delay > 0 ) {
pllcon = readl_relaxed ( pll - > reg_base + RK3399_PLLCON ( 2 ) ) ;
if ( pllcon & RK3399_PLLCON2_LOCK_STATUS )
return 0 ;
delay - - ;
}
pr_err ( " %s: timeout waiting for pll to lock \n " , __func__ ) ;
return - ETIMEDOUT ;
}
static void rockchip_rk3399_pll_get_params ( struct rockchip_clk_pll * pll ,
struct rockchip_pll_rate_table * rate )
{
u32 pllcon ;
pllcon = readl_relaxed ( pll - > reg_base + RK3399_PLLCON ( 0 ) ) ;
rate - > fbdiv = ( ( pllcon > > RK3399_PLLCON0_FBDIV_SHIFT )
& RK3399_PLLCON0_FBDIV_MASK ) ;
pllcon = readl_relaxed ( pll - > reg_base + RK3399_PLLCON ( 1 ) ) ;
rate - > refdiv = ( ( pllcon > > RK3399_PLLCON1_REFDIV_SHIFT )
& RK3399_PLLCON1_REFDIV_MASK ) ;
rate - > postdiv1 = ( ( pllcon > > RK3399_PLLCON1_POSTDIV1_SHIFT )
& RK3399_PLLCON1_POSTDIV1_MASK ) ;
rate - > postdiv2 = ( ( pllcon > > RK3399_PLLCON1_POSTDIV2_SHIFT )
& RK3399_PLLCON1_POSTDIV2_MASK ) ;
pllcon = readl_relaxed ( pll - > reg_base + RK3399_PLLCON ( 2 ) ) ;
rate - > frac = ( ( pllcon > > RK3399_PLLCON2_FRAC_SHIFT )
& RK3399_PLLCON2_FRAC_MASK ) ;
pllcon = readl_relaxed ( pll - > reg_base + RK3399_PLLCON ( 3 ) ) ;
rate - > dsmpd = ( ( pllcon > > RK3399_PLLCON3_DSMPD_SHIFT )
& RK3399_PLLCON3_DSMPD_MASK ) ;
}
static unsigned long rockchip_rk3399_pll_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
struct rockchip_pll_rate_table cur ;
u64 rate64 = prate ;
rockchip_rk3399_pll_get_params ( pll , & cur ) ;
rate64 * = cur . fbdiv ;
do_div ( rate64 , cur . refdiv ) ;
if ( cur . dsmpd = = 0 ) {
/* fractional mode */
u64 frac_rate64 = prate * cur . frac ;
do_div ( frac_rate64 , cur . refdiv ) ;
rate64 + = frac_rate64 > > 24 ;
}
do_div ( rate64 , cur . postdiv1 ) ;
do_div ( rate64 , cur . postdiv2 ) ;
return ( unsigned long ) rate64 ;
}
static int rockchip_rk3399_pll_set_params ( struct rockchip_clk_pll * pll ,
const struct rockchip_pll_rate_table * rate )
{
const struct clk_ops * pll_mux_ops = pll - > pll_mux_ops ;
struct clk_mux * pll_mux = & pll - > pll_mux ;
struct rockchip_pll_rate_table cur ;
u32 pllcon ;
int rate_change_remuxed = 0 ;
int cur_parent ;
int ret ;
pr_debug ( " %s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d \n " ,
__func__ , rate - > rate , rate - > fbdiv , rate - > postdiv1 , rate - > refdiv ,
rate - > postdiv2 , rate - > dsmpd , rate - > frac ) ;
rockchip_rk3399_pll_get_params ( pll , & cur ) ;
cur . rate = 0 ;
cur_parent = pll_mux_ops - > get_parent ( & pll_mux - > hw ) ;
if ( cur_parent = = PLL_MODE_NORM ) {
pll_mux_ops - > set_parent ( & pll_mux - > hw , PLL_MODE_SLOW ) ;
rate_change_remuxed = 1 ;
}
/* update pll values */
writel_relaxed ( HIWORD_UPDATE ( rate - > fbdiv , RK3399_PLLCON0_FBDIV_MASK ,
RK3399_PLLCON0_FBDIV_SHIFT ) ,
pll - > reg_base + RK3399_PLLCON ( 0 ) ) ;
writel_relaxed ( HIWORD_UPDATE ( rate - > refdiv , RK3399_PLLCON1_REFDIV_MASK ,
RK3399_PLLCON1_REFDIV_SHIFT ) |
HIWORD_UPDATE ( rate - > postdiv1 , RK3399_PLLCON1_POSTDIV1_MASK ,
RK3399_PLLCON1_POSTDIV1_SHIFT ) |
HIWORD_UPDATE ( rate - > postdiv2 , RK3399_PLLCON1_POSTDIV2_MASK ,
RK3399_PLLCON1_POSTDIV2_SHIFT ) ,
pll - > reg_base + RK3399_PLLCON ( 1 ) ) ;
/* xPLL CON2 is not HIWORD_MASK */
pllcon = readl_relaxed ( pll - > reg_base + RK3399_PLLCON ( 2 ) ) ;
pllcon & = ~ ( RK3399_PLLCON2_FRAC_MASK < < RK3399_PLLCON2_FRAC_SHIFT ) ;
pllcon | = rate - > frac < < RK3399_PLLCON2_FRAC_SHIFT ;
writel_relaxed ( pllcon , pll - > reg_base + RK3399_PLLCON ( 2 ) ) ;
writel_relaxed ( HIWORD_UPDATE ( rate - > dsmpd , RK3399_PLLCON3_DSMPD_MASK ,
RK3399_PLLCON3_DSMPD_SHIFT ) ,
pll - > reg_base + RK3399_PLLCON ( 3 ) ) ;
/* wait for the pll to lock */
ret = rockchip_rk3399_pll_wait_lock ( pll ) ;
if ( ret ) {
pr_warn ( " %s: pll update unsuccessful, trying to restore old params \n " ,
__func__ ) ;
rockchip_rk3399_pll_set_params ( pll , & cur ) ;
}
if ( rate_change_remuxed )
pll_mux_ops - > set_parent ( & pll_mux - > hw , PLL_MODE_NORM ) ;
return ret ;
}
static int rockchip_rk3399_pll_set_rate ( struct clk_hw * hw , unsigned long drate ,
unsigned long prate )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
const struct rockchip_pll_rate_table * rate ;
2016-03-15 19:34:56 +03:00
pr_debug ( " %s: changing %s to %lu with a parent rate of %lu \n " ,
__func__ , __clk_get_name ( hw - > clk ) , drate , prate ) ;
2016-03-10 06:47:01 +03:00
/* Get required rate settings from table */
rate = rockchip_get_pll_settings ( pll , drate ) ;
if ( ! rate ) {
pr_err ( " %s: Invalid rate : %lu for pll clk %s \n " , __func__ ,
drate , __clk_get_name ( hw - > clk ) ) ;
return - EINVAL ;
}
return rockchip_rk3399_pll_set_params ( pll , rate ) ;
}
static int rockchip_rk3399_pll_enable ( struct clk_hw * hw )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
writel ( HIWORD_UPDATE ( 0 , RK3399_PLLCON3_PWRDOWN , 0 ) ,
pll - > reg_base + RK3399_PLLCON ( 3 ) ) ;
return 0 ;
}
static void rockchip_rk3399_pll_disable ( struct clk_hw * hw )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
writel ( HIWORD_UPDATE ( RK3399_PLLCON3_PWRDOWN ,
RK3399_PLLCON3_PWRDOWN , 0 ) ,
pll - > reg_base + RK3399_PLLCON ( 3 ) ) ;
}
static int rockchip_rk3399_pll_is_enabled ( struct clk_hw * hw )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
u32 pllcon = readl ( pll - > reg_base + RK3399_PLLCON ( 3 ) ) ;
return ! ( pllcon & RK3399_PLLCON3_PWRDOWN ) ;
}
static void rockchip_rk3399_pll_init ( struct clk_hw * hw )
{
struct rockchip_clk_pll * pll = to_rockchip_clk_pll ( hw ) ;
const struct rockchip_pll_rate_table * rate ;
struct rockchip_pll_rate_table cur ;
unsigned long drate ;
if ( ! ( pll - > flags & ROCKCHIP_PLL_SYNC_RATE ) )
return ;
drate = clk_hw_get_rate ( hw ) ;
rate = rockchip_get_pll_settings ( pll , drate ) ;
/* when no rate setting for the current rate, rely on clk_set_rate */
if ( ! rate )
return ;
rockchip_rk3399_pll_get_params ( pll , & cur ) ;
pr_debug ( " %s: pll %s@%lu: Hz \n " , __func__ , __clk_get_name ( hw - > clk ) ,
drate ) ;
pr_debug ( " old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d \n " ,
cur . fbdiv , cur . postdiv1 , cur . refdiv , cur . postdiv2 ,
cur . dsmpd , cur . frac ) ;
pr_debug ( " new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d \n " ,
rate - > fbdiv , rate - > postdiv1 , rate - > refdiv , rate - > postdiv2 ,
rate - > dsmpd , rate - > frac ) ;
if ( rate - > fbdiv ! = cur . fbdiv | | rate - > postdiv1 ! = cur . postdiv1 | |
rate - > refdiv ! = cur . refdiv | | rate - > postdiv2 ! = cur . postdiv2 | |
rate - > dsmpd ! = cur . dsmpd | | rate - > frac ! = cur . frac ) {
struct clk * parent = clk_get_parent ( hw - > clk ) ;
if ( ! parent ) {
pr_warn ( " %s: parent of %s not available \n " ,
__func__ , __clk_get_name ( hw - > clk ) ) ;
return ;
}
pr_debug ( " %s: pll %s: rate params do not match rate table, adjusting \n " ,
__func__ , __clk_get_name ( hw - > clk ) ) ;
rockchip_rk3399_pll_set_params ( pll , rate ) ;
}
}
static const struct clk_ops rockchip_rk3399_pll_clk_norate_ops = {
. recalc_rate = rockchip_rk3399_pll_recalc_rate ,
. enable = rockchip_rk3399_pll_enable ,
. disable = rockchip_rk3399_pll_disable ,
. is_enabled = rockchip_rk3399_pll_is_enabled ,
} ;
static const struct clk_ops rockchip_rk3399_pll_clk_ops = {
. recalc_rate = rockchip_rk3399_pll_recalc_rate ,
. round_rate = rockchip_pll_round_rate ,
. set_rate = rockchip_rk3399_pll_set_rate ,
. enable = rockchip_rk3399_pll_enable ,
. disable = rockchip_rk3399_pll_disable ,
. is_enabled = rockchip_rk3399_pll_is_enabled ,
. init = rockchip_rk3399_pll_init ,
} ;
2014-07-03 03:59:10 +04:00
/*
* Common registering of pll clocks
*/
2016-03-09 05:37:04 +03:00
struct clk * rockchip_clk_register_pll ( struct rockchip_clk_provider * ctx ,
enum rockchip_pll_type pll_type ,
2015-05-28 11:45:51 +03:00
const char * name , const char * const * parent_names ,
2016-03-09 05:37:04 +03:00
u8 num_parents , int con_offset , int grf_lock_offset ,
int lock_shift , int mode_offset , int mode_shift ,
struct rockchip_pll_rate_table * rate_table ,
2016-07-29 10:56:55 +03:00
unsigned long flags , u8 clk_pll_flags )
2014-07-03 03:59:10 +04:00
{
const char * pll_parents [ 3 ] ;
struct clk_init_data init ;
struct rockchip_clk_pll * pll ;
struct clk_mux * pll_mux ;
struct clk * pll_clk , * mux_clk ;
char pll_name [ 20 ] ;
if ( num_parents ! = 2 ) {
pr_err ( " %s: needs two parent clocks \n " , __func__ ) ;
return ERR_PTR ( - EINVAL ) ;
}
/* name the actual pll */
snprintf ( pll_name , sizeof ( pll_name ) , " pll_%s " , name ) ;
pll = kzalloc ( sizeof ( * pll ) , GFP_KERNEL ) ;
if ( ! pll )
return ERR_PTR ( - ENOMEM ) ;
2015-08-19 16:06:55 +03:00
/* create the mux on top of the real pll */
pll - > pll_mux_ops = & clk_mux_ops ;
pll_mux = & pll - > pll_mux ;
2016-03-09 05:37:04 +03:00
pll_mux - > reg = ctx - > reg_base + mode_offset ;
2015-08-19 16:06:55 +03:00
pll_mux - > shift = mode_shift ;
pll_mux - > mask = PLL_MODE_MASK ;
pll_mux - > flags = 0 ;
2016-03-09 05:37:04 +03:00
pll_mux - > lock = & ctx - > lock ;
2015-08-19 16:06:55 +03:00
pll_mux - > hw . init = & init ;
2016-03-10 06:47:01 +03:00
if ( pll_type = = pll_rk3036 | |
pll_type = = pll_rk3066 | |
pll_type = = pll_rk3399 )
2015-08-19 16:06:55 +03:00
pll_mux - > flags | = CLK_MUX_HIWORD_MASK ;
/* the actual muxing is xin24m, pll-output, xin32k */
pll_parents [ 0 ] = parent_names [ 0 ] ;
pll_parents [ 1 ] = pll_name ;
pll_parents [ 2 ] = parent_names [ 1 ] ;
init . name = name ;
init . flags = CLK_SET_RATE_PARENT ;
init . ops = pll - > pll_mux_ops ;
init . parent_names = pll_parents ;
init . num_parents = ARRAY_SIZE ( pll_parents ) ;
mux_clk = clk_register ( NULL , & pll_mux - > hw ) ;
if ( IS_ERR ( mux_clk ) )
goto err_mux ;
/* now create the actual pll */
2014-07-03 03:59:10 +04:00
init . name = pll_name ;
/* keep all plls untouched for now */
2016-07-29 10:56:55 +03:00
init . flags = flags | CLK_IGNORE_UNUSED ;
2014-07-03 03:59:10 +04:00
init . parent_names = & parent_names [ 0 ] ;
init . num_parents = 1 ;
if ( rate_table ) {
int len ;
/* find count of rates in rate_table */
for ( len = 0 ; rate_table [ len ] . rate ! = 0 ; )
len + + ;
pll - > rate_count = len ;
pll - > rate_table = kmemdup ( rate_table ,
pll - > rate_count *
sizeof ( struct rockchip_pll_rate_table ) ,
GFP_KERNEL ) ;
WARN ( ! pll - > rate_table ,
" %s: could not allocate rate table for %s \n " ,
__func__ , name ) ;
}
switch ( pll_type ) {
2015-11-05 10:33:57 +03:00
case pll_rk3036 :
2016-03-15 18:55:41 +03:00
if ( ! pll - > rate_table | | IS_ERR ( ctx - > grf ) )
2015-11-05 10:33:57 +03:00
init . ops = & rockchip_rk3036_pll_clk_norate_ops ;
else
init . ops = & rockchip_rk3036_pll_clk_ops ;
break ;
2014-07-03 03:59:10 +04:00
case pll_rk3066 :
2016-03-15 18:55:41 +03:00
if ( ! pll - > rate_table | | IS_ERR ( ctx - > grf ) )
2014-07-03 03:59:10 +04:00
init . ops = & rockchip_rk3066_pll_clk_norate_ops ;
else
init . ops = & rockchip_rk3066_pll_clk_ops ;
break ;
2016-03-10 06:47:01 +03:00
case pll_rk3399 :
if ( ! pll - > rate_table )
init . ops = & rockchip_rk3399_pll_clk_norate_ops ;
else
init . ops = & rockchip_rk3399_pll_clk_ops ;
break ;
2014-07-03 03:59:10 +04:00
default :
pr_warn ( " %s: Unknown pll type for pll clk %s \n " ,
__func__ , name ) ;
}
pll - > hw . init = & init ;
pll - > type = pll_type ;
2016-03-09 05:37:04 +03:00
pll - > reg_base = ctx - > reg_base + con_offset ;
2014-07-03 03:59:10 +04:00
pll - > lock_offset = grf_lock_offset ;
pll - > lock_shift = lock_shift ;
2014-11-20 22:38:50 +03:00
pll - > flags = clk_pll_flags ;
2016-03-09 05:37:04 +03:00
pll - > lock = & ctx - > lock ;
pll - > ctx = ctx ;
2014-07-03 03:59:10 +04:00
pll_clk = clk_register ( NULL , & pll - > hw ) ;
if ( IS_ERR ( pll_clk ) ) {
pr_err ( " %s: failed to register pll clock %s : %ld \n " ,
__func__ , name , PTR_ERR ( pll_clk ) ) ;
goto err_pll ;
}
return mux_clk ;
err_pll :
2015-08-19 16:06:55 +03:00
clk_unregister ( mux_clk ) ;
mux_clk = pll_clk ;
err_mux :
2014-07-03 03:59:10 +04:00
kfree ( pll ) ;
return mux_clk ;
}