2018-07-16 08:54:32 +03:00
// SPDX-License-Identifier: GPL-2.0
2015-12-01 04:31:39 +03:00
/*
2018-03-08 10:18:14 +03:00
* Copyright ( c ) 2015 , 2018 , The Linux Foundation . All rights reserved .
2015-12-01 04:31:39 +03:00
*/
# 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 11:35:45 +03:00
# include "common.h"
2015-12-01 04:31:39 +03:00
2017-09-28 20:50:40 +03:00
# define PLL_MODE(p) ((p)->offset + 0x0)
2015-12-01 04:31:39 +03:00
# define PLL_OUTCTRL BIT(0)
# define PLL_BYPASSNL BIT(1)
# define PLL_RESET_N BIT(2)
2016-09-29 11:35:42 +03:00
# define PLL_OFFLINE_REQ BIT(7)
2015-12-01 04:31:39 +03: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 11:35:42 +03:00
# define PLL_FSM_ENA BIT(20)
2015-12-01 04:31:39 +03:00
# define PLL_VOTE_FSM_RESET BIT(21)
2017-09-28 20:50:45 +03:00
# define PLL_UPDATE BIT(22)
# define PLL_UPDATE_BYPASS BIT(23)
2016-09-29 11:35:42 +03:00
# define PLL_OFFLINE_ACK BIT(28)
2017-09-28 20:50:45 +03:00
# define ALPHA_PLL_ACK_LATCH BIT(29)
2015-12-01 04:31:39 +03:00
# define PLL_ACTIVE_FLAG BIT(30)
# define PLL_LOCK_DET BIT(31)
2017-09-28 20:50:40 +03:00
# define PLL_L_VAL(p) ((p)->offset + (p)->regs[PLL_OFF_L_VAL])
2019-07-22 10:43:46 +03:00
# define PLL_CAL_L_VAL(p) ((p)->offset + (p)->regs[PLL_OFF_CAL_L_VAL])
2017-09-28 20:50:40 +03:00
# 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-12-01 04:31:39 +03:00
2017-09-28 20:50:40 +03:00
# define PLL_USER_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL])
2015-12-01 04:31:39 +03:00
# define PLL_POST_DIV_SHIFT 8
2017-09-28 20:50:49 +03:00
# define PLL_POST_DIV_MASK(p) GENMASK((p)->width, 0)
2015-12-01 04:31:39 +03:00
# define PLL_ALPHA_EN BIT(24)
2017-09-28 20:50:46 +03:00
# define PLL_ALPHA_MODE BIT(25)
2015-12-01 04:31:39 +03:00
# define PLL_VCO_SHIFT 20
# define PLL_VCO_MASK 0x3
2017-09-28 20:50:40 +03:00
# define PLL_USER_CTL_U(p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL_U])
2019-07-22 10:43:46 +03:00
# define PLL_USER_CTL_U1(p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL_U1])
2017-09-28 20:50:40 +03:00
# 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])
2019-07-22 10:43:46 +03:00
# define PLL_CONFIG_CTL_U1(p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL_U1])
2017-09-28 20:50:40 +03:00
# 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])
2020-02-24 07:50:01 +03:00
# define PLL_TEST_CTL_U1(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL_U1])
2017-09-28 20:50:40 +03:00
# define PLL_STATUS(p) ((p)->offset + (p)->regs[PLL_OFF_STATUS])
2018-03-08 10:18:14 +03:00
# define PLL_OPMODE(p) ((p)->offset + (p)->regs[PLL_OFF_OPMODE])
# define PLL_FRAC(p) ((p)->offset + (p)->regs[PLL_OFF_FRAC])
2019-07-22 10:43:46 +03:00
# define PLL_CAL_VAL(p) ((p)->offset + (p)->regs[PLL_OFF_CAL_VAL])
2017-09-28 20:50:40 +03:00
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 ,
} ,
2017-09-28 20:50:46 +03:00
[ CLK_ALPHA_PLL_TYPE_HUAYRA ] = {
[ PLL_OFF_L_VAL ] = 0x04 ,
[ PLL_OFF_ALPHA_VAL ] = 0x08 ,
[ PLL_OFF_USER_CTL ] = 0x10 ,
[ PLL_OFF_CONFIG_CTL ] = 0x14 ,
[ PLL_OFF_CONFIG_CTL_U ] = 0x18 ,
[ PLL_OFF_TEST_CTL ] = 0x1c ,
[ PLL_OFF_TEST_CTL_U ] = 0x20 ,
[ PLL_OFF_STATUS ] = 0x24 ,
} ,
2017-09-28 20:50:48 +03:00
[ CLK_ALPHA_PLL_TYPE_BRAMMO ] = {
[ PLL_OFF_L_VAL ] = 0x04 ,
[ PLL_OFF_ALPHA_VAL ] = 0x08 ,
[ PLL_OFF_ALPHA_VAL_U ] = 0x0c ,
[ PLL_OFF_USER_CTL ] = 0x10 ,
[ PLL_OFF_CONFIG_CTL ] = 0x18 ,
[ PLL_OFF_TEST_CTL ] = 0x1c ,
[ PLL_OFF_STATUS ] = 0x24 ,
} ,
2018-03-08 10:18:14 +03:00
[ CLK_ALPHA_PLL_TYPE_FABIA ] = {
[ PLL_OFF_L_VAL ] = 0x04 ,
[ PLL_OFF_USER_CTL ] = 0x0c ,
[ PLL_OFF_USER_CTL_U ] = 0x10 ,
[ PLL_OFF_CONFIG_CTL ] = 0x14 ,
[ PLL_OFF_CONFIG_CTL_U ] = 0x18 ,
[ PLL_OFF_TEST_CTL ] = 0x1c ,
[ PLL_OFF_TEST_CTL_U ] = 0x20 ,
[ PLL_OFF_STATUS ] = 0x24 ,
[ PLL_OFF_OPMODE ] = 0x2c ,
[ PLL_OFF_FRAC ] = 0x38 ,
} ,
2019-07-22 10:43:46 +03:00
[ CLK_ALPHA_PLL_TYPE_TRION ] = {
[ PLL_OFF_L_VAL ] = 0x04 ,
[ PLL_OFF_CAL_L_VAL ] = 0x08 ,
[ PLL_OFF_USER_CTL ] = 0x0c ,
[ PLL_OFF_USER_CTL_U ] = 0x10 ,
[ PLL_OFF_USER_CTL_U1 ] = 0x14 ,
[ PLL_OFF_CONFIG_CTL ] = 0x18 ,
[ PLL_OFF_CONFIG_CTL_U ] = 0x1c ,
[ PLL_OFF_CONFIG_CTL_U1 ] = 0x20 ,
[ PLL_OFF_TEST_CTL ] = 0x24 ,
[ PLL_OFF_TEST_CTL_U ] = 0x28 ,
[ PLL_OFF_STATUS ] = 0x30 ,
[ PLL_OFF_OPMODE ] = 0x38 ,
[ PLL_OFF_ALPHA_VAL ] = 0x40 ,
[ PLL_OFF_CAL_VAL ] = 0x44 ,
} ,
2020-02-24 07:50:01 +03:00
[ CLK_ALPHA_PLL_TYPE_LUCID ] = {
[ PLL_OFF_L_VAL ] = 0x04 ,
[ PLL_OFF_CAL_L_VAL ] = 0x08 ,
[ PLL_OFF_USER_CTL ] = 0x0c ,
[ PLL_OFF_USER_CTL_U ] = 0x10 ,
[ PLL_OFF_USER_CTL_U1 ] = 0x14 ,
[ PLL_OFF_CONFIG_CTL ] = 0x18 ,
[ PLL_OFF_CONFIG_CTL_U ] = 0x1c ,
[ PLL_OFF_CONFIG_CTL_U1 ] = 0x20 ,
[ PLL_OFF_TEST_CTL ] = 0x24 ,
[ PLL_OFF_TEST_CTL_U ] = 0x28 ,
[ PLL_OFF_TEST_CTL_U1 ] = 0x2c ,
[ PLL_OFF_STATUS ] = 0x30 ,
[ PLL_OFF_OPMODE ] = 0x38 ,
[ PLL_OFF_ALPHA_VAL ] = 0x40 ,
} ,
2017-09-28 20:50:40 +03:00
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_regs ) ;
2015-12-01 04:31:39 +03:00
/*
* Even though 40 bits are present , use only 32 for ease of calculation .
*/
# define ALPHA_REG_BITWIDTH 40
2017-09-28 20:50:41 +03:00
# define ALPHA_REG_16BIT_WIDTH 16
# define ALPHA_BITWIDTH 32U
# define ALPHA_SHIFT(w) min(w, ALPHA_BITWIDTH)
2017-09-28 20:50:46 +03:00
# define PLL_HUAYRA_M_WIDTH 8
# define PLL_HUAYRA_M_SHIFT 8
# define PLL_HUAYRA_M_MASK 0xff
# define PLL_HUAYRA_N_SHIFT 0
# define PLL_HUAYRA_N_MASK 0xff
# define PLL_HUAYRA_ALPHA_WIDTH 16
2020-02-24 07:49:59 +03:00
# define PLL_STANDBY 0x0
# define PLL_RUN 0x1
# define PLL_OUT_MASK 0x7
# define PLL_RATE_MARGIN 500
2019-07-22 10:43:46 +03:00
2020-02-24 07:50:01 +03:00
/* LUCID PLL specific settings and offsets */
# define LUCID_PLL_CAL_VAL 0x44
# define LUCID_PCAL_DONE BIT(26)
2017-09-28 20:50:41 +03:00
# define pll_alpha_width(p) \
( ( PLL_ALPHA_VAL_U ( p ) - PLL_ALPHA_VAL ( p ) = = 4 ) ? \
ALPHA_REG_BITWIDTH : ALPHA_REG_16BIT_WIDTH )
2015-12-01 04:31:39 +03:00
2017-09-28 20:50:43 +03:00
# define pll_has_64bit_config(p) ((PLL_CONFIG_CTL_U(p) - PLL_CONFIG_CTL(p)) == 4)
2015-12-01 04:31:39 +03: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 11:35:42 +03:00
static int wait_for_pll ( struct clk_alpha_pll * pll , u32 mask , bool inverse ,
const char * action )
2015-12-01 04:31:39 +03:00
{
2017-09-28 20:50:40 +03:00
u32 val ;
2015-12-01 04:31:39 +03:00
int count ;
int ret ;
const char * name = clk_hw_get_name ( & pll - > clkr . hw ) ;
2017-09-28 20:50:40 +03:00
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2015-12-01 04:31:39 +03:00
if ( ret )
return ret ;
for ( count = 100 ; count > 0 ; count - - ) {
2017-09-28 20:50:40 +03:00
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2015-12-01 04:31:39 +03:00
if ( ret )
return ret ;
2016-09-29 11:35:42 +03:00
if ( inverse & & ! ( val & mask ) )
return 0 ;
else if ( ( val & mask ) = = mask )
2015-12-01 04:31:39 +03:00
return 0 ;
udelay ( 1 ) ;
}
2016-09-29 11:35:42 +03:00
WARN ( 1 , " %s failed to %s! \n " , name , action ) ;
2015-12-01 04:31:39 +03:00
return - ETIMEDOUT ;
}
2016-09-29 11:35:42 +03:00
# 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 20:50:45 +03:00
# 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 11:35:43 +03:00
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 20:50:40 +03:00
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 20:50:43 +03:00
if ( pll_has_64bit_config ( pll ) )
regmap_write ( regmap , PLL_CONFIG_CTL_U ( pll ) ,
config - > config_ctl_hi_val ) ;
2016-09-29 11:35:43 +03:00
2017-09-28 20:50:44 +03:00
if ( pll_alpha_width ( pll ) > 32 )
regmap_write ( regmap , PLL_ALPHA_VAL_U ( pll ) , config - > alpha_hi ) ;
2016-09-29 11:35:43 +03:00
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 20:50:44 +03:00
val | = config - > alpha_en_mask ;
val | = config - > alpha_mode_mask ;
2016-09-29 11:35:43 +03:00
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 20:50:40 +03:00
regmap_update_bits ( regmap , PLL_USER_CTL ( pll ) , mask , val ) ;
2016-09-29 11:35:45 +03:00
if ( pll - > flags & SUPPORTS_FSM_MODE )
2017-09-28 20:50:40 +03:00
qcom_pll_set_fsm_mode ( regmap , PLL_MODE ( pll ) , 6 , 0 ) ;
2016-09-29 11:35:43 +03:00
}
2018-10-10 17:51:37 +03:00
EXPORT_SYMBOL_GPL ( clk_alpha_pll_configure ) ;
2016-09-29 11:35:43 +03:00
2016-09-29 11:35:42 +03:00
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 20:50:40 +03:00
u32 val ;
2016-09-29 11:35:42 +03:00
2017-09-28 20:50:40 +03:00
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2016-09-29 11:35:42 +03:00
if ( ret )
return ret ;
val | = PLL_FSM_ENA ;
if ( pll - > flags & SUPPORTS_OFFLINE_REQ )
val & = ~ PLL_OFFLINE_REQ ;
2017-09-28 20:50:40 +03:00
ret = regmap_write ( pll - > clkr . regmap , PLL_MODE ( pll ) , val ) ;
2016-09-29 11:35:42 +03:00
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 20:50:40 +03:00
u32 val ;
2016-09-29 11:35:42 +03:00
2017-09-28 20:50:40 +03:00
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2016-09-29 11:35:42 +03:00
if ( ret )
return ;
if ( pll - > flags & SUPPORTS_OFFLINE_REQ ) {
2017-09-28 20:50:40 +03:00
ret = regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) ,
2016-09-29 11:35:42 +03:00
PLL_OFFLINE_REQ , PLL_OFFLINE_REQ ) ;
if ( ret )
return ;
ret = wait_for_pll_offline ( pll ) ;
if ( ret )
return ;
}
/* Disable hwfsm */
2017-09-28 20:50:40 +03:00
ret = regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) ,
2016-09-29 11:35:42 +03:00
PLL_FSM_ENA , 0 ) ;
if ( ret )
return ;
wait_for_pll_disable ( pll ) ;
}
2016-09-29 11:35:46 +03:00
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 20:50:40 +03:00
u32 val ;
2016-09-29 11:35:46 +03:00
2017-09-28 20:50:40 +03:00
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2016-09-29 11:35:46 +03:00
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-12-01 04:31:39 +03: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 20:50:40 +03:00
u32 val , mask ;
2015-12-01 04:31:39 +03:00
mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL ;
2017-09-28 20:50:40 +03:00
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2015-12-01 04:31:39 +03: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 11:35:42 +03:00
return wait_for_pll_enable_active ( pll ) ;
2015-12-01 04:31:39 +03:00
}
/* Skip if already enabled */
if ( ( val & mask ) = = mask )
return 0 ;
2017-09-28 20:50:40 +03:00
ret = regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) ,
2015-12-01 04:31:39 +03: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 20:50:40 +03:00
ret = regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) ,
2015-12-01 04:31:39 +03:00
PLL_RESET_N , PLL_RESET_N ) ;
if ( ret )
return ret ;
2016-09-29 11:35:42 +03:00
ret = wait_for_pll_enable_lock ( pll ) ;
2015-12-01 04:31:39 +03:00
if ( ret )
return ret ;
2017-09-28 20:50:40 +03:00
ret = regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) ,
2015-12-01 04:31:39 +03: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 20:50:40 +03:00
u32 val , mask ;
2015-12-01 04:31:39 +03:00
2017-09-28 20:50:40 +03:00
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
2015-12-01 04:31:39 +03: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 20:50:40 +03:00
regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) , mask , 0 ) ;
2015-12-01 04:31:39 +03:00
/* Delay of 2 output clock ticks required until output is disabled */
mb ( ) ;
udelay ( 1 ) ;
mask = PLL_RESET_N | PLL_BYPASSNL ;
2017-09-28 20:50:40 +03:00
regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) , mask , 0 ) ;
2015-12-01 04:31:39 +03:00
}
2017-09-28 20:50:41 +03:00
static unsigned long
alpha_pll_calc_rate ( u64 prate , u32 l , u32 a , u32 alpha_width )
2015-12-01 04:31:39 +03:00
{
2017-09-28 20:50:41 +03:00
return ( prate * l ) + ( ( prate * a ) > > ALPHA_SHIFT ( alpha_width ) ) ;
2015-12-01 04:31:39 +03:00
}
static unsigned long
2017-09-28 20:50:41 +03:00
alpha_pll_round_rate ( unsigned long rate , unsigned long prate , u32 * l , u64 * a ,
u32 alpha_width )
2015-12-01 04:31:39 +03: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 20:50:41 +03:00
quotient = remainder < < ALPHA_SHIFT ( alpha_width ) ;
2015-12-01 04:31:39 +03:00
remainder = do_div ( quotient , prate ) ;
if ( remainder )
quotient + + ;
* a = quotient ;
2017-09-28 20:50:41 +03:00
return alpha_pll_calc_rate ( prate , * l , * a , alpha_width ) ;
2015-12-01 04:31:39 +03: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 20:50:41 +03:00
u32 alpha_width = pll_alpha_width ( pll ) ;
2015-12-01 04:31:39 +03:00
2017-09-28 20:50:40 +03:00
regmap_read ( pll - > clkr . regmap , PLL_L_VAL ( pll ) , & l ) ;
2015-12-01 04:31:39 +03:00
2017-09-28 20:50:40 +03:00
regmap_read ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) , & ctl ) ;
2015-12-01 04:31:39 +03:00
if ( ctl & PLL_ALPHA_EN ) {
2017-09-28 20:50:40 +03:00
regmap_read ( pll - > clkr . regmap , PLL_ALPHA_VAL ( pll ) , & low ) ;
2017-09-28 20:50:41 +03:00
if ( alpha_width > 32 ) {
2017-09-28 20:50:40 +03:00
regmap_read ( pll - > clkr . regmap , PLL_ALPHA_VAL_U ( pll ) ,
2016-09-29 11:35:44 +03:00
& high ) ;
a = ( u64 ) high < < 32 | low ;
2017-09-28 20:50:41 +03:00
} else {
a = low & GENMASK ( alpha_width - 1 , 0 ) ;
2016-09-29 11:35:44 +03:00
}
2017-09-28 20:50:41 +03:00
if ( alpha_width > ALPHA_BITWIDTH )
a > > = alpha_width - ALPHA_BITWIDTH ;
2015-12-01 04:31:39 +03:00
}
2017-09-28 20:50:41 +03:00
return alpha_pll_calc_rate ( prate , l , a , alpha_width ) ;
2015-12-01 04:31:39 +03:00
}
2018-03-08 10:18:14 +03:00
static int __clk_alpha_pll_update_latch ( struct clk_alpha_pll * pll )
2017-09-28 20:50:45 +03:00
{
int ret ;
u32 mode ;
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 ;
}
2018-03-08 10:18:14 +03:00
static int clk_alpha_pll_update_latch ( struct clk_alpha_pll * pll ,
int ( * is_enabled ) ( struct clk_hw * ) )
{
if ( ! is_enabled ( & pll - > clkr . hw ) | |
! ( pll - > flags & SUPPORTS_DYNAMIC_UPDATE ) )
return 0 ;
return __clk_alpha_pll_update_latch ( pll ) ;
}
2017-09-28 20:50:45 +03:00
static int __clk_alpha_pll_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long prate ,
int ( * is_enabled ) ( struct clk_hw * ) )
2015-12-01 04:31:39 +03:00
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
const struct pll_vco * vco ;
2017-09-28 20:50:41 +03:00
u32 l , alpha_width = pll_alpha_width ( pll ) ;
2015-12-01 04:31:39 +03:00
u64 a ;
2017-09-28 20:50:41 +03:00
rate = alpha_pll_round_rate ( rate , prate , & l , & a , alpha_width ) ;
2015-12-01 04:31:39 +03:00
vco = alpha_pll_find_vco ( pll , rate ) ;
2017-09-28 20:50:46 +03:00
if ( pll - > vco_table & & ! vco ) {
2020-02-05 09:54:21 +03:00
pr_err ( " %s: alpha pll not in a valid vco range \n " ,
clk_hw_get_name ( hw ) ) ;
2015-12-01 04:31:39 +03:00
return - EINVAL ;
}
2017-09-28 20:50:40 +03:00
regmap_write ( pll - > clkr . regmap , PLL_L_VAL ( pll ) , l ) ;
2016-09-29 11:35:44 +03:00
2017-09-28 20:50:41 +03:00
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-12-01 04:31:39 +03:00
2017-09-28 20:50:46 +03:00
if ( vco ) {
regmap_update_bits ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) ,
PLL_VCO_MASK < < PLL_VCO_SHIFT ,
vco - > val < < PLL_VCO_SHIFT ) ;
}
2015-12-01 04:31:39 +03:00
2017-09-28 20:50:40 +03:00
regmap_update_bits ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) ,
PLL_ALPHA_EN , PLL_ALPHA_EN ) ;
2015-12-01 04:31:39 +03:00
2017-09-28 20:50:45 +03:00
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-12-01 04:31:39 +03: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 20:50:41 +03:00
u32 l , alpha_width = pll_alpha_width ( pll ) ;
2015-12-01 04:31:39 +03:00
u64 a ;
unsigned long min_freq , max_freq ;
2017-09-28 20:50:41 +03:00
rate = alpha_pll_round_rate ( rate , * prate , & l , & a , alpha_width ) ;
2017-09-28 20:50:46 +03:00
if ( ! pll - > vco_table | | alpha_pll_find_vco ( pll , rate ) )
2015-12-01 04:31:39 +03:00
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 ) ;
}
2017-09-28 20:50:46 +03:00
static unsigned long
alpha_huayra_pll_calc_rate ( u64 prate , u32 l , u32 a )
{
/*
* a contains 16 bit alpha_val in two ’ s compliment number in the range
* of [ - 0.5 , 0.5 ) .
*/
if ( a > = BIT ( PLL_HUAYRA_ALPHA_WIDTH - 1 ) )
l - = 1 ;
return ( prate * l ) + ( prate * a > > PLL_HUAYRA_ALPHA_WIDTH ) ;
}
static unsigned long
alpha_huayra_pll_round_rate ( unsigned long rate , unsigned long prate ,
u32 * l , u32 * a )
{
u64 remainder ;
u64 quotient ;
quotient = rate ;
remainder = do_div ( quotient , prate ) ;
* l = quotient ;
if ( ! remainder ) {
* a = 0 ;
return rate ;
}
quotient = remainder < < PLL_HUAYRA_ALPHA_WIDTH ;
remainder = do_div ( quotient , prate ) ;
if ( remainder )
quotient + + ;
/*
* alpha_val should be in two ’ s compliment number in the range
* of [ - 0.5 , 0.5 ) so if quotient > = 0.5 then increment the l value
* since alpha value will be subtracted in this case .
*/
if ( quotient > = BIT ( PLL_HUAYRA_ALPHA_WIDTH - 1 ) )
* l + = 1 ;
* a = quotient ;
return alpha_huayra_pll_calc_rate ( prate , * l , * a ) ;
}
static unsigned long
alpha_pll_huayra_recalc_rate ( struct clk_hw * hw , unsigned long parent_rate )
{
u64 rate = parent_rate , tmp ;
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
u32 l , alpha = 0 , ctl , alpha_m , alpha_n ;
regmap_read ( pll - > clkr . regmap , PLL_L_VAL ( pll ) , & l ) ;
regmap_read ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) , & ctl ) ;
if ( ctl & PLL_ALPHA_EN ) {
regmap_read ( pll - > clkr . regmap , PLL_ALPHA_VAL ( pll ) , & alpha ) ;
/*
* Depending upon alpha_mode , it can be treated as M / N value or
* as a two ’ s compliment number . When alpha_mode = 1 ,
* pll_alpha_val < 15 : 8 > = M and pll_apla_val < 7 : 0 > = N
*
* Fout = FIN * ( L + ( M / N ) )
*
* M is a signed number ( - 128 to 127 ) and N is unsigned
* ( 0 to 255 ) . M / N has to be within + / - 0.5 .
*
* When alpha_mode = 0 , it is a two ’ s compliment number in the
* range [ - 0.5 , 0.5 ) .
*
* Fout = FIN * ( L + ( alpha_val ) / 2 ^ 16 )
*
* where alpha_val is two ’ s compliment number .
*/
if ( ! ( ctl & PLL_ALPHA_MODE ) )
return alpha_huayra_pll_calc_rate ( rate , l , alpha ) ;
alpha_m = alpha > > PLL_HUAYRA_M_SHIFT & PLL_HUAYRA_M_MASK ;
alpha_n = alpha > > PLL_HUAYRA_N_SHIFT & PLL_HUAYRA_N_MASK ;
rate * = l ;
tmp = parent_rate ;
if ( alpha_m > = BIT ( PLL_HUAYRA_M_WIDTH - 1 ) ) {
alpha_m = BIT ( PLL_HUAYRA_M_WIDTH ) - alpha_m ;
tmp * = alpha_m ;
do_div ( tmp , alpha_n ) ;
rate - = tmp ;
} else {
tmp * = alpha_m ;
do_div ( tmp , alpha_n ) ;
rate + = tmp ;
}
return rate ;
}
return alpha_huayra_pll_calc_rate ( rate , l , alpha ) ;
}
static int alpha_pll_huayra_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long prate )
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
u32 l , a , ctl , cur_alpha = 0 ;
rate = alpha_huayra_pll_round_rate ( rate , prate , & l , & a ) ;
regmap_read ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) , & ctl ) ;
if ( ctl & PLL_ALPHA_EN )
regmap_read ( pll - > clkr . regmap , PLL_ALPHA_VAL ( pll ) , & cur_alpha ) ;
/*
* Huayra PLL supports PLL dynamic programming . User can change L_VAL ,
* without having to go through the power on sequence .
*/
if ( clk_alpha_pll_is_enabled ( hw ) ) {
if ( cur_alpha ! = a ) {
2020-02-05 09:54:21 +03:00
pr_err ( " %s: clock needs to be gated \n " ,
2017-09-28 20:50:46 +03:00
clk_hw_get_name ( hw ) ) ;
return - EBUSY ;
}
regmap_write ( pll - > clkr . regmap , PLL_L_VAL ( pll ) , l ) ;
/* Ensure that the write above goes to detect L val change. */
mb ( ) ;
return wait_for_pll_enable_lock ( pll ) ;
}
regmap_write ( pll - > clkr . regmap , PLL_L_VAL ( pll ) , l ) ;
regmap_write ( pll - > clkr . regmap , PLL_ALPHA_VAL ( pll ) , a ) ;
if ( a = = 0 )
regmap_update_bits ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) ,
PLL_ALPHA_EN , 0x0 ) ;
else
regmap_update_bits ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) ,
PLL_ALPHA_EN | PLL_ALPHA_MODE , PLL_ALPHA_EN ) ;
return 0 ;
}
static long alpha_pll_huayra_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
u32 l , a ;
return alpha_huayra_pll_round_rate ( rate , * prate , & l , & a ) ;
}
2019-07-22 10:43:46 +03:00
static int trion_pll_is_enabled ( struct clk_alpha_pll * pll ,
struct regmap * regmap )
{
u32 mode_regval , opmode_regval ;
int ret ;
ret = regmap_read ( regmap , PLL_MODE ( pll ) , & mode_regval ) ;
ret | = regmap_read ( regmap , PLL_OPMODE ( pll ) , & opmode_regval ) ;
if ( ret )
return 0 ;
2020-02-24 07:49:59 +03:00
return ( ( opmode_regval & PLL_RUN ) & & ( mode_regval & PLL_OUTCTRL ) ) ;
2019-07-22 10:43:46 +03:00
}
static int clk_trion_pll_is_enabled ( struct clk_hw * hw )
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
return trion_pll_is_enabled ( pll , pll - > clkr . regmap ) ;
}
static int clk_trion_pll_enable ( struct clk_hw * hw )
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
struct regmap * regmap = pll - > clkr . regmap ;
u32 val ;
int ret ;
ret = regmap_read ( regmap , PLL_MODE ( pll ) , & val ) ;
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 ;
return wait_for_pll_enable_active ( pll ) ;
}
/* Set operation mode to RUN */
2020-02-24 07:49:59 +03:00
regmap_write ( regmap , PLL_OPMODE ( pll ) , PLL_RUN ) ;
2019-07-22 10:43:46 +03:00
ret = wait_for_pll_enable_lock ( pll ) ;
if ( ret )
return ret ;
/* Enable the PLL outputs */
ret = regmap_update_bits ( regmap , PLL_USER_CTL ( pll ) ,
2020-02-24 07:49:59 +03:00
PLL_OUT_MASK , PLL_OUT_MASK ) ;
2019-07-22 10:43:46 +03:00
if ( ret )
return ret ;
/* Enable the global PLL outputs */
return regmap_update_bits ( regmap , PLL_MODE ( pll ) ,
PLL_OUTCTRL , PLL_OUTCTRL ) ;
}
static void clk_trion_pll_disable ( struct clk_hw * hw )
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
struct regmap * regmap = pll - > clkr . regmap ;
u32 val ;
int ret ;
ret = regmap_read ( regmap , PLL_MODE ( pll ) , & val ) ;
if ( ret )
return ;
/* If in FSM mode, just unvote it */
if ( val & PLL_VOTE_FSM_ENA ) {
clk_disable_regmap ( hw ) ;
return ;
}
/* Disable the global PLL output */
ret = regmap_update_bits ( regmap , PLL_MODE ( pll ) , PLL_OUTCTRL , 0 ) ;
if ( ret )
return ;
/* Disable the PLL outputs */
ret = regmap_update_bits ( regmap , PLL_USER_CTL ( pll ) ,
2020-02-24 07:49:59 +03:00
PLL_OUT_MASK , 0 ) ;
2019-07-22 10:43:46 +03:00
if ( ret )
return ;
/* Place the PLL mode in STANDBY */
2020-02-24 07:49:59 +03:00
regmap_write ( regmap , PLL_OPMODE ( pll ) , PLL_STANDBY ) ;
2019-07-22 10:43:46 +03:00
regmap_update_bits ( regmap , PLL_MODE ( pll ) , PLL_RESET_N , PLL_RESET_N ) ;
}
static unsigned long
clk_trion_pll_recalc_rate ( struct clk_hw * hw , unsigned long parent_rate )
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
2020-02-24 07:50:00 +03:00
u32 l , frac , alpha_width = pll_alpha_width ( pll ) ;
2019-07-22 10:43:46 +03:00
2020-02-24 07:50:00 +03:00
regmap_read ( pll - > clkr . regmap , PLL_L_VAL ( pll ) , & l ) ;
regmap_read ( pll - > clkr . regmap , PLL_ALPHA_VAL ( pll ) , & frac ) ;
2019-07-22 10:43:46 +03:00
2020-02-24 07:50:00 +03:00
return alpha_pll_calc_rate ( parent_rate , l , frac , alpha_width ) ;
2019-07-22 10:43:46 +03:00
}
2019-11-25 16:59:04 +03:00
const struct clk_ops clk_alpha_pll_fixed_ops = {
. enable = clk_alpha_pll_enable ,
. disable = clk_alpha_pll_disable ,
. is_enabled = clk_alpha_pll_is_enabled ,
. recalc_rate = clk_alpha_pll_recalc_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_fixed_ops ) ;
2015-12-01 04:31:39 +03:00
const struct clk_ops clk_alpha_pll_ops = {
. enable = clk_alpha_pll_enable ,
. disable = clk_alpha_pll_disable ,
2016-09-29 11:35:46 +03:00
. is_enabled = clk_alpha_pll_is_enabled ,
2015-12-01 04:31:39 +03: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 ) ;
2017-09-28 20:50:46 +03:00
const struct clk_ops clk_alpha_pll_huayra_ops = {
. enable = clk_alpha_pll_enable ,
. disable = clk_alpha_pll_disable ,
. is_enabled = clk_alpha_pll_is_enabled ,
. recalc_rate = alpha_pll_huayra_recalc_rate ,
. round_rate = alpha_pll_huayra_round_rate ,
. set_rate = alpha_pll_huayra_set_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_huayra_ops ) ;
2016-09-29 11:35:42 +03:00
const struct clk_ops clk_alpha_pll_hwfsm_ops = {
. enable = clk_alpha_pll_hwfsm_enable ,
. disable = clk_alpha_pll_hwfsm_disable ,
2016-09-29 11:35:46 +03:00
. is_enabled = clk_alpha_pll_hwfsm_is_enabled ,
2016-09-29 11:35:42 +03:00
. recalc_rate = clk_alpha_pll_recalc_rate ,
. round_rate = clk_alpha_pll_round_rate ,
2017-09-28 20:50:45 +03:00
. set_rate = clk_alpha_pll_hwfsm_set_rate ,
2016-09-29 11:35:42 +03:00
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_hwfsm_ops ) ;
2019-07-22 10:43:46 +03:00
const struct clk_ops clk_trion_fixed_pll_ops = {
. enable = clk_trion_pll_enable ,
. disable = clk_trion_pll_disable ,
. is_enabled = clk_trion_pll_is_enabled ,
. recalc_rate = clk_trion_pll_recalc_rate ,
2020-02-24 07:50:00 +03:00
. round_rate = clk_alpha_pll_round_rate ,
2019-07-22 10:43:46 +03:00
} ;
EXPORT_SYMBOL_GPL ( clk_trion_fixed_pll_ops ) ;
2015-12-01 04:31:39 +03: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 20:50:40 +03:00
regmap_read ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) , & ctl ) ;
2015-12-01 04:31:39 +03:00
ctl > > = PLL_POST_DIV_SHIFT ;
2017-09-28 20:50:49 +03:00
ctl & = PLL_POST_DIV_MASK ( pll ) ;
2015-12-01 04:31:39 +03:00
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 } ,
{ }
} ;
2017-09-28 20:50:49 +03:00
static const struct clk_div_table clk_alpha_2bit_div_table [ ] = {
{ 0x0 , 1 } ,
{ 0x1 , 2 } ,
{ 0x3 , 4 } ,
{ }
} ;
2015-12-01 04:31:39 +03:00
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 ) ;
2017-09-28 20:50:49 +03:00
const struct clk_div_table * table ;
if ( pll - > width = = 2 )
table = clk_alpha_2bit_div_table ;
else
table = clk_alpha_div_table ;
2015-12-01 04:31:39 +03:00
2017-09-28 20:50:49 +03:00
return divider_round_rate ( hw , rate , prate , table ,
2015-12-01 04:31:39 +03:00
pll - > width , CLK_DIVIDER_POWER_OF_TWO ) ;
}
2017-09-28 20:50:50 +03:00
static long
clk_alpha_pll_postdiv_round_ro_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
struct clk_alpha_pll_postdiv * pll = to_clk_alpha_pll_postdiv ( hw ) ;
u32 ctl , div ;
regmap_read ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) , & ctl ) ;
ctl > > = PLL_POST_DIV_SHIFT ;
ctl & = BIT ( pll - > width ) - 1 ;
div = 1 < < fls ( ctl ) ;
if ( clk_hw_get_flags ( hw ) & CLK_SET_RATE_PARENT )
* prate = clk_hw_round_rate ( clk_hw_get_parent ( hw ) , div * rate ) ;
return DIV_ROUND_UP_ULL ( ( u64 ) * prate , div ) ;
}
2015-12-01 04:31:39 +03:00
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 */
2019-07-22 10:43:44 +03:00
div = DIV_ROUND_UP_ULL ( parent_rate , rate ) - 1 ;
2015-12-01 04:31:39 +03:00
2017-09-28 20:50:40 +03:00
return regmap_update_bits ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) ,
2017-09-28 20:50:49 +03:00
PLL_POST_DIV_MASK ( pll ) < < PLL_POST_DIV_SHIFT ,
2015-12-01 04:31:39 +03:00
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 ) ;
2017-09-28 20:50:50 +03:00
const struct clk_ops clk_alpha_pll_postdiv_ro_ops = {
. round_rate = clk_alpha_pll_postdiv_round_ro_rate ,
. recalc_rate = clk_alpha_pll_postdiv_recalc_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_postdiv_ro_ops ) ;
2018-03-08 10:18:14 +03:00
void clk_fabia_pll_configure ( struct clk_alpha_pll * pll , struct regmap * regmap ,
const struct alpha_pll_config * config )
{
u32 val , mask ;
if ( config - > l )
regmap_write ( regmap , PLL_L_VAL ( pll ) , config - > l ) ;
if ( config - > alpha )
regmap_write ( regmap , PLL_FRAC ( pll ) , config - > alpha ) ;
if ( config - > config_ctl_val )
regmap_write ( regmap , PLL_CONFIG_CTL ( pll ) ,
config - > config_ctl_val ) ;
2019-11-15 13:04:58 +03:00
if ( config - > config_ctl_hi_val )
regmap_write ( regmap , PLL_CONFIG_CTL_U ( pll ) ,
config - > config_ctl_hi_val ) ;
if ( config - > user_ctl_val )
regmap_write ( regmap , PLL_USER_CTL ( pll ) , config - > user_ctl_val ) ;
if ( config - > user_ctl_hi_val )
regmap_write ( regmap , PLL_USER_CTL_U ( pll ) ,
config - > user_ctl_hi_val ) ;
if ( config - > test_ctl_val )
regmap_write ( regmap , PLL_TEST_CTL ( pll ) ,
config - > test_ctl_val ) ;
if ( config - > test_ctl_hi_val )
regmap_write ( regmap , PLL_TEST_CTL_U ( pll ) ,
config - > test_ctl_hi_val ) ;
2018-03-08 10:18:14 +03:00
if ( config - > post_div_mask ) {
mask = config - > post_div_mask ;
val = config - > post_div_val ;
regmap_update_bits ( regmap , PLL_USER_CTL ( pll ) , mask , val ) ;
}
regmap_update_bits ( regmap , PLL_MODE ( pll ) , PLL_UPDATE_BYPASS ,
PLL_UPDATE_BYPASS ) ;
regmap_update_bits ( regmap , PLL_MODE ( pll ) , PLL_RESET_N , PLL_RESET_N ) ;
}
2018-06-02 10:19:07 +03:00
EXPORT_SYMBOL_GPL ( clk_fabia_pll_configure ) ;
2018-03-08 10:18:14 +03:00
static int alpha_pll_fabia_enable ( struct clk_hw * hw )
{
int ret ;
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
u32 val , opmode_val ;
struct regmap * regmap = pll - > clkr . regmap ;
ret = regmap_read ( regmap , PLL_MODE ( pll ) , & val ) ;
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 ;
return wait_for_pll_enable_active ( pll ) ;
}
ret = regmap_read ( regmap , PLL_OPMODE ( pll ) , & opmode_val ) ;
if ( ret )
return ret ;
/* Skip If PLL is already running */
2020-02-24 07:49:59 +03:00
if ( ( opmode_val & PLL_RUN ) & & ( val & PLL_OUTCTRL ) )
2018-03-08 10:18:14 +03:00
return 0 ;
ret = regmap_update_bits ( regmap , PLL_MODE ( pll ) , PLL_OUTCTRL , 0 ) ;
if ( ret )
return ret ;
2020-02-24 07:49:59 +03:00
ret = regmap_write ( regmap , PLL_OPMODE ( pll ) , PLL_STANDBY ) ;
2018-03-08 10:18:14 +03:00
if ( ret )
return ret ;
ret = regmap_update_bits ( regmap , PLL_MODE ( pll ) , PLL_RESET_N ,
PLL_RESET_N ) ;
if ( ret )
return ret ;
2020-02-24 07:49:59 +03:00
ret = regmap_write ( regmap , PLL_OPMODE ( pll ) , PLL_RUN ) ;
2018-03-08 10:18:14 +03:00
if ( ret )
return ret ;
ret = wait_for_pll_enable_lock ( pll ) ;
if ( ret )
return ret ;
ret = regmap_update_bits ( regmap , PLL_USER_CTL ( pll ) ,
2020-02-24 07:49:59 +03:00
PLL_OUT_MASK , PLL_OUT_MASK ) ;
2018-03-08 10:18:14 +03:00
if ( ret )
return ret ;
return regmap_update_bits ( regmap , PLL_MODE ( pll ) , PLL_OUTCTRL ,
PLL_OUTCTRL ) ;
}
static void alpha_pll_fabia_disable ( struct clk_hw * hw )
{
int ret ;
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
u32 val ;
struct regmap * regmap = pll - > clkr . regmap ;
ret = regmap_read ( regmap , PLL_MODE ( pll ) , & val ) ;
if ( ret )
return ;
/* If in FSM mode, just unvote it */
if ( val & PLL_FSM_ENA ) {
clk_disable_regmap ( hw ) ;
return ;
}
ret = regmap_update_bits ( regmap , PLL_MODE ( pll ) , PLL_OUTCTRL , 0 ) ;
if ( ret )
return ;
/* Disable main outputs */
2020-02-24 07:49:59 +03:00
ret = regmap_update_bits ( regmap , PLL_USER_CTL ( pll ) , PLL_OUT_MASK , 0 ) ;
2018-03-08 10:18:14 +03:00
if ( ret )
return ;
/* Place the PLL in STANDBY */
2020-02-24 07:49:59 +03:00
regmap_write ( regmap , PLL_OPMODE ( pll ) , PLL_STANDBY ) ;
2018-03-08 10:18:14 +03:00
}
static unsigned long alpha_pll_fabia_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
u32 l , frac , alpha_width = pll_alpha_width ( pll ) ;
regmap_read ( pll - > clkr . regmap , PLL_L_VAL ( pll ) , & l ) ;
regmap_read ( pll - > clkr . regmap , PLL_FRAC ( pll ) , & frac ) ;
return alpha_pll_calc_rate ( parent_rate , l , frac , alpha_width ) ;
}
static int alpha_pll_fabia_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long prate )
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
2019-11-15 13:04:57 +03:00
u32 l , alpha_width = pll_alpha_width ( pll ) ;
2018-03-08 10:18:14 +03:00
u64 a ;
2020-02-24 07:49:59 +03:00
unsigned long rrate , max = rate + PLL_RATE_MARGIN ;
2018-03-08 10:18:14 +03:00
rrate = alpha_pll_round_rate ( rate , prate , & l , & a , alpha_width ) ;
/*
* Due to limited number of bits for fractional rate programming , the
* rounded up rate could be marginally higher than the requested rate .
*/
2020-02-24 07:50:00 +03:00
if ( rrate > ( rate + PLL_RATE_MARGIN ) | | rrate < rate ) {
2020-02-05 09:54:21 +03:00
pr_err ( " %s: Rounded rate %lu not within range [%lu, %lu) \n " ,
clk_hw_get_name ( hw ) , rrate , rate , max ) ;
2018-03-08 10:18:14 +03:00
return - EINVAL ;
}
regmap_write ( pll - > clkr . regmap , PLL_L_VAL ( pll ) , l ) ;
regmap_write ( pll - > clkr . regmap , PLL_FRAC ( pll ) , a ) ;
return __clk_alpha_pll_update_latch ( pll ) ;
}
2019-11-15 13:04:58 +03:00
static int alpha_pll_fabia_prepare ( struct clk_hw * hw )
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
const struct pll_vco * vco ;
struct clk_hw * parent_hw ;
unsigned long cal_freq , rrate ;
u32 cal_l , val , alpha_width = pll_alpha_width ( pll ) ;
2020-02-05 09:54:21 +03:00
const char * name = clk_hw_get_name ( hw ) ;
2019-11-15 13:04:58 +03:00
u64 a ;
int ret ;
/* Check if calibration needs to be done i.e. PLL is in reset */
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
if ( ret )
return ret ;
/* Return early if calibration is not needed. */
if ( val & PLL_RESET_N )
return 0 ;
vco = alpha_pll_find_vco ( pll , clk_hw_get_rate ( hw ) ) ;
if ( ! vco ) {
2020-02-05 09:54:21 +03:00
pr_err ( " %s: alpha pll not in a valid vco range \n " , name ) ;
2019-11-15 13:04:58 +03:00
return - EINVAL ;
}
cal_freq = DIV_ROUND_CLOSEST ( ( pll - > vco_table [ 0 ] . min_freq +
pll - > vco_table [ 0 ] . max_freq ) * 54 , 100 ) ;
parent_hw = clk_hw_get_parent ( hw ) ;
if ( ! parent_hw )
return - EINVAL ;
rrate = alpha_pll_round_rate ( cal_freq , clk_hw_get_rate ( parent_hw ) ,
& cal_l , & a , alpha_width ) ;
/*
* Due to a limited number of bits for fractional rate programming , the
* rounded up rate could be marginally higher than the requested rate .
*/
2020-02-24 07:49:59 +03:00
if ( rrate > ( cal_freq + PLL_RATE_MARGIN ) | | rrate < cal_freq )
2019-11-15 13:04:58 +03:00
return - EINVAL ;
/* Setup PLL for calibration frequency */
regmap_write ( pll - > clkr . regmap , PLL_ALPHA_VAL ( pll ) , cal_l ) ;
/* Bringup the PLL at calibration frequency */
ret = clk_alpha_pll_enable ( hw ) ;
if ( ret ) {
2020-02-05 09:54:21 +03:00
pr_err ( " %s: alpha pll calibration failed \n " , name ) ;
2019-11-15 13:04:58 +03:00
return ret ;
}
clk_alpha_pll_disable ( hw ) ;
return 0 ;
}
2018-03-08 10:18:14 +03:00
const struct clk_ops clk_alpha_pll_fabia_ops = {
2019-11-15 13:04:58 +03:00
. prepare = alpha_pll_fabia_prepare ,
2018-03-08 10:18:14 +03:00
. enable = alpha_pll_fabia_enable ,
. disable = alpha_pll_fabia_disable ,
. is_enabled = clk_alpha_pll_is_enabled ,
. set_rate = alpha_pll_fabia_set_rate ,
. recalc_rate = alpha_pll_fabia_recalc_rate ,
. round_rate = clk_alpha_pll_round_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_fabia_ops ) ;
const struct clk_ops clk_alpha_pll_fixed_fabia_ops = {
. enable = alpha_pll_fabia_enable ,
. disable = alpha_pll_fabia_disable ,
. is_enabled = clk_alpha_pll_is_enabled ,
. recalc_rate = alpha_pll_fabia_recalc_rate ,
. round_rate = clk_alpha_pll_round_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_fixed_fabia_ops ) ;
static unsigned long clk_alpha_pll_postdiv_fabia_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_alpha_pll_postdiv * pll = to_clk_alpha_pll_postdiv ( hw ) ;
u32 i , div = 1 , val ;
int ret ;
ret = regmap_read ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) , & val ) ;
if ( ret )
return ret ;
val > > = pll - > post_div_shift ;
val & = BIT ( pll - > width ) - 1 ;
for ( i = 0 ; i < pll - > num_post_div ; i + + ) {
if ( pll - > post_div_table [ i ] . val = = val ) {
div = pll - > post_div_table [ i ] . div ;
break ;
}
}
return ( parent_rate / div ) ;
}
2019-07-22 10:43:46 +03:00
static unsigned long
clk_trion_pll_postdiv_recalc_rate ( struct clk_hw * hw , unsigned long parent_rate )
{
struct clk_alpha_pll_postdiv * pll = to_clk_alpha_pll_postdiv ( hw ) ;
struct regmap * regmap = pll - > clkr . regmap ;
u32 i , div = 1 , val ;
regmap_read ( regmap , PLL_USER_CTL ( pll ) , & val ) ;
val > > = pll - > post_div_shift ;
val & = PLL_POST_DIV_MASK ( pll ) ;
for ( i = 0 ; i < pll - > num_post_div ; i + + ) {
if ( pll - > post_div_table [ i ] . val = = val ) {
div = pll - > post_div_table [ i ] . div ;
break ;
}
}
return ( parent_rate / div ) ;
}
static long
clk_trion_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 , pll - > post_div_table ,
pll - > width , CLK_DIVIDER_ROUND_CLOSEST ) ;
} ;
static int
clk_trion_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 ) ;
struct regmap * regmap = pll - > clkr . regmap ;
int i , val = 0 , div ;
div = DIV_ROUND_UP_ULL ( parent_rate , rate ) ;
for ( i = 0 ; i < pll - > num_post_div ; i + + ) {
if ( pll - > post_div_table [ i ] . div = = div ) {
val = pll - > post_div_table [ i ] . val ;
break ;
}
}
return regmap_update_bits ( regmap , PLL_USER_CTL ( pll ) ,
PLL_POST_DIV_MASK ( pll ) < < PLL_POST_DIV_SHIFT ,
val < < PLL_POST_DIV_SHIFT ) ;
}
const struct clk_ops clk_trion_pll_postdiv_ops = {
. recalc_rate = clk_trion_pll_postdiv_recalc_rate ,
. round_rate = clk_trion_pll_postdiv_round_rate ,
. set_rate = clk_trion_pll_postdiv_set_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_trion_pll_postdiv_ops ) ;
2018-03-08 10:18:14 +03:00
static long clk_alpha_pll_postdiv_fabia_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 , pll - > post_div_table ,
pll - > width , CLK_DIVIDER_ROUND_CLOSEST ) ;
}
static int clk_alpha_pll_postdiv_fabia_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 i , val = 0 , div , ret ;
/*
* If the PLL is in FSM mode , then treat set_rate callback as a
* no - operation .
*/
ret = regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & val ) ;
if ( ret )
return ret ;
if ( val & PLL_VOTE_FSM_ENA )
return 0 ;
2019-07-22 10:43:44 +03:00
div = DIV_ROUND_UP_ULL ( parent_rate , rate ) ;
2018-03-08 10:18:14 +03:00
for ( i = 0 ; i < pll - > num_post_div ; i + + ) {
if ( pll - > post_div_table [ i ] . div = = div ) {
val = pll - > post_div_table [ i ] . val ;
break ;
}
}
return regmap_update_bits ( pll - > clkr . regmap , PLL_USER_CTL ( pll ) ,
( BIT ( pll - > width ) - 1 ) < < pll - > post_div_shift ,
val < < pll - > post_div_shift ) ;
}
const struct clk_ops clk_alpha_pll_postdiv_fabia_ops = {
. recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate ,
. round_rate = clk_alpha_pll_postdiv_fabia_round_rate ,
. set_rate = clk_alpha_pll_postdiv_fabia_set_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_postdiv_fabia_ops ) ;
2020-02-24 07:50:01 +03:00
/**
* clk_lucid_pll_configure - configure the lucid pll
*
* @ pll : clk alpha pll
* @ regmap : register map
* @ config : configuration to apply for pll
*/
void clk_lucid_pll_configure ( struct clk_alpha_pll * pll , struct regmap * regmap ,
const struct alpha_pll_config * config )
{
if ( config - > l )
regmap_write ( regmap , PLL_L_VAL ( pll ) , config - > l ) ;
regmap_write ( regmap , PLL_CAL_L_VAL ( pll ) , LUCID_PLL_CAL_VAL ) ;
if ( config - > alpha )
regmap_write ( regmap , PLL_ALPHA_VAL ( pll ) , config - > alpha ) ;
if ( config - > config_ctl_val )
regmap_write ( regmap , PLL_CONFIG_CTL ( pll ) ,
config - > config_ctl_val ) ;
if ( config - > config_ctl_hi_val )
regmap_write ( regmap , PLL_CONFIG_CTL_U ( pll ) ,
config - > config_ctl_hi_val ) ;
if ( config - > config_ctl_hi1_val )
regmap_write ( regmap , PLL_CONFIG_CTL_U1 ( pll ) ,
config - > config_ctl_hi1_val ) ;
if ( config - > user_ctl_val )
regmap_write ( regmap , PLL_USER_CTL ( pll ) ,
config - > user_ctl_val ) ;
if ( config - > user_ctl_hi_val )
regmap_write ( regmap , PLL_USER_CTL_U ( pll ) ,
config - > user_ctl_hi_val ) ;
if ( config - > user_ctl_hi1_val )
regmap_write ( regmap , PLL_USER_CTL_U1 ( pll ) ,
config - > user_ctl_hi1_val ) ;
if ( config - > test_ctl_val )
regmap_write ( regmap , PLL_TEST_CTL ( pll ) ,
config - > test_ctl_val ) ;
if ( config - > test_ctl_hi_val )
regmap_write ( regmap , PLL_TEST_CTL_U ( pll ) ,
config - > test_ctl_hi_val ) ;
if ( config - > test_ctl_hi1_val )
regmap_write ( regmap , PLL_TEST_CTL_U1 ( pll ) ,
config - > test_ctl_hi1_val ) ;
regmap_update_bits ( regmap , PLL_MODE ( pll ) , PLL_UPDATE_BYPASS ,
PLL_UPDATE_BYPASS ) ;
/* Disable PLL output */
regmap_update_bits ( regmap , PLL_MODE ( pll ) , PLL_OUTCTRL , 0 ) ;
/* Set operation mode to OFF */
regmap_write ( regmap , PLL_OPMODE ( pll ) , PLL_STANDBY ) ;
/* Place the PLL in STANDBY mode */
regmap_update_bits ( regmap , PLL_MODE ( pll ) , PLL_RESET_N , PLL_RESET_N ) ;
}
EXPORT_SYMBOL_GPL ( clk_lucid_pll_configure ) ;
/*
* The Lucid PLL requires a power - on self - calibration which happens when the
* PLL comes out of reset . Calibrate in case it is not completed .
*/
static int alpha_pll_lucid_prepare ( struct clk_hw * hw )
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
u32 regval ;
int ret ;
/* Return early if calibration is not needed. */
regmap_read ( pll - > clkr . regmap , PLL_STATUS ( pll ) , & regval ) ;
if ( regval & LUCID_PCAL_DONE )
return 0 ;
/* On/off to calibrate */
ret = clk_trion_pll_enable ( hw ) ;
if ( ! ret )
clk_trion_pll_disable ( hw ) ;
return ret ;
}
static int alpha_pll_lucid_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long prate )
{
struct clk_alpha_pll * pll = to_clk_alpha_pll ( hw ) ;
unsigned long rrate ;
u32 regval , l , alpha_width = pll_alpha_width ( pll ) ;
u64 a ;
int ret ;
rrate = alpha_pll_round_rate ( rate , prate , & l , & a , alpha_width ) ;
/*
* Due to a limited number of bits for fractional rate programming , the
* rounded up rate could be marginally higher than the requested rate .
*/
if ( rrate > ( rate + PLL_RATE_MARGIN ) | | rrate < rate ) {
pr_err ( " Call set rate on the PLL with rounded rates! \n " ) ;
return - EINVAL ;
}
regmap_write ( pll - > clkr . regmap , PLL_L_VAL ( pll ) , l ) ;
regmap_write ( pll - > clkr . regmap , PLL_ALPHA_VAL ( pll ) , a ) ;
/* Latch the PLL input */
ret = regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) ,
PLL_UPDATE , PLL_UPDATE ) ;
if ( ret )
return ret ;
/* Wait for 2 reference cycles before checking the ACK bit. */
udelay ( 1 ) ;
regmap_read ( pll - > clkr . regmap , PLL_MODE ( pll ) , & regval ) ;
if ( ! ( regval & ALPHA_PLL_ACK_LATCH ) ) {
pr_err ( " Lucid PLL latch failed. Output may be unstable! \n " ) ;
return - EINVAL ;
}
/* Return the latch input to 0 */
ret = regmap_update_bits ( pll - > clkr . regmap , PLL_MODE ( pll ) ,
PLL_UPDATE , 0 ) ;
if ( ret )
return ret ;
if ( clk_hw_is_enabled ( hw ) ) {
ret = wait_for_pll_enable_lock ( pll ) ;
if ( ret )
return ret ;
}
/* Wait for PLL output to stabilize */
udelay ( 100 ) ;
return 0 ;
}
const struct clk_ops clk_alpha_pll_lucid_ops = {
. prepare = alpha_pll_lucid_prepare ,
. enable = clk_trion_pll_enable ,
. disable = clk_trion_pll_disable ,
. is_enabled = clk_trion_pll_is_enabled ,
. recalc_rate = clk_trion_pll_recalc_rate ,
. round_rate = clk_alpha_pll_round_rate ,
. set_rate = alpha_pll_lucid_set_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_lucid_ops ) ;
const struct clk_ops clk_alpha_pll_fixed_lucid_ops = {
. enable = clk_trion_pll_enable ,
. disable = clk_trion_pll_disable ,
. is_enabled = clk_trion_pll_is_enabled ,
. recalc_rate = clk_trion_pll_recalc_rate ,
. round_rate = clk_alpha_pll_round_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_fixed_lucid_ops ) ;
const struct clk_ops clk_alpha_pll_postdiv_lucid_ops = {
. recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate ,
. round_rate = clk_alpha_pll_postdiv_fabia_round_rate ,
. set_rate = clk_alpha_pll_postdiv_fabia_set_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_alpha_pll_postdiv_lucid_ops ) ;