2012-03-09 12:11:55 +04:00
# include <linux/clk-provider.h>
# include <linux/io.h>
# include <linux/slab.h>
# include <linux/kernel.h>
# include <linux/err.h>
2012-09-11 10:50:00 +04:00
2012-03-09 12:11:55 +04:00
# include "clk.h"
/**
* pll v1
*
* @ clk_hw clock source
* @ parent the parent clock name
* @ base base address of pll registers
*
* PLL clock version 1 , found on i . MX1 / 21 / 25 / 27 / 31 / 35
*/
2013-11-10 13:34:49 +04:00
# define MFN_BITS (10)
# define MFN_SIGN (BIT(MFN_BITS - 1))
# define MFN_MASK (MFN_SIGN - 1)
2012-03-09 12:11:55 +04:00
struct clk_pllv1 {
struct clk_hw hw ;
void __iomem * base ;
2015-04-26 08:33:39 +03:00
enum imx_pllv1_type type ;
2012-03-09 12:11:55 +04:00
} ;
# define to_clk_pllv1(clk) (container_of(clk, struct clk_pllv1, clk))
2015-04-26 08:33:39 +03:00
static inline bool is_imx1_pllv1 ( struct clk_pllv1 * pll )
2013-11-10 13:34:49 +04:00
{
2015-04-26 08:33:39 +03:00
return pll - > type = = IMX_PLLV1_IMX1 ;
}
static inline bool is_imx21_pllv1 ( struct clk_pllv1 * pll )
{
return pll - > type = = IMX_PLLV1_IMX21 ;
}
static inline bool is_imx27_pllv1 ( struct clk_pllv1 * pll )
{
return pll - > type = = IMX_PLLV1_IMX27 ;
}
static inline bool mfn_is_negative ( struct clk_pllv1 * pll , unsigned int mfn )
{
return ! is_imx1_pllv1 ( pll ) & & ! is_imx21_pllv1 ( pll ) & & ( mfn & MFN_SIGN ) ;
2013-11-10 13:34:49 +04:00
}
2012-03-09 12:11:55 +04:00
static unsigned long clk_pllv1_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_pllv1 * pll = to_clk_pllv1 ( hw ) ;
2015-11-04 03:46:23 +03:00
unsigned long long ull ;
2012-09-11 10:40:38 +04:00
int mfn_abs ;
unsigned int mfi , mfn , mfd , pd ;
u32 reg ;
unsigned long rate ;
2012-03-09 12:11:55 +04:00
2012-09-11 10:40:38 +04:00
reg = readl ( pll - > base ) ;
/*
* Get the resulting clock rate from a PLL register value and the input
* frequency . PLLs with this register layout can be found on i . MX1 ,
* i . MX21 , i . MX27 and i , MX31
*
* mfi + mfn / ( mfd + 1 )
* f = 2 * f_ref * - - - - - - - - - - - - - - - - - - - -
* pd + 1
*/
mfi = ( reg > > 10 ) & 0xf ;
mfn = reg & 0x3ff ;
mfd = ( reg > > 16 ) & 0x3ff ;
pd = ( reg > > 26 ) & 0xf ;
mfi = mfi < = 5 ? 5 : mfi ;
mfn_abs = mfn ;
/*
* On all i . MXs except i . MX1 and i . MX21 mfn is a 10 bit
2013-11-10 13:34:49 +04:00
* 2 ' s complements number .
* On i . MX27 the bit 9 is the sign bit .
2012-09-11 10:40:38 +04:00
*/
2015-04-26 08:33:39 +03:00
if ( mfn_is_negative ( pll , mfn ) ) {
if ( is_imx27_pllv1 ( pll ) )
2013-11-10 13:34:49 +04:00
mfn_abs = mfn & MFN_MASK ;
else
mfn_abs = BIT ( MFN_BITS ) - mfn ;
}
2012-09-11 10:40:38 +04:00
rate = parent_rate * 2 ;
rate / = pd + 1 ;
2015-11-04 03:46:23 +03:00
ull = ( unsigned long long ) rate * mfn_abs ;
2012-09-11 10:40:38 +04:00
2015-11-04 03:46:23 +03:00
do_div ( ull , mfd + 1 ) ;
2012-09-11 10:40:38 +04:00
2015-04-26 08:33:39 +03:00
if ( mfn_is_negative ( pll , mfn ) )
2015-11-04 03:46:23 +03:00
ull = ( rate * mfi ) - ull ;
else
ull = ( rate * mfi ) + ull ;
2012-09-11 10:40:38 +04:00
2015-11-04 03:46:23 +03:00
return ull ;
2012-03-09 12:11:55 +04:00
}
2013-03-25 16:20:33 +04:00
static struct clk_ops clk_pllv1_ops = {
2012-03-09 12:11:55 +04:00
. recalc_rate = clk_pllv1_recalc_rate ,
} ;
2015-04-26 08:33:39 +03:00
struct clk * imx_clk_pllv1 ( enum imx_pllv1_type type , const char * name ,
const char * parent , void __iomem * base )
2012-03-09 12:11:55 +04:00
{
struct clk_pllv1 * pll ;
struct clk * clk ;
struct clk_init_data init ;
pll = kmalloc ( sizeof ( * pll ) , GFP_KERNEL ) ;
if ( ! pll )
return ERR_PTR ( - ENOMEM ) ;
pll - > base = base ;
2015-04-26 08:33:39 +03:00
pll - > type = type ;
2012-03-09 12:11:55 +04:00
init . name = name ;
init . ops = & clk_pllv1_ops ;
init . flags = 0 ;
init . parent_names = & parent ;
init . num_parents = 1 ;
pll - > hw . init = & init ;
clk = clk_register ( NULL , & pll - > hw ) ;
if ( IS_ERR ( clk ) )
kfree ( pll ) ;
return clk ;
}