2012-04-04 12:02:28 +04:00
/*
* Copyright 2012 Freescale Semiconductor , Inc .
* Copyright 2012 Linaro Ltd .
*
* The code contained herein is licensed under the GNU General Public
* License . You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations :
*
* http : //www.opensource.org/licenses/gpl-license.html
* http : //www.gnu.org/copyleft/gpl.html
*/
# include <linux/clk-provider.h>
2013-10-30 11:12:55 +04:00
# include <linux/delay.h>
2012-04-04 12:02:28 +04:00
# include <linux/io.h>
# include <linux/slab.h>
# include <linux/jiffies.h>
# include <linux/err.h>
# include "clk.h"
# define PLL_NUM_OFFSET 0x10
# define PLL_DENOM_OFFSET 0x20
# define BM_PLL_POWER (0x1 << 12)
# define BM_PLL_LOCK (0x1 << 31)
2015-05-18 21:45:02 +03:00
# define IMX7_ENET_PLL_POWER (0x1 << 5)
2012-04-04 12:02:28 +04:00
/**
* struct clk_pllv3 - IMX PLL clock version 3
* @ clk_hw : clock source
* @ base : base address of PLL registers
* @ powerup_set : set POWER bit to power up the PLL
2015-05-18 21:45:02 +03:00
* @ powerdown : pll powerdown offset bit
2012-04-04 12:02:28 +04:00
* @ div_mask : mask of divider bits
2014-12-02 19:59:42 +03:00
* @ div_shift : shift of divider bits
2012-04-04 12:02:28 +04:00
*
* IMX PLL clock version 3 , found on i . MX6 series . Divider for pllv3
* is actually a multiplier , and always sits at bit 0.
*/
struct clk_pllv3 {
struct clk_hw hw ;
void __iomem * base ;
bool powerup_set ;
2015-05-18 21:45:02 +03:00
u32 powerdown ;
2012-04-04 12:02:28 +04:00
u32 div_mask ;
2014-12-02 19:59:42 +03:00
u32 div_shift ;
2016-01-30 01:49:24 +03:00
unsigned long ref_clock ;
2012-04-04 12:02:28 +04:00
} ;
# define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw)
2013-10-30 11:56:22 +04:00
static int clk_pllv3_wait_lock ( struct clk_pllv3 * pll )
2012-04-04 12:02:28 +04:00
{
2013-10-30 11:56:22 +04:00
unsigned long timeout = jiffies + msecs_to_jiffies ( 10 ) ;
2015-05-18 21:45:02 +03:00
u32 val = readl_relaxed ( pll - > base ) & pll - > powerdown ;
2012-04-04 12:02:28 +04:00
2013-10-30 11:56:22 +04:00
/* No need to wait for lock when pll is not powered up */
if ( ( pll - > powerup_set & & ! val ) | | ( ! pll - > powerup_set & & val ) )
return 0 ;
2012-04-04 12:02:28 +04:00
/* Wait for PLL to lock */
2013-07-16 06:23:20 +04:00
do {
if ( readl_relaxed ( pll - > base ) & BM_PLL_LOCK )
break ;
2012-04-04 12:02:28 +04:00
if ( time_after ( jiffies , timeout ) )
2013-07-16 06:23:20 +04:00
break ;
2013-10-30 11:12:55 +04:00
usleep_range ( 50 , 500 ) ;
2013-07-16 06:23:20 +04:00
} while ( 1 ) ;
2012-04-04 12:02:28 +04:00
2013-10-30 11:56:22 +04:00
return readl_relaxed ( pll - > base ) & BM_PLL_LOCK ? 0 : - ETIMEDOUT ;
}
static int clk_pllv3_prepare ( struct clk_hw * hw )
{
struct clk_pllv3 * pll = to_clk_pllv3 ( hw ) ;
u32 val ;
val = readl_relaxed ( pll - > base ) ;
if ( pll - > powerup_set )
val | = BM_PLL_POWER ;
2013-07-16 06:23:20 +04:00
else
2013-10-30 11:56:22 +04:00
val & = ~ BM_PLL_POWER ;
writel_relaxed ( val , pll - > base ) ;
2014-11-06 21:49:32 +03:00
return clk_pllv3_wait_lock ( pll ) ;
2012-04-04 12:02:28 +04:00
}
static void clk_pllv3_unprepare ( struct clk_hw * hw )
{
struct clk_pllv3 * pll = to_clk_pllv3 ( hw ) ;
u32 val ;
val = readl_relaxed ( pll - > base ) ;
if ( pll - > powerup_set )
val & = ~ BM_PLL_POWER ;
else
val | = BM_PLL_POWER ;
writel_relaxed ( val , pll - > base ) ;
}
2015-11-24 19:06:53 +03:00
static int clk_pllv3_is_prepared ( struct clk_hw * hw )
{
struct clk_pllv3 * pll = to_clk_pllv3 ( hw ) ;
if ( readl_relaxed ( pll - > base ) & BM_PLL_LOCK )
return 1 ;
return 0 ;
}
2012-04-04 12:02:28 +04:00
static unsigned long clk_pllv3_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_pllv3 * pll = to_clk_pllv3 ( hw ) ;
2014-12-02 19:59:42 +03:00
u32 div = ( readl_relaxed ( pll - > base ) > > pll - > div_shift ) & pll - > div_mask ;
2012-04-04 12:02:28 +04:00
return ( div = = 1 ) ? parent_rate * 22 : parent_rate * 20 ;
}
static long clk_pllv3_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
unsigned long parent_rate = * prate ;
return ( rate > = parent_rate * 22 ) ? parent_rate * 22 :
parent_rate * 20 ;
}
static int clk_pllv3_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct clk_pllv3 * pll = to_clk_pllv3 ( hw ) ;
u32 val , div ;
if ( rate = = parent_rate * 22 )
div = 1 ;
else if ( rate = = parent_rate * 20 )
div = 0 ;
else
return - EINVAL ;
val = readl_relaxed ( pll - > base ) ;
2014-12-02 19:59:42 +03:00
val & = ~ ( pll - > div_mask < < pll - > div_shift ) ;
val | = ( div < < pll - > div_shift ) ;
2012-04-04 12:02:28 +04:00
writel_relaxed ( val , pll - > base ) ;
2013-10-30 11:56:22 +04:00
return clk_pllv3_wait_lock ( pll ) ;
2012-04-04 12:02:28 +04:00
}
static const struct clk_ops clk_pllv3_ops = {
. prepare = clk_pllv3_prepare ,
. unprepare = clk_pllv3_unprepare ,
2015-11-24 19:06:53 +03:00
. is_prepared = clk_pllv3_is_prepared ,
2012-04-04 12:02:28 +04:00
. recalc_rate = clk_pllv3_recalc_rate ,
. round_rate = clk_pllv3_round_rate ,
. set_rate = clk_pllv3_set_rate ,
} ;
static unsigned long clk_pllv3_sys_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_pllv3 * pll = to_clk_pllv3 ( hw ) ;
u32 div = readl_relaxed ( pll - > base ) & pll - > div_mask ;
return parent_rate * div / 2 ;
}
static long clk_pllv3_sys_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
unsigned long parent_rate = * prate ;
unsigned long min_rate = parent_rate * 54 / 2 ;
unsigned long max_rate = parent_rate * 108 / 2 ;
u32 div ;
if ( rate > max_rate )
rate = max_rate ;
else if ( rate < min_rate )
rate = min_rate ;
div = rate * 2 / parent_rate ;
return parent_rate * div / 2 ;
}
static int clk_pllv3_sys_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct clk_pllv3 * pll = to_clk_pllv3 ( hw ) ;
unsigned long min_rate = parent_rate * 54 / 2 ;
unsigned long max_rate = parent_rate * 108 / 2 ;
u32 val , div ;
if ( rate < min_rate | | rate > max_rate )
return - EINVAL ;
div = rate * 2 / parent_rate ;
val = readl_relaxed ( pll - > base ) ;
val & = ~ pll - > div_mask ;
val | = div ;
writel_relaxed ( val , pll - > base ) ;
2013-10-30 11:56:22 +04:00
return clk_pllv3_wait_lock ( pll ) ;
2012-04-04 12:02:28 +04:00
}
static const struct clk_ops clk_pllv3_sys_ops = {
. prepare = clk_pllv3_prepare ,
. unprepare = clk_pllv3_unprepare ,
2015-11-24 19:06:53 +03:00
. is_prepared = clk_pllv3_is_prepared ,
2012-04-04 12:02:28 +04:00
. recalc_rate = clk_pllv3_sys_recalc_rate ,
. round_rate = clk_pllv3_sys_round_rate ,
. set_rate = clk_pllv3_sys_set_rate ,
} ;
static unsigned long clk_pllv3_av_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_pllv3 * pll = to_clk_pllv3 ( hw ) ;
u32 mfn = readl_relaxed ( pll - > base + PLL_NUM_OFFSET ) ;
u32 mfd = readl_relaxed ( pll - > base + PLL_DENOM_OFFSET ) ;
u32 div = readl_relaxed ( pll - > base ) & pll - > div_mask ;
return ( parent_rate * div ) + ( ( parent_rate / mfd ) * mfn ) ;
}
static long clk_pllv3_av_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
unsigned long parent_rate = * prate ;
unsigned long min_rate = parent_rate * 27 ;
unsigned long max_rate = parent_rate * 54 ;
u32 div ;
u32 mfn , mfd = 1000000 ;
2015-05-07 19:16:51 +03:00
u64 temp64 ;
2012-04-04 12:02:28 +04:00
if ( rate > max_rate )
rate = max_rate ;
else if ( rate < min_rate )
rate = min_rate ;
div = rate / parent_rate ;
temp64 = ( u64 ) ( rate - div * parent_rate ) ;
temp64 * = mfd ;
do_div ( temp64 , parent_rate ) ;
mfn = temp64 ;
return parent_rate * div + parent_rate / mfd * mfn ;
}
static int clk_pllv3_av_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct clk_pllv3 * pll = to_clk_pllv3 ( hw ) ;
unsigned long min_rate = parent_rate * 27 ;
unsigned long max_rate = parent_rate * 54 ;
u32 val , div ;
u32 mfn , mfd = 1000000 ;
2015-05-07 19:16:51 +03:00
u64 temp64 ;
2012-04-04 12:02:28 +04:00
if ( rate < min_rate | | rate > max_rate )
return - EINVAL ;
div = rate / parent_rate ;
temp64 = ( u64 ) ( rate - div * parent_rate ) ;
temp64 * = mfd ;
do_div ( temp64 , parent_rate ) ;
mfn = temp64 ;
val = readl_relaxed ( pll - > base ) ;
val & = ~ pll - > div_mask ;
val | = div ;
writel_relaxed ( val , pll - > base ) ;
writel_relaxed ( mfn , pll - > base + PLL_NUM_OFFSET ) ;
writel_relaxed ( mfd , pll - > base + PLL_DENOM_OFFSET ) ;
2013-10-30 11:56:22 +04:00
return clk_pllv3_wait_lock ( pll ) ;
2012-04-04 12:02:28 +04:00
}
static const struct clk_ops clk_pllv3_av_ops = {
. prepare = clk_pllv3_prepare ,
. unprepare = clk_pllv3_unprepare ,
2015-11-24 19:06:53 +03:00
. is_prepared = clk_pllv3_is_prepared ,
2012-04-04 12:02:28 +04:00
. recalc_rate = clk_pllv3_av_recalc_rate ,
. round_rate = clk_pllv3_av_round_rate ,
. set_rate = clk_pllv3_av_set_rate ,
} ;
static unsigned long clk_pllv3_enet_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
2016-01-30 01:49:24 +03:00
struct clk_pllv3 * pll = to_clk_pllv3 ( hw ) ;
return pll - > ref_clock ;
2012-04-04 12:02:28 +04:00
}
static const struct clk_ops clk_pllv3_enet_ops = {
. prepare = clk_pllv3_prepare ,
. unprepare = clk_pllv3_unprepare ,
2015-11-24 19:06:53 +03:00
. is_prepared = clk_pllv3_is_prepared ,
2012-04-04 12:02:28 +04:00
. recalc_rate = clk_pllv3_enet_recalc_rate ,
} ;
struct clk * imx_clk_pllv3 ( enum imx_pllv3_type type , const char * name ,
const char * parent_name , void __iomem * base ,
2012-11-22 13:18:41 +04:00
u32 div_mask )
2012-04-04 12:02:28 +04:00
{
struct clk_pllv3 * pll ;
const struct clk_ops * ops ;
struct clk * clk ;
struct clk_init_data init ;
pll = kzalloc ( sizeof ( * pll ) , GFP_KERNEL ) ;
if ( ! pll )
return ERR_PTR ( - ENOMEM ) ;
2015-05-18 21:45:02 +03:00
pll - > powerdown = BM_PLL_POWER ;
2012-04-04 12:02:28 +04:00
switch ( type ) {
case IMX_PLLV3_SYS :
ops = & clk_pllv3_sys_ops ;
break ;
2014-12-02 19:59:42 +03:00
case IMX_PLLV3_USB_VF610 :
pll - > div_shift = 1 ;
2012-04-04 12:02:28 +04:00
case IMX_PLLV3_USB :
ops = & clk_pllv3_ops ;
pll - > powerup_set = true ;
break ;
case IMX_PLLV3_AV :
ops = & clk_pllv3_av_ops ;
break ;
2015-05-18 21:45:02 +03:00
case IMX_PLLV3_ENET_IMX7 :
pll - > powerdown = IMX7_ENET_PLL_POWER ;
2016-01-30 01:49:24 +03:00
pll - > ref_clock = 1000000000 ;
ops = & clk_pllv3_enet_ops ;
break ;
2012-04-04 12:02:28 +04:00
case IMX_PLLV3_ENET :
2016-01-30 01:49:24 +03:00
pll - > ref_clock = 500000000 ;
2012-04-04 12:02:28 +04:00
ops = & clk_pllv3_enet_ops ;
break ;
default :
ops = & clk_pllv3_ops ;
}
pll - > base = base ;
pll - > div_mask = div_mask ;
init . name = name ;
init . ops = ops ;
init . flags = 0 ;
init . parent_names = & parent_name ;
init . num_parents = 1 ;
pll - > hw . init = & init ;
clk = clk_register ( NULL , & pll - > hw ) ;
if ( IS_ERR ( clk ) )
kfree ( pll ) ;
return clk ;
}