2015-11-30 17:31:39 -08:00
/*
* Copyright ( c ) 2015 , The Linux Foundation . All rights reserved .
*
* This software is licensed under the terms of the GNU General Public
* License version 2 , as published by the Free Software Foundation , and
* may be copied , distributed , and modified under those terms .
*
* 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 <linux/kernel.h>
# include <linux/export.h>
# include <linux/clk-provider.h>
# include <linux/regmap.h>
# include <linux/delay.h>
# include "clk-alpha-pll.h"
2016-09-29 14:05:45 +05:30
# include "common.h"
2015-11-30 17:31:39 -08:00
2017-09-28 23:20:40 +05:30
# define PLL_MODE(p) ((p)->offset + 0x0)
2015-11-30 17:31:39 -08:00
# define PLL_OUTCTRL BIT(0)
# define PLL_BYPASSNL BIT(1)
# define PLL_RESET_N BIT(2)
2016-09-29 14:05:42 +05:30
# define PLL_OFFLINE_REQ BIT(7)
2015-11-30 17:31:39 -08:00
# define PLL_LOCK_COUNT_SHIFT 8
# define PLL_LOCK_COUNT_MASK 0x3f
# define PLL_BIAS_COUNT_SHIFT 14
# define PLL_BIAS_COUNT_MASK 0x3f
# define PLL_VOTE_FSM_ENA BIT(20)
2016-09-29 14:05:42 +05:30
# define PLL_FSM_ENA BIT(20)
2015-11-30 17:31:39 -08:00
# define PLL_VOTE_FSM_RESET BIT(21)
2017-09-28 23:20:45 +05:30
# define PLL_UPDATE BIT(22)
# define PLL_UPDATE_BYPASS BIT(23)
2016-09-29 14:05:42 +05:30
# define PLL_OFFLINE_ACK BIT(28)
2017-09-28 23:20:45 +05:30
# define ALPHA_PLL_ACK_LATCH BIT(29)
2015-11-30 17:31:39 -08:00
# define PLL_ACTIVE_FLAG BIT(30)
# define PLL_LOCK_DET BIT(31)
2017-09-28 23:20:40 +05:30
# define PLL_L_VAL(p) ((p)->offset + (p)->regs[PLL_OFF_L_VAL])
# define PLL_ALPHA_VAL(p) ((p)->offset + (p)->regs[PLL_OFF_ALPHA_VAL])
# define PLL_ALPHA_VAL_U(p) ((p)->offset + (p)->regs[PLL_OFF_ALPHA_VAL_U])
2015-11-30 17:31:39 -08:00
2017-09-28 23:20:40 +05:30
# define PLL_USER_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL])
2015-11-30 17:31:39 -08:00
# define PLL_POST_DIV_SHIFT 8
# define PLL_POST_DIV_MASK 0xf
# define PLL_ALPHA_EN BIT(24)
# define PLL_VCO_SHIFT 20
# define PLL_VCO_MASK 0x3
2017-09-28 23:20:40 +05:30
# define PLL_USER_CTL_U(p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL_U])
# define PLL_CONFIG_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL])
# define PLL_CONFIG_CTL_U(p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL_U])
# define PLL_TEST_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL])
# define PLL_TEST_CTL_U(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL_U])
# define PLL_STATUS(p) ((p)->offset + (p)->regs[PLL_OFF_STATUS])
const u8 clk_alpha_pll_regs [ ] [ PLL_OFF_MAX_REGS ] = {
[ CLK_ALPHA_PLL_TYPE_DEFAULT ] = {
[ PLL_OFF_L_VAL ] = 0x04 ,
[ PLL_OFF_ALPHA_VAL ] = 0x08 ,
[ PLL_OFF_ALPHA_VAL_U ] = 0x0c ,
[ PLL_OFF_USER_CTL ] = 0x10 ,
[ PLL_OFF_USER_CTL_U ] = 0x14 ,
[ PLL_OFF_CONFIG_CTL ] = 0x18 ,
[ PLL_OFF_TEST_CTL ] = 0x1c ,
[ PLL_OFF_TEST_CTL_U ] = 0x20 ,
[ PLL_OFF_STATUS ] = 0x24 ,
} ,
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_regs ) ;
2015-11-30 17:31:39 -08:00
/*
* Even though 40 bits are present , use only 32 for ease of calculation .
*/
# define ALPHA_REG_BITWIDTH 40
2017-09-28 23:20:41 +05:30
# define ALPHA_REG_16BIT_WIDTH 16
# define ALPHA_BITWIDTH 32U
# define ALPHA_SHIFT(w) min(w, ALPHA_BITWIDTH)
# define pll_alpha_width(p) \
( ( PLL_ALPHA_VAL_U ( p ) - PLL_ALPHA_VAL ( p ) = = 4 ) ? \
ALPHA_REG_BITWIDTH : ALPHA_REG_16BIT_WIDTH )
2015-11-30 17:31:39 -08:00
2017-09-28 23:20:43 +05:30
# define pll_has_64bit_config(p) ((PLL_CONFIG_CTL_U(p) - PLL_CONFIG_CTL(p)) == 4)
2015-11-30 17:31:39 -08:00
# define to_clk_alpha_pll(_hw) container_of(to_clk_regmap(_hw), \
struct clk_alpha_pll , clkr )
# define to_clk_alpha_pll_postdiv(_hw) container_of(to_clk_regmap(_hw), \
struct clk_alpha_pll_postdiv , clkr )
2016-09-29 14:05:42 +05:30
static int wait_for_pll ( struct clk_alpha_pll * pll , u32 mask , bool inverse ,
const char * action )
2015-11-30 17:31:39 -08:00
{
2017-09-28 23:20:40 +05:30
u32 val ;
2015-11-30 17:31:39 -08:00
int count ;
int ret ;
const char * name = clk_hw_get_name ( & pll - > clkr . hw ) ;
2017-09-28 23:20:40 +05:30
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2015-11-30 17:31:39 -08:00
if ( ret )
return ret ;
for ( count = 100 ; count > 0 ; count - - ) {
2017-09-28 23:20:40 +05:30
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2015-11-30 17:31:39 -08:00
if ( ret )
return ret ;
2016-09-29 14:05:42 +05:30
if ( inverse & & ! ( val & mask ) )
return 0 ;
else if ( ( val & mask ) = = mask )
2015-11-30 17:31:39 -08:00
return 0 ;
udelay ( 1 ) ;
}
2016-09-29 14:05:42 +05:30
WARN ( 1 , " %s failed to %s! \n " , name , action ) ;
2015-11-30 17:31:39 -08:00
return - ETIMEDOUT ;
}
2016-09-29 14:05:42 +05:30
# define wait_for_pll_enable_active(pll) \
wait_for_pll ( pll , PLL_ACTIVE_FLAG , 0 , " enable " )
# define wait_for_pll_enable_lock(pll) \
wait_for_pll ( pll , PLL_LOCK_DET , 0 , " enable " )
# define wait_for_pll_disable(pll) \
wait_for_pll ( pll , PLL_ACTIVE_FLAG , 1 , " disable " )
# define wait_for_pll_offline(pll) \
wait_for_pll ( pll , PLL_OFFLINE_ACK , 0 , " offline " )
2017-09-28 23:20:45 +05:30
# define wait_for_pll_update(pll) \
wait_for_pll ( pll , PLL_UPDATE , 1 , " update " )
# define wait_for_pll_update_ack_set(pll) \
wait_for_pll ( pll , ALPHA_PLL_ACK_LATCH , 0 , " update_ack_set " )
# define wait_for_pll_update_ack_clear(pll) \
wait_for_pll ( pll , ALPHA_PLL_ACK_LATCH , 1 , " update_ack_clear " )
2016-09-29 14:05:43 +05:30
void clk_alpha_pll_configure ( struct clk_alpha_pll * pll , struct regmap * regmap ,
const struct alpha_pll_config * config )
{
u32 val , mask ;
2017-09-28 23:20:40 +05:30
regmap_write ( regmap , PLL_L_VAL ( pll ) , config - > l ) ;
regmap_write ( regmap , PLL_ALPHA_VAL ( pll ) , config - > alpha ) ;
regmap_write ( regmap , PLL_CONFIG_CTL ( pll ) , config - > config_ctl_val ) ;
2017-09-28 23:20:43 +05:30
if ( pll_has_64bit_config ( pll ) )
regmap_write ( regmap , PLL_CONFIG_CTL_U ( pll ) ,
config - > config_ctl_hi_val ) ;
2016-09-29 14:05:43 +05:30
2017-09-28 23:20:44 +05:30
if ( pll_alpha_width ( pll ) > 32 )
regmap_write ( regmap , PLL_ALPHA_VAL_U ( pll ) , config - > alpha_hi ) ;
2016-09-29 14:05:43 +05:30
val = config - > main_output_mask ;
val | = config - > aux_output_mask ;
val | = config - > aux2_output_mask ;
val | = config - > early_output_mask ;
val | = config - > pre_div_val ;
val | = config - > post_div_val ;
val | = config - > vco_val ;
2017-09-28 23:20:44 +05:30
val | = config - > alpha_en_mask ;
val | = config - > alpha_mode_mask ;
2016-09-29 14:05:43 +05:30
mask = config - > main_output_mask ;
mask | = config - > aux_output_mask ;
mask | = config - > aux2_output_mask ;
mask | = config - > early_output_mask ;
mask | = config - > pre_div_mask ;
mask | = config - > post_div_mask ;
mask | = config - > vco_mask ;
2017-09-28 23:20:40 +05:30
regmap_update_bits ( regmap , PLL_USER_CTL ( pll ) , mask , val ) ;
2016-09-29 14:05:45 +05:30
if ( pll - > flags & SUPPORTS_FSM_MODE )
2017-09-28 23:20:40 +05:30
qcom_pll_set_fsm_mode ( regmap , PLL_MODE ( pll ) , 6 , 0 ) ;
2016-09-29 14:05:43 +05:30
}
2016-09-29 14:05:42 +05:30
static int clk_alpha_pll_hwfsm_enable ( struct clk_hw * hw )
{
int ret ;
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
2017-09-28 23:20:40 +05:30
u32 val ;
2016-09-29 14:05:42 +05:30
2017-09-28 23:20:40 +05:30
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2016-09-29 14:05:42 +05:30
if ( ret )
return ret ;
val | = PLL_FSM_ENA ;
if ( pll - > flags & SUPPORTS_OFFLINE_REQ )
val & = ~ PLL_OFFLINE_REQ ;
2017-09-28 23:20:40 +05:30
ret = regmap_write ( pll - > clkr . regmap , PLL_MODE ( pll ) , val ) ;
2016-09-29 14:05:42 +05:30
if ( ret )
return ret ;
/* Make sure enable request goes through before waiting for update */
mb ( ) ;
return wait_for_pll_enable_active ( pll ) ;
}
static void clk_alpha_pll_hwfsm_disable ( struct clk_hw * hw )
{
int ret ;
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
2017-09-28 23:20:40 +05:30
u32 val ;
2016-09-29 14:05:42 +05:30
2017-09-28 23:20:40 +05:30
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2016-09-29 14:05:42 +05:30
if ( ret )
return ;
if ( pll - > flags & SUPPORTS_OFFLINE_REQ ) {
2017-09-28 23:20:40 +05:30
ret = regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) ,
2016-09-29 14:05:42 +05:30
PLL_OFFLINE_REQ , PLL_OFFLINE_REQ ) ;
if ( ret )
return ;
ret = wait_for_pll_offline ( pll ) ;
if ( ret )
return ;
}
/* Disable hwfsm */
2017-09-28 23:20:40 +05:30
ret = regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) ,
2016-09-29 14:05:42 +05:30
PLL_FSM_ENA , 0 ) ;
if ( ret )
return ;
wait_for_pll_disable ( pll ) ;
}
2016-09-29 14:05:46 +05:30
static int pll_is_enabled ( struct clk_hw * hw , u32 mask )
{
int ret ;
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
2017-09-28 23:20:40 +05:30
u32 val ;
2016-09-29 14:05:46 +05:30
2017-09-28 23:20:40 +05:30
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2016-09-29 14:05:46 +05:30
if ( ret )
return ret ;
return ! ! ( val & mask ) ;
}
static int clk_alpha_pll_hwfsm_is_enabled ( struct clk_hw * hw )
{
return pll_is_enabled ( hw , PLL_ACTIVE_FLAG ) ;
}
static int clk_alpha_pll_is_enabled ( struct clk_hw * hw )
{
return pll_is_enabled ( hw , PLL_LOCK_DET ) ;
}
2015-11-30 17:31:39 -08:00
static int clk_alpha_pll_enable ( struct clk_hw * hw )
{
int ret ;
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
2017-09-28 23:20:40 +05:30
u32 val , mask ;
2015-11-30 17:31:39 -08:00
mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL ;
2017-09-28 23:20:40 +05:30
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2015-11-30 17:31:39 -08:00
if ( ret )
return ret ;
/* If in FSM mode, just vote for it */
if ( val & PLL_VOTE_FSM_ENA ) {
ret = clk_enable_regmap ( hw ) ;
if ( ret )
return ret ;
2016-09-29 14:05:42 +05:30
return wait_for_pll_enable_active ( pll ) ;
2015-11-30 17:31:39 -08:00
}
/* Skip if already enabled */
if ( ( val & mask ) = = mask )
return 0 ;
2017-09-28 23:20:40 +05:30
ret = regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) ,
2015-11-30 17:31:39 -08:00
PLL_BYPASSNL , PLL_BYPASSNL ) ;
if ( ret )
return ret ;
/*
* H / W requires a 5u s delay between disabling the bypass and
* de - asserting the reset .
*/
mb ( ) ;
udelay ( 5 ) ;
2017-09-28 23:20:40 +05:30
ret = regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) ,
2015-11-30 17:31:39 -08:00
PLL_RESET_N , PLL_RESET_N ) ;
if ( ret )
return ret ;
2016-09-29 14:05:42 +05:30
ret = wait_for_pll_enable_lock ( pll ) ;
2015-11-30 17:31:39 -08:00
if ( ret )
return ret ;
2017-09-28 23:20:40 +05:30
ret = regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) ,
2015-11-30 17:31:39 -08:00
PLL_OUTCTRL , PLL_OUTCTRL ) ;
/* Ensure that the write above goes through before returning. */
mb ( ) ;
return ret ;
}
static void clk_alpha_pll_disable ( struct clk_hw * hw )
{
int ret ;
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
2017-09-28 23:20:40 +05:30
u32 val , mask ;
2015-11-30 17:31:39 -08:00
2017-09-28 23:20:40 +05:30
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2015-11-30 17:31:39 -08:00
if ( ret )
return ;
/* If in FSM mode, just unvote it */
if ( val & PLL_VOTE_FSM_ENA ) {
clk_disable_regmap ( hw ) ;
return ;
}
mask = PLL_OUTCTRL ;
2017-09-28 23:20:40 +05:30
regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) , mask , 0 ) ;
2015-11-30 17:31:39 -08:00
/* Delay of 2 output clock ticks required until output is disabled */
mb ( ) ;
udelay ( 1 ) ;
mask = PLL_RESET_N | PLL_BYPASSNL ;
2017-09-28 23:20:40 +05:30
regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) , mask , 0 ) ;
2015-11-30 17:31:39 -08:00
}
2017-09-28 23:20:41 +05:30
static unsigned long
alpha_pll_calc_rate ( u64 prate , u32 l , u32 a , u32 alpha_width )
2015-11-30 17:31:39 -08:00
{
2017-09-28 23:20:41 +05:30
return ( prate * l ) + ( ( prate * a ) > > ALPHA_SHIFT ( alpha_width ) ) ;
2015-11-30 17:31:39 -08:00
}
static unsigned long
2017-09-28 23:20:41 +05:30
alpha_pll_round_rate ( unsigned long rate , unsigned long prate , u32 * l , u64 * a ,
u32 alpha_width )
2015-11-30 17:31:39 -08:00
{
u64 remainder ;
u64 quotient ;
quotient = rate ;
remainder = do_div ( quotient , prate ) ;
* l = quotient ;
if ( ! remainder ) {
* a = 0 ;
return rate ;
}
/* Upper ALPHA_BITWIDTH bits of Alpha */
2017-09-28 23:20:41 +05:30
quotient = remainder < < ALPHA_SHIFT ( alpha_width ) ;
2015-11-30 17:31:39 -08:00
remainder = do_div ( quotient , prate ) ;
if ( remainder )
quotient + + ;
* a = quotient ;
2017-09-28 23:20:41 +05:30
return alpha_pll_calc_rate ( prate , * l , * a , alpha_width ) ;
2015-11-30 17:31:39 -08:00
}
static const struct pll_vco *
alpha_pll_find_vco ( const struct clk_alpha_pll * pll , unsigned long rate )
{
const struct pll_vco * v = pll - > vco_table ;
const struct pll_vco * end = v + pll - > num_vco ;
for ( ; v < end ; v + + )
if ( rate > = v - > min_freq & & rate < = v - > max_freq )
return v ;
return NULL ;
}
static unsigned long
clk_alpha_pll_recalc_rate ( struct clk_hw * hw , unsigned long parent_rate )
{
u32 l , low , high , ctl ;
u64 a = 0 , prate = parent_rate ;
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
2017-09-28 23:20:41 +05:30
u32 alpha_width = pll_alpha_width ( pll ) ;
2015-11-30 17:31:39 -08:00
2017-09-28 23:20:40 +05:30
regmap_read ( pll - > clkr . regmap , PLL_L_VAL ( pll ) , & l ) ;
2015-11-30 17:31:39 -08:00
2017-09-28 23:20:40 +05:30
regmap_read ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) , & ctl ) ;
2015-11-30 17:31:39 -08:00
if ( ctl & PLL_ALPHA_EN ) {
2017-09-28 23:20:40 +05:30
regmap_read ( pll - > clkr . regmap , PLL_ALPHA_VAL ( pll ) , & low ) ;
2017-09-28 23:20:41 +05:30
if ( alpha_width > 32 ) {
2017-09-28 23:20:40 +05:30
regmap_read ( pll - > clkr . regmap , PLL_ALPHA_VAL_U ( pll ) ,
2016-09-29 14:05:44 +05:30
& high ) ;
a = ( u64 ) high < < 32 | low ;
2017-09-28 23:20:41 +05:30
} else {
a = low & GENMASK ( alpha_width - 1 , 0 ) ;
2016-09-29 14:05:44 +05:30
}
2017-09-28 23:20:41 +05:30
if ( alpha_width > ALPHA_BITWIDTH )
a > > = alpha_width - ALPHA_BITWIDTH ;
2015-11-30 17:31:39 -08:00
}
2017-09-28 23:20:41 +05:30
return alpha_pll_calc_rate ( prate , l , a , alpha_width ) ;
2015-11-30 17:31:39 -08:00
}
2017-09-28 23:20:45 +05:30
static int clk_alpha_pll_update_latch ( struct clk_alpha_pll * pll ,
int ( * is_enabled ) ( struct clk_hw * ) )
{
int ret ;
u32 mode ;
if ( ! is_enabled ( & pll - > clkr . hw ) | |
! ( pll - > flags & SUPPORTS_DYNAMIC_UPDATE ) )
return 0 ;
regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & mode ) ;
/* Latch the input to the PLL */
regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) , PLL_UPDATE ,
PLL_UPDATE ) ;
/* Wait for 2 reference cycle before checking ACK bit */
udelay ( 1 ) ;
/*
* PLL will latch the new L , Alpha and freq control word .
* PLL will respond by raising PLL_ACK_LATCH output when new programming
* has been latched in and PLL is being updated . When
* UPDATE_LOGIC_BYPASS bit is not set , PLL_UPDATE will be cleared
* automatically by hardware when PLL_ACK_LATCH is asserted by PLL .
*/
if ( mode & PLL_UPDATE_BYPASS ) {
ret = wait_for_pll_update_ack_set ( pll ) ;
if ( ret )
return ret ;
regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) , PLL_UPDATE , 0 ) ;
} else {
ret = wait_for_pll_update ( pll ) ;
if ( ret )
return ret ;
}
ret = wait_for_pll_update_ack_clear ( pll ) ;
if ( ret )
return ret ;
/* Wait for PLL output to stabilize */
udelay ( 10 ) ;
return 0 ;
}
static int __clk_alpha_pll_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long prate ,
int ( * is_enabled ) ( struct clk_hw * ) )
2015-11-30 17:31:39 -08:00
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
const struct pll_vco * vco ;
2017-09-28 23:20:41 +05:30
u32 l , alpha_width = pll_alpha_width ( pll ) ;
2015-11-30 17:31:39 -08:00
u64 a ;
2017-09-28 23:20:41 +05:30
rate = alpha_pll_round_rate ( rate , prate , & l , & a , alpha_width ) ;
2015-11-30 17:31:39 -08:00
vco = alpha_pll_find_vco ( pll , rate ) ;
if ( ! vco ) {
pr_err ( " alpha pll not in a valid vco range \n " ) ;
return - EINVAL ;
}
2017-09-28 23:20:40 +05:30
regmap_write ( pll - > clkr . regmap , PLL_L_VAL ( pll ) , l ) ;
2016-09-29 14:05:44 +05:30
2017-09-28 23:20:41 +05:30
if ( alpha_width > ALPHA_BITWIDTH )
a < < = alpha_width - ALPHA_BITWIDTH ;
if ( alpha_width > 32 )
regmap_write ( pll - > clkr . regmap , PLL_ALPHA_VAL_U ( pll ) , a > > 32 ) ;
regmap_write ( pll - > clkr . regmap , PLL_ALPHA_VAL ( pll ) , a ) ;
2015-11-30 17:31:39 -08:00
2017-09-28 23:20:40 +05:30
regmap_update_bits ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) ,
2015-11-30 17:31:39 -08:00
PLL_VCO_MASK < < PLL_VCO_SHIFT ,
vco - > val < < PLL_VCO_SHIFT ) ;
2017-09-28 23:20:40 +05:30
regmap_update_bits ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) ,
PLL_ALPHA_EN , PLL_ALPHA_EN ) ;
2015-11-30 17:31:39 -08:00
2017-09-28 23:20:45 +05:30
return clk_alpha_pll_update_latch ( pll , is_enabled ) ;
}
static int clk_alpha_pll_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long prate )
{
return __clk_alpha_pll_set_rate ( hw , rate , prate ,
clk_alpha_pll_is_enabled ) ;
}
static int clk_alpha_pll_hwfsm_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long prate )
{
return __clk_alpha_pll_set_rate ( hw , rate , prate ,
clk_alpha_pll_hwfsm_is_enabled ) ;
2015-11-30 17:31:39 -08:00
}
static long clk_alpha_pll_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
2017-09-28 23:20:41 +05:30
u32 l , alpha_width = pll_alpha_width ( pll ) ;
2015-11-30 17:31:39 -08:00
u64 a ;
unsigned long min_freq , max_freq ;
2017-09-28 23:20:41 +05:30
rate = alpha_pll_round_rate ( rate , * prate , & l , & a , alpha_width ) ;
2015-11-30 17:31:39 -08:00
if ( alpha_pll_find_vco ( pll , rate ) )
return rate ;
min_freq = pll - > vco_table [ 0 ] . min_freq ;
max_freq = pll - > vco_table [ pll - > num_vco - 1 ] . max_freq ;
return clamp ( rate , min_freq , max_freq ) ;
}
const struct clk_ops clk_alpha_pll_ops = {
. enable = clk_alpha_pll_enable ,
. disable = clk_alpha_pll_disable ,
2016-09-29 14:05:46 +05:30
. is_enabled = clk_alpha_pll_is_enabled ,
2015-11-30 17:31:39 -08:00
. recalc_rate = clk_alpha_pll_recalc_rate ,
. round_rate = clk_alpha_pll_round_rate ,
. set_rate = clk_alpha_pll_set_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_ops ) ;
2016-09-29 14:05:42 +05:30
const struct clk_ops clk_alpha_pll_hwfsm_ops = {
. enable = clk_alpha_pll_hwfsm_enable ,
. disable = clk_alpha_pll_hwfsm_disable ,
2016-09-29 14:05:46 +05:30
. is_enabled = clk_alpha_pll_hwfsm_is_enabled ,
2016-09-29 14:05:42 +05:30
. recalc_rate = clk_alpha_pll_recalc_rate ,
. round_rate = clk_alpha_pll_round_rate ,
2017-09-28 23:20:45 +05:30
. set_rate = clk_alpha_pll_hwfsm_set_rate ,
2016-09-29 14:05:42 +05:30
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_hwfsm_ops ) ;
2015-11-30 17:31:39 -08:00
static unsigned long
clk_alpha_pll_postdiv_recalc_rate ( struct clk_hw * hw , unsigned long parent_rate )
{
struct clk_alpha_pll_postdiv * pll = to_clk_alpha_pll_postdiv ( hw ) ;
u32 ctl ;
2017-09-28 23:20:40 +05:30
regmap_read ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) , & ctl ) ;
2015-11-30 17:31:39 -08:00
ctl > > = PLL_POST_DIV_SHIFT ;
ctl & = PLL_POST_DIV_MASK ;
return parent_rate > > fls ( ctl ) ;
}
static const struct clk_div_table clk_alpha_div_table [ ] = {
{ 0x0 , 1 } ,
{ 0x1 , 2 } ,
{ 0x3 , 4 } ,
{ 0x7 , 8 } ,
{ 0xf , 16 } ,
{ }
} ;
static long
clk_alpha_pll_postdiv_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
struct clk_alpha_pll_postdiv * pll = to_clk_alpha_pll_postdiv ( hw ) ;
return divider_round_rate ( hw , rate , prate , clk_alpha_div_table ,
pll - > width , CLK_DIVIDER_POWER_OF_TWO ) ;
}
static int clk_alpha_pll_postdiv_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct clk_alpha_pll_postdiv * pll = to_clk_alpha_pll_postdiv ( hw ) ;
int div ;
/* 16 -> 0xf, 8 -> 0x7, 4 -> 0x3, 2 -> 0x1, 1 -> 0x0 */
div = DIV_ROUND_UP_ULL ( ( u64 ) parent_rate , rate ) - 1 ;
2017-09-28 23:20:40 +05:30
return regmap_update_bits ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) ,
2015-11-30 17:31:39 -08:00
PLL_POST_DIV_MASK < < PLL_POST_DIV_SHIFT ,
div < < PLL_POST_DIV_SHIFT ) ;
}
const struct clk_ops clk_alpha_pll_postdiv_ops = {
. recalc_rate = clk_alpha_pll_postdiv_recalc_rate ,
. round_rate = clk_alpha_pll_postdiv_round_rate ,
. set_rate = clk_alpha_pll_postdiv_set_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_postdiv_ops ) ;