2011-07-08 13:40:12 +04:00
/*
* Clock tree for CSR SiRFprimaII
*
* Copyright ( c ) 2011 Cambridge Silicon Radio Limited , a CSR plc group company .
*
* Licensed under GPLv2 or later .
*/
# include <linux/module.h>
# include <linux/bitops.h>
# include <linux/io.h>
# include <linux/clk.h>
2012-08-20 10:42:36 +04:00
# include <linux/clkdev.h>
# include <linux/clk-provider.h>
2011-07-08 13:40:12 +04:00
# include <linux/of_address.h>
2012-08-20 10:42:36 +04:00
# include <linux/syscore_ops.h>
2011-07-08 13:40:12 +04:00
# define SIRFSOC_CLKC_CLK_EN0 0x0000
# define SIRFSOC_CLKC_CLK_EN1 0x0004
# define SIRFSOC_CLKC_REF_CFG 0x0014
# define SIRFSOC_CLKC_CPU_CFG 0x0018
# define SIRFSOC_CLKC_MEM_CFG 0x001c
# define SIRFSOC_CLKC_SYS_CFG 0x0020
# define SIRFSOC_CLKC_IO_CFG 0x0024
# define SIRFSOC_CLKC_DSP_CFG 0x0028
# define SIRFSOC_CLKC_GFX_CFG 0x002c
# define SIRFSOC_CLKC_MM_CFG 0x0030
2012-08-20 10:42:36 +04:00
# define SIRFSOC_CLKC_LCD_CFG 0x0034
2011-07-08 13:40:12 +04:00
# define SIRFSOC_CLKC_MMC_CFG 0x0038
# define SIRFSOC_CLKC_PLL1_CFG0 0x0040
# define SIRFSOC_CLKC_PLL2_CFG0 0x0044
# define SIRFSOC_CLKC_PLL3_CFG0 0x0048
# define SIRFSOC_CLKC_PLL1_CFG1 0x004c
# define SIRFSOC_CLKC_PLL2_CFG1 0x0050
# define SIRFSOC_CLKC_PLL3_CFG1 0x0054
# define SIRFSOC_CLKC_PLL1_CFG2 0x0058
# define SIRFSOC_CLKC_PLL2_CFG2 0x005c
# define SIRFSOC_CLKC_PLL3_CFG2 0x0060
2012-08-20 10:42:36 +04:00
# define SIRFSOC_USBPHY_PLL_CTRL 0x0008
# define SIRFSOC_USBPHY_PLL_POWERDOWN BIT(1)
# define SIRFSOC_USBPHY_PLL_BYPASS BIT(2)
# define SIRFSOC_USBPHY_PLL_LOCK BIT(3)
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static void * sirfsoc_clk_vbase , * sirfsoc_rsc_vbase ;
2011-07-08 13:40:12 +04:00
# define KHZ 1000
# define MHZ (KHZ * KHZ)
2012-08-20 10:42:36 +04:00
/*
* SiRFprimaII clock controller
* - 2 oscillators : osc - 26 MHz , rtc - 32.768 KHz
* - 3 standard configurable plls : pll1 , pll2 & pll3
* - 2 exclusive plls : usb phy pll and sata phy pll
* - 8 clock domains : cpu / cpudiv , mem / memdiv , sys / io , dsp , graphic , multimedia ,
* display and sdphy .
* Each clock domain can select its own clock source from five clock sources ,
* X_XIN , X_XINW , PLL1 , PLL2 and PLL3 . The domain clock is used as the source
* clock of the group clock .
* - dsp domain : gps , mf
* - io domain : dmac , nand , audio , uart , i2c , spi , usp , pwm , pulse
* - sys domain : security
*/
struct clk_pll {
struct clk_hw hw ;
unsigned short regofs ; /* register offset */
2011-07-08 13:40:12 +04:00
} ;
2012-08-20 10:42:36 +04:00
# define to_pllclk(_hw) container_of(_hw, struct clk_pll, hw)
struct clk_dmn {
struct clk_hw hw ;
2011-07-08 13:40:12 +04:00
signed char enable_bit ; /* enable bit: 0 ~ 63 */
unsigned short regofs ; /* register offset */
} ;
2012-08-20 10:42:36 +04:00
# define to_dmnclk(_hw) container_of(_hw, struct clk_dmn, hw)
struct clk_std {
struct clk_hw hw ;
signed char enable_bit ; /* enable bit: 0 ~ 63 */
} ;
# define to_stdclk(_hw) container_of(_hw, struct clk_std, hw)
static int std_clk_is_enabled ( struct clk_hw * hw ) ;
static int std_clk_enable ( struct clk_hw * hw ) ;
static void std_clk_disable ( struct clk_hw * hw ) ;
2011-07-08 13:40:12 +04:00
static inline unsigned long clkc_readl ( unsigned reg )
{
2012-08-20 10:42:36 +04:00
return readl ( sirfsoc_clk_vbase + reg ) ;
2011-07-08 13:40:12 +04:00
}
static inline void clkc_writel ( u32 val , unsigned reg )
{
2012-08-20 10:42:36 +04:00
writel ( val , sirfsoc_clk_vbase + reg ) ;
2011-07-08 13:40:12 +04:00
}
/*
* std pll
*/
2012-08-20 10:42:36 +04:00
static unsigned long pll_clk_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
2011-07-08 13:40:12 +04:00
{
2012-08-20 10:42:36 +04:00
unsigned long fin = parent_rate ;
struct clk_pll * clk = to_pllclk ( hw ) ;
2011-07-08 13:40:12 +04:00
u32 regcfg2 = clk - > regofs + SIRFSOC_CLKC_PLL1_CFG2 -
SIRFSOC_CLKC_PLL1_CFG0 ;
if ( clkc_readl ( regcfg2 ) & BIT ( 2 ) ) {
/* pll bypass mode */
2012-08-20 10:42:36 +04:00
return fin ;
2011-07-08 13:40:12 +04:00
} else {
/* fout = fin * nf / nr / od */
u32 cfg0 = clkc_readl ( clk - > regofs ) ;
u32 nf = ( cfg0 & ( BIT ( 13 ) - 1 ) ) + 1 ;
u32 nr = ( ( cfg0 > > 13 ) & ( BIT ( 6 ) - 1 ) ) + 1 ;
u32 od = ( ( cfg0 > > 19 ) & ( BIT ( 4 ) - 1 ) ) + 1 ;
WARN_ON ( fin % MHZ ) ;
2012-08-20 10:42:36 +04:00
return fin / MHZ * nf / nr / od * MHZ ;
2011-07-08 13:40:12 +04:00
}
2012-08-20 10:42:36 +04:00
}
static long pll_clk_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * parent_rate )
{
unsigned long fin , nf , nr , od ;
/*
* fout = fin * nf / ( nr * od ) ;
* set od = 1 , nr = fin / MHz , so fout = nf * MHz
*/
rate = rate - rate % MHZ ;
nf = rate / MHZ ;
if ( nf > BIT ( 13 ) )
nf = BIT ( 13 ) ;
if ( nf < 1 )
nf = 1 ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
fin = * parent_rate ;
nr = fin / MHZ ;
if ( nr > BIT ( 6 ) )
nr = BIT ( 6 ) ;
od = 1 ;
return fin * nf / ( nr * od ) ;
2011-07-08 13:40:12 +04:00
}
2012-08-20 10:42:36 +04:00
static int pll_clk_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
2011-07-08 13:40:12 +04:00
{
2012-08-20 10:42:36 +04:00
struct clk_pll * clk = to_pllclk ( hw ) ;
2011-07-08 13:40:12 +04:00
unsigned long fin , nf , nr , od , reg ;
/*
* fout = fin * nf / ( nr * od ) ;
* set od = 1 , nr = fin / MHz , so fout = nf * MHz
*/
nf = rate / MHZ ;
if ( unlikely ( ( rate % MHZ ) | | nf > BIT ( 13 ) | | nf < 1 ) )
return - EINVAL ;
2012-08-20 10:42:36 +04:00
fin = parent_rate ;
2011-07-08 13:40:12 +04:00
BUG_ON ( fin < MHZ ) ;
nr = fin / MHZ ;
BUG_ON ( ( fin % MHZ ) | | nr > BIT ( 6 ) ) ;
od = 1 ;
reg = ( nf - 1 ) | ( ( nr - 1 ) < < 13 ) | ( ( od - 1 ) < < 19 ) ;
clkc_writel ( reg , clk - > regofs ) ;
reg = clk - > regofs + SIRFSOC_CLKC_PLL1_CFG1 - SIRFSOC_CLKC_PLL1_CFG0 ;
clkc_writel ( ( nf > > 1 ) - 1 , reg ) ;
reg = clk - > regofs + SIRFSOC_CLKC_PLL1_CFG2 - SIRFSOC_CLKC_PLL1_CFG0 ;
while ( ! ( clkc_readl ( reg ) & BIT ( 6 ) ) )
cpu_relax ( ) ;
return 0 ;
}
static struct clk_ops std_pll_ops = {
2012-08-20 10:42:36 +04:00
. recalc_rate = pll_clk_recalc_rate ,
. round_rate = pll_clk_round_rate ,
. set_rate = pll_clk_set_rate ,
2011-07-08 13:40:12 +04:00
} ;
2012-08-20 10:42:36 +04:00
static const char * pll_clk_parents [ ] = {
" osc " ,
} ;
static struct clk_init_data clk_pll1_init = {
. name = " pll1 " ,
2011-07-08 13:40:12 +04:00
. ops = & std_pll_ops ,
2012-08-20 10:42:36 +04:00
. parent_names = pll_clk_parents ,
. num_parents = ARRAY_SIZE ( pll_clk_parents ) ,
2011-07-08 13:40:12 +04:00
} ;
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_pll2_init = {
. name = " pll2 " ,
2011-07-08 13:40:12 +04:00
. ops = & std_pll_ops ,
2012-08-20 10:42:36 +04:00
. parent_names = pll_clk_parents ,
. num_parents = ARRAY_SIZE ( pll_clk_parents ) ,
2011-07-08 13:40:12 +04:00
} ;
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_pll3_init = {
. name = " pll3 " ,
2011-07-08 13:40:12 +04:00
. ops = & std_pll_ops ,
2012-08-20 10:42:36 +04:00
. parent_names = pll_clk_parents ,
. num_parents = ARRAY_SIZE ( pll_clk_parents ) ,
} ;
static struct clk_pll clk_pll1 = {
. regofs = SIRFSOC_CLKC_PLL1_CFG0 ,
. hw = {
. init = & clk_pll1_init ,
} ,
} ;
static struct clk_pll clk_pll2 = {
. regofs = SIRFSOC_CLKC_PLL2_CFG0 ,
. hw = {
. init = & clk_pll2_init ,
} ,
} ;
static struct clk_pll clk_pll3 = {
. regofs = SIRFSOC_CLKC_PLL3_CFG0 ,
. hw = {
. init = & clk_pll3_init ,
} ,
2011-07-08 13:40:12 +04:00
} ;
/*
2012-08-20 10:42:36 +04:00
* usb uses specified pll
2011-07-08 13:40:12 +04:00
*/
2012-08-20 10:42:36 +04:00
static int usb_pll_clk_enable ( struct clk_hw * hw )
{
u32 reg = readl ( sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL ) ;
reg & = ~ ( SIRFSOC_USBPHY_PLL_POWERDOWN | SIRFSOC_USBPHY_PLL_BYPASS ) ;
writel ( reg , sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL ) ;
while ( ! ( readl ( sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL ) &
SIRFSOC_USBPHY_PLL_LOCK ) )
cpu_relax ( ) ;
return 0 ;
}
static void usb_pll_clk_disable ( struct clk_hw * clk )
{
u32 reg = readl ( sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL ) ;
reg | = ( SIRFSOC_USBPHY_PLL_POWERDOWN | SIRFSOC_USBPHY_PLL_BYPASS ) ;
writel ( reg , sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL ) ;
}
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static unsigned long usb_pll_clk_recalc_rate ( struct clk_hw * hw , unsigned long parent_rate )
2011-07-08 13:40:12 +04:00
{
2012-08-20 10:42:36 +04:00
u32 reg = readl ( sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL ) ;
return ( reg & SIRFSOC_USBPHY_PLL_BYPASS ) ? parent_rate : 48 * MHZ ;
}
static struct clk_ops usb_pll_ops = {
. enable = usb_pll_clk_enable ,
. disable = usb_pll_clk_disable ,
. recalc_rate = usb_pll_clk_recalc_rate ,
} ;
static struct clk_init_data clk_usb_pll_init = {
. name = " usb_pll " ,
. ops = & usb_pll_ops ,
. parent_names = pll_clk_parents ,
. num_parents = ARRAY_SIZE ( pll_clk_parents ) ,
} ;
static struct clk_hw usb_pll_clk_hw = {
. init = & clk_usb_pll_init ,
} ;
/*
* clock domains - cpu , mem , sys / io , dsp , gfx
*/
static const char * dmn_clk_parents [ ] = {
" rtc " ,
" osc " ,
" pll1 " ,
" pll2 " ,
" pll3 " ,
} ;
static u8 dmn_clk_get_parent ( struct clk_hw * hw )
{
struct clk_dmn * clk = to_dmnclk ( hw ) ;
2011-07-08 13:40:12 +04:00
u32 cfg = clkc_readl ( clk - > regofs ) ;
2012-08-20 10:42:36 +04:00
/* parent of io domain can only be pll3 */
if ( strcmp ( hw - > init - > name , " io " ) = = 0 )
return 4 ;
2011-07-08 13:40:12 +04:00
WARN_ON ( ( cfg & ( BIT ( 3 ) - 1 ) ) > 4 ) ;
2012-08-20 10:42:36 +04:00
return cfg & ( BIT ( 3 ) - 1 ) ;
2011-07-08 13:40:12 +04:00
}
2012-08-20 10:42:36 +04:00
static int dmn_clk_set_parent ( struct clk_hw * hw , u8 parent )
2011-07-08 13:40:12 +04:00
{
2012-08-20 10:42:36 +04:00
struct clk_dmn * clk = to_dmnclk ( hw ) ;
2011-07-08 13:40:12 +04:00
u32 cfg = clkc_readl ( clk - > regofs ) ;
2012-08-20 10:42:36 +04:00
/* parent of io domain can only be pll3 */
if ( strcmp ( hw - > init - > name , " io " ) = = 0 )
return - EINVAL ;
cfg & = ~ ( BIT ( 3 ) - 1 ) ;
clkc_writel ( cfg | parent , clk - > regofs ) ;
/* BIT(3) - switching status: 1 - busy, 0 - done */
while ( clkc_readl ( clk - > regofs ) & BIT ( 3 ) )
cpu_relax ( ) ;
return 0 ;
2011-07-08 13:40:12 +04:00
}
2012-08-20 10:42:36 +04:00
static unsigned long dmn_clk_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
2011-07-08 13:40:12 +04:00
{
2012-08-20 10:42:36 +04:00
unsigned long fin = parent_rate ;
struct clk_dmn * clk = to_dmnclk ( hw ) ;
2011-07-08 13:40:12 +04:00
u32 cfg = clkc_readl ( clk - > regofs ) ;
2012-08-20 10:42:36 +04:00
2011-07-08 13:40:12 +04:00
if ( cfg & BIT ( 24 ) ) {
/* fcd bypass mode */
2012-08-20 10:42:36 +04:00
return fin ;
2011-07-08 13:40:12 +04:00
} else {
/*
* wait count : bit [ 19 : 16 ] , hold count : bit [ 23 : 20 ]
*/
u32 wait = ( cfg > > 16 ) & ( BIT ( 4 ) - 1 ) ;
u32 hold = ( cfg > > 20 ) & ( BIT ( 4 ) - 1 ) ;
2012-08-20 10:42:36 +04:00
return fin / ( wait + hold + 2 ) ;
2011-07-08 13:40:12 +04:00
}
2012-08-20 10:42:36 +04:00
}
static long dmn_clk_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * parent_rate )
{
unsigned long fin ;
unsigned ratio , wait , hold ;
unsigned bits = ( strcmp ( hw - > init - > name , " mem " ) = = 0 ) ? 3 : 4 ;
fin = * parent_rate ;
ratio = fin / rate ;
if ( ratio < 2 )
ratio = 2 ;
if ( ratio > BIT ( bits + 1 ) )
ratio = BIT ( bits + 1 ) ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
wait = ( ratio > > 1 ) - 1 ;
hold = ratio - wait - 2 ;
return fin / ( wait + hold + 2 ) ;
2011-07-08 13:40:12 +04:00
}
2012-08-20 10:42:36 +04:00
static int dmn_clk_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
2011-07-08 13:40:12 +04:00
{
2012-08-20 10:42:36 +04:00
struct clk_dmn * clk = to_dmnclk ( hw ) ;
2011-07-08 13:40:12 +04:00
unsigned long fin ;
unsigned ratio , wait , hold , reg ;
2012-08-20 10:42:36 +04:00
unsigned bits = ( strcmp ( hw - > init - > name , " mem " ) = = 0 ) ? 3 : 4 ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
fin = parent_rate ;
2011-07-08 13:40:12 +04:00
ratio = fin / rate ;
if ( unlikely ( ratio < 2 | | ratio > BIT ( bits + 1 ) ) )
return - EINVAL ;
WARN_ON ( fin % rate ) ;
wait = ( ratio > > 1 ) - 1 ;
hold = ratio - wait - 2 ;
reg = clkc_readl ( clk - > regofs ) ;
reg & = ~ ( ( ( BIT ( bits ) - 1 ) < < 16 ) | ( ( BIT ( bits ) - 1 ) < < 20 ) ) ;
reg | = ( wait < < 16 ) | ( hold < < 20 ) | BIT ( 25 ) ;
clkc_writel ( reg , clk - > regofs ) ;
/* waiting FCD been effective */
while ( clkc_readl ( clk - > regofs ) & BIT ( 25 ) )
cpu_relax ( ) ;
return 0 ;
}
2012-08-20 10:42:36 +04:00
static struct clk_ops msi_ops = {
. set_rate = dmn_clk_set_rate ,
. round_rate = dmn_clk_round_rate ,
. recalc_rate = dmn_clk_recalc_rate ,
. set_parent = dmn_clk_set_parent ,
. get_parent = dmn_clk_get_parent ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_mem_init = {
. name = " mem " ,
. ops = & msi_ops ,
. parent_names = dmn_clk_parents ,
. num_parents = ARRAY_SIZE ( dmn_clk_parents ) ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_dmn clk_mem = {
. regofs = SIRFSOC_CLKC_MEM_CFG ,
. hw = {
. init = & clk_mem_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_sys_init = {
. name = " sys " ,
. ops = & msi_ops ,
. parent_names = dmn_clk_parents ,
. num_parents = ARRAY_SIZE ( dmn_clk_parents ) ,
. flags = CLK_SET_RATE_GATE ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_dmn clk_sys = {
. regofs = SIRFSOC_CLKC_SYS_CFG ,
. hw = {
. init = & clk_sys_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_io_init = {
. name = " io " ,
. ops = & msi_ops ,
. parent_names = dmn_clk_parents ,
. num_parents = ARRAY_SIZE ( dmn_clk_parents ) ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_dmn clk_io = {
. regofs = SIRFSOC_CLKC_IO_CFG ,
. hw = {
. init = & clk_io_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
static struct clk_ops cpu_ops = {
2012-08-20 10:42:36 +04:00
. set_parent = dmn_clk_set_parent ,
. get_parent = dmn_clk_get_parent ,
2011-07-08 13:40:12 +04:00
} ;
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_cpu_init = {
. name = " cpu " ,
2011-07-08 13:40:12 +04:00
. ops = & cpu_ops ,
2012-08-20 10:42:36 +04:00
. parent_names = dmn_clk_parents ,
. num_parents = ARRAY_SIZE ( dmn_clk_parents ) ,
. flags = CLK_SET_RATE_PARENT ,
2011-07-08 13:40:12 +04:00
} ;
2012-08-20 10:42:36 +04:00
static struct clk_dmn clk_cpu = {
. regofs = SIRFSOC_CLKC_CPU_CFG ,
. hw = {
. init = & clk_cpu_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_ops dmn_ops = {
. is_enabled = std_clk_is_enabled ,
. enable = std_clk_enable ,
. disable = std_clk_disable ,
. set_rate = dmn_clk_set_rate ,
. round_rate = dmn_clk_round_rate ,
. recalc_rate = dmn_clk_recalc_rate ,
. set_parent = dmn_clk_set_parent ,
. get_parent = dmn_clk_get_parent ,
2011-07-08 13:40:12 +04:00
} ;
2012-08-20 10:42:36 +04:00
/* dsp, gfx, mm, lcd and vpp domain */
static struct clk_init_data clk_dsp_init = {
. name = " dsp " ,
. ops = & dmn_ops ,
. parent_names = dmn_clk_parents ,
. num_parents = ARRAY_SIZE ( dmn_clk_parents ) ,
2011-07-08 13:40:12 +04:00
} ;
2012-08-20 10:42:36 +04:00
static struct clk_dmn clk_dsp = {
. regofs = SIRFSOC_CLKC_DSP_CFG ,
. enable_bit = 0 ,
. hw = {
. init = & clk_dsp_init ,
} ,
2011-07-08 13:40:12 +04:00
} ;
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_gfx_init = {
. name = " gfx " ,
. ops = & dmn_ops ,
. parent_names = dmn_clk_parents ,
. num_parents = ARRAY_SIZE ( dmn_clk_parents ) ,
2011-07-08 13:40:12 +04:00
} ;
2012-08-20 10:42:36 +04:00
static struct clk_dmn clk_gfx = {
. regofs = SIRFSOC_CLKC_GFX_CFG ,
. enable_bit = 8 ,
. hw = {
. init = & clk_gfx_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_mm_init = {
. name = " mm " ,
. ops = & dmn_ops ,
. parent_names = dmn_clk_parents ,
. num_parents = ARRAY_SIZE ( dmn_clk_parents ) ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_dmn clk_mm = {
. regofs = SIRFSOC_CLKC_MM_CFG ,
. enable_bit = 9 ,
. hw = {
. init = & clk_mm_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_lcd_init = {
. name = " lcd " ,
. ops = & dmn_ops ,
. parent_names = dmn_clk_parents ,
. num_parents = ARRAY_SIZE ( dmn_clk_parents ) ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_dmn clk_lcd = {
. regofs = SIRFSOC_CLKC_LCD_CFG ,
. enable_bit = 10 ,
. hw = {
. init = & clk_lcd_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_vpp_init = {
. name = " vpp " ,
. ops = & dmn_ops ,
. parent_names = dmn_clk_parents ,
. num_parents = ARRAY_SIZE ( dmn_clk_parents ) ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_dmn clk_vpp = {
. regofs = SIRFSOC_CLKC_LCD_CFG ,
. enable_bit = 11 ,
. hw = {
. init = & clk_vpp_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_mmc01_init = {
. name = " mmc01 " ,
. ops = & dmn_ops ,
. parent_names = dmn_clk_parents ,
. num_parents = ARRAY_SIZE ( dmn_clk_parents ) ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_dmn clk_mmc01 = {
. regofs = SIRFSOC_CLKC_MMC_CFG ,
. enable_bit = 59 ,
. hw = {
. init = & clk_mmc01_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_mmc23_init = {
. name = " mmc23 " ,
. ops = & dmn_ops ,
. parent_names = dmn_clk_parents ,
. num_parents = ARRAY_SIZE ( dmn_clk_parents ) ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_dmn clk_mmc23 = {
. regofs = SIRFSOC_CLKC_MMC_CFG ,
. enable_bit = 60 ,
. hw = {
. init = & clk_mmc23_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_mmc45_init = {
. name = " mmc45 " ,
. ops = & dmn_ops ,
. parent_names = dmn_clk_parents ,
. num_parents = ARRAY_SIZE ( dmn_clk_parents ) ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_dmn clk_mmc45 = {
. regofs = SIRFSOC_CLKC_MMC_CFG ,
. enable_bit = 61 ,
. hw = {
. init = & clk_mmc45_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
/*
* peripheral controllers in io domain
*/
static int std_clk_is_enabled ( struct clk_hw * hw )
2011-07-08 13:40:12 +04:00
{
2012-08-20 10:42:36 +04:00
u32 reg ;
int bit ;
struct clk_std * clk = to_stdclk ( hw ) ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
bit = clk - > enable_bit % 32 ;
reg = clk - > enable_bit / 32 ;
reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof ( reg ) ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
return ! ! ( clkc_readl ( reg ) & BIT ( bit ) ) ;
2011-07-08 13:40:12 +04:00
}
2012-08-20 10:42:36 +04:00
static int std_clk_enable ( struct clk_hw * hw )
2011-07-08 13:40:12 +04:00
{
2012-08-20 10:42:36 +04:00
u32 val , reg ;
int bit ;
struct clk_std * clk = to_stdclk ( hw ) ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
BUG_ON ( clk - > enable_bit < 0 | | clk - > enable_bit > 63 ) ;
bit = clk - > enable_bit % 32 ;
reg = clk - > enable_bit / 32 ;
reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof ( reg ) ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
val = clkc_readl ( reg ) | BIT ( bit ) ;
clkc_writel ( val , reg ) ;
return 0 ;
2011-07-08 13:40:12 +04:00
}
2012-08-20 10:42:36 +04:00
static void std_clk_disable ( struct clk_hw * hw )
2011-07-08 13:40:12 +04:00
{
2012-08-20 10:42:36 +04:00
u32 val , reg ;
int bit ;
struct clk_std * clk = to_stdclk ( hw ) ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
BUG_ON ( clk - > enable_bit < 0 | | clk - > enable_bit > 63 ) ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
bit = clk - > enable_bit % 32 ;
reg = clk - > enable_bit / 32 ;
reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof ( reg ) ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
val = clkc_readl ( reg ) & ~ BIT ( bit ) ;
clkc_writel ( val , reg ) ;
2011-07-08 13:40:12 +04:00
}
2012-08-20 10:42:36 +04:00
static const char * std_clk_io_parents [ ] = {
" io " ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_ops ios_ops = {
. is_enabled = std_clk_is_enabled ,
. enable = std_clk_enable ,
. disable = std_clk_disable ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_dmac0_init = {
. name = " dmac0 " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_std clk_dmac0 = {
. enable_bit = 32 ,
. hw = {
. init = & clk_dmac0_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
static struct clk_init_data clk_dmac1_init = {
. name = " dmac1 " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_dmac1 = {
. enable_bit = 33 ,
. hw = {
. init = & clk_dmac1_init ,
} ,
} ;
static struct clk_init_data clk_nand_init = {
. name = " nand " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_nand = {
. enable_bit = 34 ,
. hw = {
. init = & clk_nand_init ,
} ,
} ;
static struct clk_init_data clk_audio_init = {
. name = " audio " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_audio = {
. enable_bit = 35 ,
. hw = {
. init = & clk_audio_init ,
} ,
} ;
static struct clk_init_data clk_uart0_init = {
. name = " uart0 " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_uart0 = {
. enable_bit = 36 ,
. hw = {
. init = & clk_uart0_init ,
} ,
} ;
static struct clk_init_data clk_uart1_init = {
. name = " uart1 " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_uart1 = {
. enable_bit = 37 ,
. hw = {
. init = & clk_uart1_init ,
} ,
} ;
static struct clk_init_data clk_uart2_init = {
. name = " uart2 " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_uart2 = {
. enable_bit = 38 ,
. hw = {
. init = & clk_uart2_init ,
} ,
} ;
static struct clk_init_data clk_usp0_init = {
. name = " usp0 " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_usp0 = {
. enable_bit = 39 ,
. hw = {
. init = & clk_usp0_init ,
} ,
} ;
static struct clk_init_data clk_usp1_init = {
. name = " usp1 " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_usp1 = {
. enable_bit = 40 ,
. hw = {
. init = & clk_usp1_init ,
} ,
} ;
static struct clk_init_data clk_usp2_init = {
. name = " usp2 " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_usp2 = {
. enable_bit = 41 ,
. hw = {
. init = & clk_usp2_init ,
} ,
} ;
static struct clk_init_data clk_vip_init = {
. name = " vip " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_vip = {
. enable_bit = 42 ,
. hw = {
. init = & clk_vip_init ,
} ,
} ;
static struct clk_init_data clk_spi0_init = {
. name = " spi0 " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_spi0 = {
. enable_bit = 43 ,
. hw = {
. init = & clk_spi0_init ,
} ,
} ;
static struct clk_init_data clk_spi1_init = {
. name = " spi1 " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_spi1 = {
. enable_bit = 44 ,
. hw = {
. init = & clk_spi1_init ,
} ,
} ;
static struct clk_init_data clk_tsc_init = {
. name = " tsc " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_tsc = {
. enable_bit = 45 ,
. hw = {
. init = & clk_tsc_init ,
} ,
} ;
static struct clk_init_data clk_i2c0_init = {
. name = " i2c0 " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_i2c0 = {
. enable_bit = 46 ,
. hw = {
. init = & clk_i2c0_init ,
} ,
} ;
static struct clk_init_data clk_i2c1_init = {
. name = " i2c1 " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_i2c1 = {
. enable_bit = 47 ,
. hw = {
. init = & clk_i2c1_init ,
} ,
} ;
static struct clk_init_data clk_pwmc_init = {
. name = " pwmc " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_pwmc = {
. enable_bit = 48 ,
. hw = {
. init = & clk_pwmc_init ,
} ,
} ;
static struct clk_init_data clk_efuse_init = {
. name = " efuse " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_efuse = {
. enable_bit = 49 ,
. hw = {
. init = & clk_efuse_init ,
} ,
} ;
static struct clk_init_data clk_pulse_init = {
. name = " pulse " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_pulse = {
. enable_bit = 50 ,
. hw = {
. init = & clk_pulse_init ,
} ,
} ;
static const char * std_clk_dsp_parents [ ] = {
" dsp " ,
} ;
static struct clk_init_data clk_gps_init = {
. name = " gps " ,
. ops = & ios_ops ,
. parent_names = std_clk_dsp_parents ,
. num_parents = ARRAY_SIZE ( std_clk_dsp_parents ) ,
} ;
static struct clk_std clk_gps = {
. enable_bit = 1 ,
. hw = {
. init = & clk_gps_init ,
} ,
} ;
static struct clk_init_data clk_mf_init = {
. name = " mf " ,
. ops = & ios_ops ,
. parent_names = std_clk_io_parents ,
. num_parents = ARRAY_SIZE ( std_clk_io_parents ) ,
} ;
static struct clk_std clk_mf = {
. enable_bit = 2 ,
. hw = {
. init = & clk_mf_init ,
} ,
} ;
static const char * std_clk_sys_parents [ ] = {
" sys " ,
} ;
static struct clk_init_data clk_security_init = {
. name = " mf " ,
. ops = & ios_ops ,
. parent_names = std_clk_sys_parents ,
. num_parents = ARRAY_SIZE ( std_clk_sys_parents ) ,
} ;
static struct clk_std clk_security = {
. enable_bit = 19 ,
. hw = {
. init = & clk_security_init ,
} ,
} ;
static const char * std_clk_usb_parents [ ] = {
" usb_pll " ,
} ;
static struct clk_init_data clk_usb0_init = {
. name = " usb0 " ,
. ops = & ios_ops ,
. parent_names = std_clk_usb_parents ,
. num_parents = ARRAY_SIZE ( std_clk_usb_parents ) ,
} ;
static struct clk_std clk_usb0 = {
. enable_bit = 16 ,
. hw = {
. init = & clk_usb0_init ,
} ,
} ;
static struct clk_init_data clk_usb1_init = {
. name = " usb1 " ,
. ops = & ios_ops ,
. parent_names = std_clk_usb_parents ,
. num_parents = ARRAY_SIZE ( std_clk_usb_parents ) ,
} ;
static struct clk_std clk_usb1 = {
. enable_bit = 17 ,
. hw = {
. init = & clk_usb1_init ,
} ,
} ;
2011-07-08 13:40:12 +04:00
2012-12-20 12:51:31 +04:00
enum prima2_clk_index {
/* 0 1 2 3 4 5 6 7 8 9 */
rtc , osc , pll1 , pll2 , pll3 , mem , sys , security , dsp , gps ,
mf , io , cpu , uart0 , uart1 , uart2 , tsc , i2c0 , i2c1 , spi0 ,
spi1 , pwmc , efuse , pulse , dmac0 , dmac1 , nand , audio , usp0 , usp1 ,
usp2 , vip , gfx , mm , lcd , vpp , mmc01 , mmc23 , mmc45 , usbpll ,
usb0 , usb1 , maxclk ,
} ;
2013-08-08 08:31:26 +04:00
static struct clk_hw * prima2_clk_hw_array [ maxclk ] __initdata = {
2012-12-20 12:51:31 +04:00
NULL , /* dummy */
NULL ,
& clk_pll1 . hw ,
& clk_pll2 . hw ,
& clk_pll3 . hw ,
& clk_mem . hw ,
& clk_sys . hw ,
& clk_security . hw ,
& clk_dsp . hw ,
& clk_gps . hw ,
& clk_mf . hw ,
& clk_io . hw ,
& clk_cpu . hw ,
& clk_uart0 . hw ,
& clk_uart1 . hw ,
& clk_uart2 . hw ,
& clk_tsc . hw ,
& clk_i2c0 . hw ,
& clk_i2c1 . hw ,
& clk_spi0 . hw ,
& clk_spi1 . hw ,
& clk_pwmc . hw ,
& clk_efuse . hw ,
& clk_pulse . hw ,
& clk_dmac0 . hw ,
& clk_dmac1 . hw ,
& clk_nand . hw ,
& clk_audio . hw ,
& clk_usp0 . hw ,
& clk_usp1 . hw ,
& clk_usp2 . hw ,
& clk_vip . hw ,
& clk_gfx . hw ,
& clk_mm . hw ,
& clk_lcd . hw ,
& clk_vpp . hw ,
& clk_mmc01 . hw ,
& clk_mmc23 . hw ,
& clk_mmc45 . hw ,
& usb_pll_clk_hw ,
& clk_usb0 . hw ,
& clk_usb1 . hw ,
} ;
static struct clk * prima2_clks [ maxclk ] ;
static struct clk_onecell_data clk_data ;
2013-09-04 16:21:18 +04:00
static void __init sirfsoc_clk_init ( struct device_node * np )
2011-07-08 13:40:12 +04:00
{
2013-09-04 16:21:18 +04:00
struct device_node * rscnp ;
2012-12-20 12:51:31 +04:00
int i ;
2011-07-08 13:40:12 +04:00
2013-09-04 16:21:18 +04:00
rscnp = of_find_compatible_node ( NULL , NULL , " sirf,prima2-rsc " ) ;
sirfsoc_rsc_vbase = of_iomap ( rscnp , 0 ) ;
2012-08-20 10:42:36 +04:00
if ( ! sirfsoc_rsc_vbase )
panic ( " unable to map rsc registers \n " ) ;
2013-09-04 16:21:18 +04:00
of_node_put ( rscnp ) ;
2012-12-20 12:51:31 +04:00
sirfsoc_clk_vbase = of_iomap ( np , 0 ) ;
if ( ! sirfsoc_clk_vbase )
panic ( " unable to map clkc registers \n " ) ;
2011-07-08 13:40:12 +04:00
2012-08-20 10:42:36 +04:00
/* These are always available (RTC and 26MHz OSC)*/
2012-12-20 12:51:31 +04:00
prima2_clks [ rtc ] = clk_register_fixed_rate ( NULL , " rtc " , NULL ,
2012-08-20 10:42:36 +04:00
CLK_IS_ROOT , 32768 ) ;
2012-12-20 12:51:31 +04:00
prima2_clks [ osc ] = clk_register_fixed_rate ( NULL , " osc " , NULL ,
2012-08-20 10:42:36 +04:00
CLK_IS_ROOT , 26000000 ) ;
2012-12-20 12:51:31 +04:00
for ( i = pll1 ; i < maxclk ; i + + ) {
prima2_clks [ i ] = clk_register ( NULL , prima2_clk_hw_array [ i ] ) ;
2013-03-11 19:55:18 +04:00
BUG_ON ( IS_ERR ( prima2_clks [ i ] ) ) ;
2012-12-20 12:51:31 +04:00
}
clk_register_clkdev ( prima2_clks [ cpu ] , NULL , " cpu " ) ;
clk_register_clkdev ( prima2_clks [ io ] , NULL , " io " ) ;
clk_register_clkdev ( prima2_clks [ mem ] , NULL , " mem " ) ;
clk_data . clks = prima2_clks ;
clk_data . clk_num = maxclk ;
of_clk_add_provider ( np , of_clk_src_onecell_get , & clk_data ) ;
2011-07-08 13:40:12 +04:00
}
2013-09-04 16:21:18 +04:00
CLK_OF_DECLARE ( sirfsoc_clk , " sirf,prima2-clkc " , sirfsoc_clk_init ) ;