2010-11-17 13:59:31 +03:00
/*
* sh73a0 clock framework support
*
* Copyright ( C ) 2010 Magnus Damm
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/io.h>
# include <linux/sh_clk.h>
2011-01-07 05:49:49 +03:00
# include <linux/clkdev.h>
2010-11-17 13:59:31 +03:00
# include <mach/common.h>
2010-12-03 10:22:31 +03:00
# define FRQCRA 0xe6150000
# define FRQCRB 0xe6150004
# define FRQCRD 0xe61500e4
# define VCLKCR1 0xe6150008
# define VCLKCR2 0xe615000C
# define VCLKCR3 0xe615001C
# define ZBCKCR 0xe6150010
# define FLCKCR 0xe6150014
# define SD0CKCR 0xe6150074
# define SD1CKCR 0xe6150078
# define SD2CKCR 0xe615007C
# define FSIACKCR 0xe6150018
# define FSIBCKCR 0xe6150090
# define SUBCKCR 0xe6150080
# define SPUACKCR 0xe6150084
# define SPUVCKCR 0xe6150094
# define MSUCKCR 0xe6150088
# define HSICKCR 0xe615008C
# define MFCK1CR 0xe6150098
# define MFCK2CR 0xe615009C
# define DSITCKCR 0xe6150060
# define DSI0PCKCR 0xe6150064
# define DSI1PCKCR 0xe6150068
# define DSI0PHYCR 0xe615006C
# define DSI1PHYCR 0xe6150070
# define PLLECR 0xe61500d0
# define PLL0CR 0xe61500d8
# define PLL1CR 0xe6150028
# define PLL2CR 0xe615002c
# define PLL3CR 0xe61500dc
2010-11-17 13:59:31 +03:00
# define SMSTPCR0 0xe6150130
# define SMSTPCR1 0xe6150134
# define SMSTPCR2 0xe6150138
# define SMSTPCR3 0xe615013c
# define SMSTPCR4 0xe6150140
# define SMSTPCR5 0xe6150144
2010-12-03 10:22:31 +03:00
# define CKSCR 0xe61500c0
2010-11-17 13:59:31 +03:00
/* Fixed 32 KHz root clock from EXTALR pin */
static struct clk r_clk = {
. rate = 32768 ,
} ;
2010-12-03 10:22:31 +03:00
/*
* 26 MHz default rate for the EXTAL1 root input clock .
* If needed , reset this with clk_set_rate ( ) from the platform code .
*/
struct clk sh73a0_extal1_clk = {
. rate = 26000000 ,
} ;
/*
* 48 MHz default rate for the EXTAL2 root input clock .
* If needed , reset this with clk_set_rate ( ) from the platform code .
*/
struct clk sh73a0_extal2_clk = {
. rate = 48000000 ,
} ;
/* A fixed divide-by-2 block */
static unsigned long div2_recalc ( struct clk * clk )
{
return clk - > parent - > rate / 2 ;
}
static struct clk_ops div2_clk_ops = {
. recalc = div2_recalc ,
} ;
/* Divide extal1 by two */
static struct clk extal1_div2_clk = {
. ops = & div2_clk_ops ,
. parent = & sh73a0_extal1_clk ,
} ;
/* Divide extal2 by two */
static struct clk extal2_div2_clk = {
. ops = & div2_clk_ops ,
. parent = & sh73a0_extal2_clk ,
} ;
static struct clk_ops main_clk_ops = {
. recalc = followparent_recalc ,
} ;
/* Main clock */
static struct clk main_clk = {
. ops = & main_clk_ops ,
} ;
/* PLL0, PLL1, PLL2, PLL3 */
static unsigned long pll_recalc ( struct clk * clk )
{
unsigned long mult = 1 ;
if ( __raw_readl ( PLLECR ) & ( 1 < < clk - > enable_bit ) )
mult = ( ( ( __raw_readl ( clk - > enable_reg ) > > 24 ) & 0x3f ) + 1 ) ;
return clk - > parent - > rate * mult ;
}
static struct clk_ops pll_clk_ops = {
. recalc = pll_recalc ,
} ;
static struct clk pll0_clk = {
. ops = & pll_clk_ops ,
. flags = CLK_ENABLE_ON_INIT ,
. parent = & main_clk ,
. enable_reg = ( void __iomem * ) PLL0CR ,
. enable_bit = 0 ,
2010-11-17 13:59:31 +03:00
} ;
2010-12-03 10:22:31 +03:00
static struct clk pll1_clk = {
. ops = & pll_clk_ops ,
. flags = CLK_ENABLE_ON_INIT ,
. parent = & main_clk ,
. enable_reg = ( void __iomem * ) PLL1CR ,
. enable_bit = 1 ,
} ;
static struct clk pll2_clk = {
. ops = & pll_clk_ops ,
. flags = CLK_ENABLE_ON_INIT ,
. parent = & main_clk ,
. enable_reg = ( void __iomem * ) PLL2CR ,
. enable_bit = 2 ,
} ;
static struct clk pll3_clk = {
. ops = & pll_clk_ops ,
. flags = CLK_ENABLE_ON_INIT ,
. parent = & main_clk ,
. enable_reg = ( void __iomem * ) PLL3CR ,
. enable_bit = 3 ,
} ;
/* Divide PLL1 by two */
static struct clk pll1_div2_clk = {
. ops = & div2_clk_ops ,
. parent = & pll1_clk ,
2010-11-19 16:20:45 +03:00
} ;
2010-11-17 13:59:31 +03:00
static struct clk * main_clks [ ] = {
& r_clk ,
2010-12-03 10:22:31 +03:00
& sh73a0_extal1_clk ,
& sh73a0_extal2_clk ,
& extal1_div2_clk ,
& extal2_div2_clk ,
& main_clk ,
& pll0_clk ,
& pll1_clk ,
& pll2_clk ,
& pll3_clk ,
& pll1_div2_clk ,
} ;
static void div4_kick ( struct clk * clk )
{
unsigned long value ;
/* set KICK bit in FRQCRB to update hardware setting */
value = __raw_readl ( FRQCRB ) ;
value | = ( 1 < < 31 ) ;
__raw_writel ( value , FRQCRB ) ;
}
static int divisors [ ] = { 2 , 3 , 4 , 6 , 8 , 12 , 16 , 18 ,
2010-12-22 17:15:08 +03:00
24 , 0 , 36 , 48 , 7 } ;
2010-12-03 10:22:31 +03:00
static struct clk_div_mult_table div4_div_mult_table = {
. divisors = divisors ,
. nr_divisors = ARRAY_SIZE ( divisors ) ,
} ;
static struct clk_div4_table div4_table = {
. div_mult_table = & div4_div_mult_table ,
. kick = div4_kick ,
} ;
enum { DIV4_I , DIV4_ZG , DIV4_M3 , DIV4_B , DIV4_M1 , DIV4_M2 ,
DIV4_Z , DIV4_ZTR , DIV4_ZT , DIV4_ZX , DIV4_HP , DIV4_NR } ;
# define DIV4(_reg, _bit, _mask, _flags) \
SH_CLK_DIV4 ( & pll1_clk , _reg , _bit , _mask , _flags )
static struct clk div4_clks [ DIV4_NR ] = {
[ DIV4_I ] = DIV4 ( FRQCRA , 20 , 0xfff , CLK_ENABLE_ON_INIT ) ,
[ DIV4_ZG ] = DIV4 ( FRQCRA , 16 , 0xbff , CLK_ENABLE_ON_INIT ) ,
2011-01-18 11:53:06 +03:00
[ DIV4_M3 ] = DIV4 ( FRQCRA , 12 , 0xfff , CLK_ENABLE_ON_INIT ) ,
2010-12-03 10:22:31 +03:00
[ DIV4_B ] = DIV4 ( FRQCRA , 8 , 0xfff , CLK_ENABLE_ON_INIT ) ,
[ DIV4_M1 ] = DIV4 ( FRQCRA , 4 , 0xfff , 0 ) ,
[ DIV4_M2 ] = DIV4 ( FRQCRA , 0 , 0xfff , 0 ) ,
[ DIV4_Z ] = DIV4 ( FRQCRB , 24 , 0xbff , 0 ) ,
[ DIV4_ZTR ] = DIV4 ( FRQCRB , 20 , 0xfff , 0 ) ,
[ DIV4_ZT ] = DIV4 ( FRQCRB , 16 , 0xfff , 0 ) ,
[ DIV4_ZX ] = DIV4 ( FRQCRB , 12 , 0xfff , 0 ) ,
[ DIV4_HP ] = DIV4 ( FRQCRB , 4 , 0xfff , 0 ) ,
} ;
enum { DIV6_VCK1 , DIV6_VCK2 , DIV6_VCK3 , DIV6_ZB1 ,
DIV6_FLCTL , DIV6_SDHI0 , DIV6_SDHI1 , DIV6_SDHI2 ,
DIV6_FSIA , DIV6_FSIB , DIV6_SUB ,
DIV6_SPUA , DIV6_SPUV , DIV6_MSU ,
DIV6_HSI , DIV6_MFG1 , DIV6_MFG2 ,
DIV6_DSIT , DIV6_DSI0P , DIV6_DSI1P ,
DIV6_NR } ;
static struct clk div6_clks [ DIV6_NR ] = {
[ DIV6_VCK1 ] = SH_CLK_DIV6 ( & pll1_div2_clk , VCLKCR1 , 0 ) ,
[ DIV6_VCK2 ] = SH_CLK_DIV6 ( & pll1_div2_clk , VCLKCR2 , 0 ) ,
[ DIV6_VCK3 ] = SH_CLK_DIV6 ( & pll1_div2_clk , VCLKCR3 , 0 ) ,
[ DIV6_ZB1 ] = SH_CLK_DIV6 ( & pll1_div2_clk , ZBCKCR , 0 ) ,
[ DIV6_FLCTL ] = SH_CLK_DIV6 ( & pll1_div2_clk , FLCKCR , 0 ) ,
[ DIV6_SDHI0 ] = SH_CLK_DIV6 ( & pll1_div2_clk , SD0CKCR , 0 ) ,
[ DIV6_SDHI1 ] = SH_CLK_DIV6 ( & pll1_div2_clk , SD1CKCR , 0 ) ,
[ DIV6_SDHI2 ] = SH_CLK_DIV6 ( & pll1_div2_clk , SD2CKCR , 0 ) ,
[ DIV6_FSIA ] = SH_CLK_DIV6 ( & pll1_div2_clk , FSIACKCR , 0 ) ,
[ DIV6_FSIB ] = SH_CLK_DIV6 ( & pll1_div2_clk , FSIBCKCR , 0 ) ,
[ DIV6_SUB ] = SH_CLK_DIV6 ( & sh73a0_extal2_clk , SUBCKCR , 0 ) ,
[ DIV6_SPUA ] = SH_CLK_DIV6 ( & pll1_div2_clk , SPUACKCR , 0 ) ,
[ DIV6_SPUV ] = SH_CLK_DIV6 ( & pll1_div2_clk , SPUVCKCR , 0 ) ,
[ DIV6_MSU ] = SH_CLK_DIV6 ( & pll1_div2_clk , MSUCKCR , 0 ) ,
[ DIV6_HSI ] = SH_CLK_DIV6 ( & pll1_div2_clk , HSICKCR , 0 ) ,
[ DIV6_MFG1 ] = SH_CLK_DIV6 ( & pll1_div2_clk , MFCK1CR , 0 ) ,
[ DIV6_MFG2 ] = SH_CLK_DIV6 ( & pll1_div2_clk , MFCK2CR , 0 ) ,
[ DIV6_DSIT ] = SH_CLK_DIV6 ( & pll1_div2_clk , DSITCKCR , 0 ) ,
[ DIV6_DSI0P ] = SH_CLK_DIV6 ( & pll1_div2_clk , DSI0PCKCR , 0 ) ,
[ DIV6_DSI1P ] = SH_CLK_DIV6 ( & pll1_div2_clk , DSI1PCKCR , 0 ) ,
2010-11-17 13:59:31 +03:00
} ;
2010-12-03 10:22:31 +03:00
enum { MSTP001 ,
2010-12-21 11:40:59 +03:00
MSTP125 , MSTP116 ,
2010-12-03 10:22:31 +03:00
MSTP219 ,
MSTP207 , MSTP206 , MSTP204 , MSTP203 , MSTP202 , MSTP201 , MSTP200 ,
2011-01-14 14:00:41 +03:00
MSTP331 , MSTP329 , MSTP325 , MSTP323 , MSTP312 ,
2010-11-24 10:41:14 +03:00
MSTP411 , MSTP410 , MSTP403 ,
2010-11-17 13:59:31 +03:00
MSTP_NR } ;
# define MSTP(_parent, _reg, _bit, _flags) \
SH_CLK_MSTP32 ( _parent , _reg , _bit , _flags )
static struct clk mstp_clks [ MSTP_NR ] = {
2010-12-03 10:22:31 +03:00
[ MSTP001 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR0 , 1 , 0 ) , /* IIC2 */
2010-12-21 11:40:59 +03:00
[ MSTP125 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR1 , 25 , 0 ) , /* TMU0 */
2010-12-03 10:22:31 +03:00
[ MSTP116 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR1 , 16 , 0 ) , /* IIC0 */
[ MSTP219 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR2 , 19 , 0 ) , /* SCIFA7 */
[ MSTP207 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR2 , 7 , 0 ) , /* SCIFA5 */
[ MSTP206 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR2 , 6 , 0 ) , /* SCIFB */
[ MSTP204 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR2 , 4 , 0 ) , /* SCIFA0 */
[ MSTP203 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR2 , 3 , 0 ) , /* SCIFA1 */
[ MSTP202 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR2 , 2 , 0 ) , /* SCIFA2 */
[ MSTP201 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR2 , 1 , 0 ) , /* SCIFA3 */
[ MSTP200 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR2 , 0 , 0 ) , /* SCIFA4 */
[ MSTP331 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR3 , 31 , 0 ) , /* SCIFA6 */
2010-11-17 13:59:31 +03:00
[ MSTP329 ] = MSTP ( & r_clk , SMSTPCR3 , 29 , 0 ) , /* CMT10 */
2011-01-14 14:00:41 +03:00
[ MSTP325 ] = MSTP ( & div4_clks [ DIV6_SUB ] , SMSTPCR3 , 25 , 0 ) , /* IrDA */
2010-12-03 10:22:31 +03:00
[ MSTP323 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR3 , 23 , 0 ) , /* IIC1 */
2010-12-22 09:35:30 +03:00
[ MSTP312 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR3 , 12 , 0 ) , /* MMCIF0 */
2010-12-03 10:22:31 +03:00
[ MSTP411 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR4 , 11 , 0 ) , /* IIC3 */
[ MSTP410 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR4 , 10 , 0 ) , /* IIC4 */
2010-12-22 09:14:05 +03:00
[ MSTP403 ] = MSTP ( & r_clk , SMSTPCR4 , 3 , 0 ) , /* KEYSC */
2010-11-17 13:59:31 +03:00
} ;
2010-12-03 10:22:31 +03:00
# define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
2010-11-17 13:59:31 +03:00
# define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
static struct clk_lookup lookups [ ] = {
2010-12-03 10:22:31 +03:00
/* main clocks */
CLKDEV_CON_ID ( " r_clk " , & r_clk ) ,
2010-11-17 13:59:31 +03:00
/* MSTP32 clocks */
2010-11-24 10:41:14 +03:00
CLKDEV_DEV_ID ( " i2c-sh_mobile.2 " , & mstp_clks [ MSTP001 ] ) , /* I2C2 */
2010-12-21 11:40:59 +03:00
CLKDEV_DEV_ID ( " sh_tmu.0 " , & mstp_clks [ MSTP125 ] ) , /* TMU00 */
CLKDEV_DEV_ID ( " sh_tmu.1 " , & mstp_clks [ MSTP125 ] ) , /* TMU01 */
2010-11-24 10:41:14 +03:00
CLKDEV_DEV_ID ( " i2c-sh_mobile.0 " , & mstp_clks [ MSTP116 ] ) , /* I2C0 */
2010-11-17 13:59:31 +03:00
CLKDEV_DEV_ID ( " sh-sci.7 " , & mstp_clks [ MSTP219 ] ) , /* SCIFA7 */
CLKDEV_DEV_ID ( " sh-sci.5 " , & mstp_clks [ MSTP207 ] ) , /* SCIFA5 */
CLKDEV_DEV_ID ( " sh-sci.8 " , & mstp_clks [ MSTP206 ] ) , /* SCIFB */
CLKDEV_DEV_ID ( " sh-sci.0 " , & mstp_clks [ MSTP204 ] ) , /* SCIFA0 */
CLKDEV_DEV_ID ( " sh-sci.1 " , & mstp_clks [ MSTP203 ] ) , /* SCIFA1 */
CLKDEV_DEV_ID ( " sh-sci.2 " , & mstp_clks [ MSTP202 ] ) , /* SCIFA2 */
CLKDEV_DEV_ID ( " sh-sci.3 " , & mstp_clks [ MSTP201 ] ) , /* SCIFA3 */
CLKDEV_DEV_ID ( " sh-sci.4 " , & mstp_clks [ MSTP200 ] ) , /* SCIFA4 */
CLKDEV_DEV_ID ( " sh-sci.6 " , & mstp_clks [ MSTP331 ] ) , /* SCIFA6 */
CLKDEV_DEV_ID ( " sh_cmt.10 " , & mstp_clks [ MSTP329 ] ) , /* CMT10 */
2011-01-14 14:00:41 +03:00
CLKDEV_DEV_ID ( " sh_irda.0 " , & mstp_clks [ MSTP325 ] ) , /* IrDA */
2010-11-19 16:20:45 +03:00
CLKDEV_DEV_ID ( " i2c-sh_mobile.1 " , & mstp_clks [ MSTP323 ] ) , /* I2C1 */
2010-12-22 09:35:30 +03:00
CLKDEV_DEV_ID ( " sh_mmcif.0 " , & mstp_clks [ MSTP312 ] ) , /* MMCIF0 */
2010-11-19 16:20:45 +03:00
CLKDEV_DEV_ID ( " i2c-sh_mobile.3 " , & mstp_clks [ MSTP411 ] ) , /* I2C3 */
CLKDEV_DEV_ID ( " i2c-sh_mobile.4 " , & mstp_clks [ MSTP410 ] ) , /* I2C4 */
2010-12-22 09:14:05 +03:00
CLKDEV_DEV_ID ( " sh_keysc.0 " , & mstp_clks [ MSTP403 ] ) , /* KEYSC */
2010-11-17 13:59:31 +03:00
} ;
void __init sh73a0_clock_init ( void )
{
int k , ret = 0 ;
2010-12-03 10:22:31 +03:00
/* detect main clock parent */
switch ( ( __raw_readl ( CKSCR ) > > 24 ) & 0x03 ) {
case 0 :
main_clk . parent = & sh73a0_extal1_clk ;
break ;
case 1 :
main_clk . parent = & extal1_div2_clk ;
break ;
case 2 :
main_clk . parent = & sh73a0_extal2_clk ;
break ;
case 3 :
main_clk . parent = & extal2_div2_clk ;
break ;
}
2010-11-17 13:59:31 +03:00
for ( k = 0 ; ! ret & & ( k < ARRAY_SIZE ( main_clks ) ) ; k + + )
ret = clk_register ( main_clks [ k ] ) ;
2010-12-03 10:22:31 +03:00
if ( ! ret )
ret = sh_clk_div4_register ( div4_clks , DIV4_NR , & div4_table ) ;
if ( ! ret )
ret = sh_clk_div6_register ( div6_clks , DIV6_NR ) ;
2010-11-17 13:59:31 +03:00
if ( ! ret )
ret = sh_clk_mstp32_register ( mstp_clks , MSTP_NR ) ;
clkdev_add_table ( lookups , ARRAY_SIZE ( lookups ) ) ;
if ( ! ret )
clk_init ( ) ;
else
panic ( " failed to setup sh73a0 clocks \n " ) ;
}