2010-11-17 10:59:31 +00: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 11:49:49 +09:00
# include <linux/clkdev.h>
2013-02-28 13:21:58 +01:00
# include <asm/processor.h>
2013-03-27 00:56:14 -07:00
# include <mach/clock.h>
2010-11-17 10:59:31 +00:00
# include <mach/common.h>
2012-09-14 20:08:08 +00:00
# define FRQCRA IOMEM(0xe6150000)
# define FRQCRB IOMEM(0xe6150004)
# define FRQCRD IOMEM(0xe61500e4)
# define VCLKCR1 IOMEM(0xe6150008)
# define VCLKCR2 IOMEM(0xe615000C)
# define VCLKCR3 IOMEM(0xe615001C)
# define ZBCKCR IOMEM(0xe6150010)
# define FLCKCR IOMEM(0xe6150014)
# define SD0CKCR IOMEM(0xe6150074)
# define SD1CKCR IOMEM(0xe6150078)
# define SD2CKCR IOMEM(0xe615007C)
# define FSIACKCR IOMEM(0xe6150018)
# define FSIBCKCR IOMEM(0xe6150090)
# define SUBCKCR IOMEM(0xe6150080)
# define SPUACKCR IOMEM(0xe6150084)
# define SPUVCKCR IOMEM(0xe6150094)
# define MSUCKCR IOMEM(0xe6150088)
# define HSICKCR IOMEM(0xe615008C)
# define MFCK1CR IOMEM(0xe6150098)
# define MFCK2CR IOMEM(0xe615009C)
# define DSITCKCR IOMEM(0xe6150060)
# define DSI0PCKCR IOMEM(0xe6150064)
# define DSI1PCKCR IOMEM(0xe6150068)
2010-12-03 07:22:31 +00:00
# define DSI0PHYCR 0xe615006C
# define DSI1PHYCR 0xe6150070
2012-09-14 20:08:08 +00:00
# define PLLECR IOMEM(0xe61500d0)
# define PLL0CR IOMEM(0xe61500d8)
# define PLL1CR IOMEM(0xe6150028)
# define PLL2CR IOMEM(0xe615002c)
# define PLL3CR IOMEM(0xe61500dc)
# define SMSTPCR0 IOMEM(0xe6150130)
# define SMSTPCR1 IOMEM(0xe6150134)
# define SMSTPCR2 IOMEM(0xe6150138)
# define SMSTPCR3 IOMEM(0xe615013c)
# define SMSTPCR4 IOMEM(0xe6150140)
# define SMSTPCR5 IOMEM(0xe6150144)
# define CKSCR IOMEM(0xe61500c0)
2010-11-17 10:59:31 +00:00
/* Fixed 32 KHz root clock from EXTALR pin */
static struct clk r_clk = {
. rate = 32768 ,
} ;
2010-12-03 07:22:31 +00: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 ,
} ;
2012-02-29 22:16:52 +09:00
static struct sh_clk_ops main_clk_ops = {
2010-12-03 07:22:31 +00:00
. recalc = followparent_recalc ,
} ;
/* Main clock */
static struct clk main_clk = {
2013-03-27 00:56:14 -07:00
/* .parent wll be set on sh73a0_clock_init() */
2010-12-03 07:22:31 +00:00
. ops = & main_clk_ops ,
} ;
/* PLL0, PLL1, PLL2, PLL3 */
static unsigned long pll_recalc ( struct clk * clk )
{
unsigned long mult = 1 ;
2011-01-20 08:11:11 +00:00
if ( __raw_readl ( PLLECR ) & ( 1 < < clk - > enable_bit ) ) {
2010-12-03 07:22:31 +00:00
mult = ( ( ( __raw_readl ( clk - > enable_reg ) > > 24 ) & 0x3f ) + 1 ) ;
2011-01-20 08:11:11 +00:00
/* handle CFG bit for PLL1 and PLL2 */
switch ( clk - > enable_bit ) {
case 1 :
case 2 :
if ( __raw_readl ( clk - > enable_reg ) & ( 1 < < 20 ) )
mult * = 2 ;
}
}
2010-12-03 07:22:31 +00:00
return clk - > parent - > rate * mult ;
}
2012-02-29 22:16:52 +09:00
static struct sh_clk_ops pll_clk_ops = {
2010-12-03 07:22:31 +00:00
. 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 10:59:31 +00:00
} ;
2010-12-03 07:22:31 +00: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 ,
} ;
2013-03-27 00:56:14 -07:00
/* A fixed divide block */
SH_CLK_RATIO ( div2 , 1 , 2 ) ;
SH_CLK_RATIO ( div7 , 1 , 7 ) ;
SH_CLK_RATIO ( div13 , 1 , 13 ) ;
2011-12-05 22:29:15 -08:00
2013-03-27 00:56:14 -07:00
SH_FIXED_RATIO_CLK ( extal1_div2_clk , sh73a0_extal1_clk , div2 ) ;
SH_FIXED_RATIO_CLK ( extal2_div2_clk , sh73a0_extal2_clk , div2 ) ;
SH_FIXED_RATIO_CLK ( main_div2_clk , main_clk , div2 ) ;
SH_FIXED_RATIO_CLK ( pll1_div2_clk , pll1_clk , div2 ) ;
SH_FIXED_RATIO_CLK ( pll1_div7_clk , pll1_clk , div7 ) ;
SH_FIXED_RATIO_CLK ( pll1_div13_clk , pll1_clk , div13 ) ;
2011-12-05 22:29:15 -08:00
/* External input clock */
struct clk sh73a0_extcki_clk = {
} ;
struct clk sh73a0_extalr_clk = {
} ;
2010-11-17 10:59:31 +00:00
static struct clk * main_clks [ ] = {
& r_clk ,
2010-12-03 07:22:31 +00:00
& sh73a0_extal1_clk ,
& sh73a0_extal2_clk ,
& extal1_div2_clk ,
& extal2_div2_clk ,
& main_clk ,
2011-12-05 22:29:15 -08:00
& main_div2_clk ,
2010-12-03 07:22:31 +00:00
& pll0_clk ,
& pll1_clk ,
& pll2_clk ,
& pll3_clk ,
& pll1_div2_clk ,
2011-12-05 22:29:15 -08:00
& pll1_div7_clk ,
& pll1_div13_clk ,
& sh73a0_extcki_clk ,
& sh73a0_extalr_clk ,
2010-12-03 07:22:31 +00:00
} ;
2013-02-28 13:21:58 +01:00
static int frqcr_kick ( void )
2010-12-03 07:22:31 +00:00
{
2013-02-28 13:21:58 +01:00
int i ;
/* set KICK bit in FRQCRB to update hardware setting, check success */
__raw_writel ( __raw_readl ( FRQCRB ) | ( 1 < < 31 ) , FRQCRB ) ;
for ( i = 1000 ; i ; i - - )
if ( __raw_readl ( FRQCRB ) & ( 1 < < 31 ) )
cpu_relax ( ) ;
else
return i ;
return - ETIMEDOUT ;
}
2010-12-03 07:22:31 +00:00
2013-02-28 13:21:58 +01:00
static void div4_kick ( struct clk * clk )
{
frqcr_kick ( ) ;
2010-12-03 07:22:31 +00:00
}
static int divisors [ ] = { 2 , 3 , 4 , 6 , 8 , 12 , 16 , 18 ,
2010-12-22 14:15:08 +00:00
24 , 0 , 36 , 48 , 7 } ;
2010-12-03 07:22:31 +00: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 ,
2013-03-27 00:55:07 -07:00
DIV4_Z , DIV4_ZX , DIV4_HP , DIV4_NR } ;
2010-12-03 07:22:31 +00:00
# define DIV4(_reg, _bit, _mask, _flags) \
SH_CLK_DIV4 ( & pll1_clk , _reg , _bit , _mask , _flags )
static struct clk div4_clks [ DIV4_NR ] = {
2012-12-04 17:43:29 -08:00
[ DIV4_I ] = DIV4 ( FRQCRA , 20 , 0xdff , CLK_ENABLE_ON_INIT ) ,
2013-04-05 12:00:36 +02:00
/*
* ZG clock is dividing PLL0 frequency to supply SGX . Make sure not to
* exceed maximum frequencies of 201.5 MHz for VDD_DVFS = 1.175 and
* 239.2 MHz for VDD_DVFS = 1.315 V .
*/
2013-02-22 18:17:51 +01:00
[ DIV4_ZG ] = SH_CLK_DIV4 ( & pll0_clk , FRQCRA , 16 , 0xd7f , CLK_ENABLE_ON_INIT ) ,
2012-12-04 17:43:29 -08:00
[ DIV4_M3 ] = DIV4 ( FRQCRA , 12 , 0x1dff , CLK_ENABLE_ON_INIT ) ,
[ DIV4_B ] = DIV4 ( FRQCRA , 8 , 0xdff , CLK_ENABLE_ON_INIT ) ,
[ DIV4_M1 ] = DIV4 ( FRQCRA , 4 , 0x1dff , 0 ) ,
[ DIV4_M2 ] = DIV4 ( FRQCRA , 0 , 0x1dff , 0 ) ,
2013-02-22 18:17:51 +01:00
[ DIV4_Z ] = SH_CLK_DIV4 ( & pll0_clk , FRQCRB , 24 , 0x97f , 0 ) ,
2012-12-04 17:43:29 -08:00
[ DIV4_ZX ] = DIV4 ( FRQCRB , 12 , 0xdff , 0 ) ,
[ DIV4_HP ] = DIV4 ( FRQCRB , 4 , 0xdff , 0 ) ,
2010-12-03 07:22:31 +00:00
} ;
2013-03-07 20:00:48 +01:00
static unsigned long twd_recalc ( struct clk * clk )
{
return clk_get_rate ( clk - > parent ) / 4 ;
}
static struct sh_clk_ops twd_clk_ops = {
. recalc = twd_recalc ,
} ;
static struct clk twd_clk = {
. parent = & div4_clks [ DIV4_Z ] ,
. ops = & twd_clk_ops ,
} ;
2013-05-23 00:10:00 +02:00
static struct sh_clk_ops zclk_ops , kicker_ops ;
2013-05-23 00:09:36 +02:00
static const struct sh_clk_ops * div4_clk_ops ;
2013-04-05 12:00:36 +02:00
static int zclk_set_rate ( struct clk * clk , unsigned long rate )
{
int ret ;
if ( ! clk - > parent | | ! __clk_get ( clk - > parent ) )
return - ENODEV ;
if ( readl ( FRQCRB ) & ( 1 < < 31 ) )
return - EBUSY ;
if ( rate = = clk_get_rate ( clk - > parent ) ) {
/* 1:1 - switch off divider */
__raw_writel ( __raw_readl ( FRQCRB ) & ~ ( 1 < < 28 ) , FRQCRB ) ;
/* nullify the divider to prepare for the next time */
2013-05-23 00:09:36 +02:00
ret = div4_clk_ops - > set_rate ( clk , rate / 2 ) ;
2013-04-05 12:00:36 +02:00
if ( ! ret )
ret = frqcr_kick ( ) ;
if ( ret > 0 )
ret = 0 ;
} else {
/* Enable the divider */
__raw_writel ( __raw_readl ( FRQCRB ) | ( 1 < < 28 ) , FRQCRB ) ;
ret = frqcr_kick ( ) ;
if ( ret > = 0 )
/*
* set the divider - call the DIV4 method , it will kick
* FRQCRB too
*/
2013-05-23 00:09:36 +02:00
ret = div4_clk_ops - > set_rate ( clk , rate ) ;
2013-04-05 12:00:36 +02:00
if ( ret < 0 )
goto esetrate ;
}
esetrate :
__clk_put ( clk - > parent ) ;
return ret ;
}
static long zclk_round_rate ( struct clk * clk , unsigned long rate )
{
2013-05-23 00:09:36 +02:00
unsigned long div_freq = div4_clk_ops - > round_rate ( clk , rate ) ,
2013-04-05 12:00:36 +02:00
parent_freq = clk_get_rate ( clk - > parent ) ;
if ( rate > div_freq & & abs ( parent_freq - rate ) < rate - div_freq )
return parent_freq ;
return div_freq ;
}
static unsigned long zclk_recalc ( struct clk * clk )
{
/*
* Must recalculate frequencies in case PLL0 has been changed , even if
* the divisor is unused ATM !
*/
2013-05-23 00:09:36 +02:00
unsigned long div_freq = div4_clk_ops - > recalc ( clk ) ;
2013-04-05 12:00:36 +02:00
if ( __raw_readl ( FRQCRB ) & ( 1 < < 28 ) )
return div_freq ;
return clk_get_rate ( clk - > parent ) ;
}
2013-05-23 00:10:00 +02:00
static int kicker_set_rate ( struct clk * clk , unsigned long rate )
2013-04-05 12:00:36 +02:00
{
2013-05-23 00:10:00 +02:00
if ( __raw_readl ( FRQCRB ) & ( 1 < < 31 ) )
return - EBUSY ;
return div4_clk_ops - > set_rate ( clk , rate ) ;
}
static void div4_clk_extend ( void )
{
int i ;
div4_clk_ops = div4_clks [ 0 ] . ops ;
2013-05-23 00:09:36 +02:00
2013-05-23 00:10:00 +02:00
/* Add a kicker-busy check before changing the rate */
kicker_ops = * div4_clk_ops ;
2013-04-05 12:00:36 +02:00
/* We extend the DIV4 clock with a 1:1 pass-through case */
2013-05-23 00:09:36 +02:00
zclk_ops = * div4_clk_ops ;
2013-05-23 00:10:00 +02:00
kicker_ops . set_rate = kicker_set_rate ;
2013-05-23 00:09:36 +02:00
zclk_ops . set_rate = zclk_set_rate ;
zclk_ops . round_rate = zclk_round_rate ;
zclk_ops . recalc = zclk_recalc ;
2013-05-23 00:10:00 +02:00
for ( i = 0 ; i < DIV4_NR ; i + + )
div4_clks [ i ] . ops = i = = DIV4_Z ? & zclk_ops : & kicker_ops ;
2013-04-05 12:00:36 +02:00
}
2010-12-03 07:22:31 +00:00
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 } ;
2011-12-05 22:29:15 -08:00
static struct clk * vck_parent [ 8 ] = {
[ 0 ] = & pll1_div2_clk ,
[ 1 ] = & pll2_clk ,
[ 2 ] = & sh73a0_extcki_clk ,
[ 3 ] = & sh73a0_extal2_clk ,
[ 4 ] = & main_div2_clk ,
[ 5 ] = & sh73a0_extalr_clk ,
[ 6 ] = & main_clk ,
} ;
static struct clk * pll_parent [ 4 ] = {
[ 0 ] = & pll1_div2_clk ,
[ 1 ] = & pll2_clk ,
[ 2 ] = & pll1_div13_clk ,
} ;
static struct clk * hsi_parent [ 4 ] = {
[ 0 ] = & pll1_div2_clk ,
[ 1 ] = & pll2_clk ,
[ 2 ] = & pll1_div7_clk ,
} ;
static struct clk * pll_extal2_parent [ ] = {
[ 0 ] = & pll1_div2_clk ,
[ 1 ] = & pll2_clk ,
[ 2 ] = & sh73a0_extal2_clk ,
[ 3 ] = & sh73a0_extal2_clk ,
} ;
static struct clk * dsi_parent [ 8 ] = {
[ 0 ] = & pll1_div2_clk ,
[ 1 ] = & pll2_clk ,
[ 2 ] = & main_clk ,
[ 3 ] = & sh73a0_extal2_clk ,
[ 4 ] = & sh73a0_extcki_clk ,
} ;
2010-12-03 07:22:31 +00:00
static struct clk div6_clks [ DIV6_NR ] = {
2011-12-05 22:29:15 -08:00
[ DIV6_VCK1 ] = SH_CLK_DIV6_EXT ( VCLKCR1 , 0 ,
vck_parent , ARRAY_SIZE ( vck_parent ) , 12 , 3 ) ,
[ DIV6_VCK2 ] = SH_CLK_DIV6_EXT ( VCLKCR2 , 0 ,
vck_parent , ARRAY_SIZE ( vck_parent ) , 12 , 3 ) ,
[ DIV6_VCK3 ] = SH_CLK_DIV6_EXT ( VCLKCR3 , 0 ,
vck_parent , ARRAY_SIZE ( vck_parent ) , 12 , 3 ) ,
2012-01-09 11:12:55 +09:00
[ DIV6_ZB1 ] = SH_CLK_DIV6_EXT ( ZBCKCR , CLK_ENABLE_ON_INIT ,
2011-12-05 22:29:15 -08:00
pll_parent , ARRAY_SIZE ( pll_parent ) , 7 , 1 ) ,
[ DIV6_FLCTL ] = SH_CLK_DIV6_EXT ( FLCKCR , 0 ,
pll_parent , ARRAY_SIZE ( pll_parent ) , 7 , 1 ) ,
[ DIV6_SDHI0 ] = SH_CLK_DIV6_EXT ( SD0CKCR , 0 ,
pll_parent , ARRAY_SIZE ( pll_parent ) , 6 , 2 ) ,
[ DIV6_SDHI1 ] = SH_CLK_DIV6_EXT ( SD1CKCR , 0 ,
pll_parent , ARRAY_SIZE ( pll_parent ) , 6 , 2 ) ,
[ DIV6_SDHI2 ] = SH_CLK_DIV6_EXT ( SD2CKCR , 0 ,
pll_parent , ARRAY_SIZE ( pll_parent ) , 6 , 2 ) ,
[ DIV6_FSIA ] = SH_CLK_DIV6_EXT ( FSIACKCR , 0 ,
pll_parent , ARRAY_SIZE ( pll_parent ) , 6 , 1 ) ,
[ DIV6_FSIB ] = SH_CLK_DIV6_EXT ( FSIBCKCR , 0 ,
pll_parent , ARRAY_SIZE ( pll_parent ) , 6 , 1 ) ,
[ DIV6_SUB ] = SH_CLK_DIV6_EXT ( SUBCKCR , 0 ,
pll_extal2_parent , ARRAY_SIZE ( pll_extal2_parent ) , 6 , 2 ) ,
[ DIV6_SPUA ] = SH_CLK_DIV6_EXT ( SPUACKCR , 0 ,
pll_extal2_parent , ARRAY_SIZE ( pll_extal2_parent ) , 6 , 2 ) ,
[ DIV6_SPUV ] = SH_CLK_DIV6_EXT ( SPUVCKCR , 0 ,
pll_extal2_parent , ARRAY_SIZE ( pll_extal2_parent ) , 6 , 2 ) ,
[ DIV6_MSU ] = SH_CLK_DIV6_EXT ( MSUCKCR , 0 ,
pll_parent , ARRAY_SIZE ( pll_parent ) , 7 , 1 ) ,
[ DIV6_HSI ] = SH_CLK_DIV6_EXT ( HSICKCR , 0 ,
hsi_parent , ARRAY_SIZE ( hsi_parent ) , 6 , 2 ) ,
[ DIV6_MFG1 ] = SH_CLK_DIV6_EXT ( MFCK1CR , 0 ,
pll_parent , ARRAY_SIZE ( pll_parent ) , 7 , 1 ) ,
[ DIV6_MFG2 ] = SH_CLK_DIV6_EXT ( MFCK2CR , 0 ,
pll_parent , ARRAY_SIZE ( pll_parent ) , 7 , 1 ) ,
[ DIV6_DSIT ] = SH_CLK_DIV6_EXT ( DSITCKCR , 0 ,
pll_parent , ARRAY_SIZE ( pll_parent ) , 7 , 1 ) ,
[ DIV6_DSI0P ] = SH_CLK_DIV6_EXT ( DSI0PCKCR , 0 ,
dsi_parent , ARRAY_SIZE ( dsi_parent ) , 12 , 3 ) ,
[ DIV6_DSI1P ] = SH_CLK_DIV6_EXT ( DSI1PCKCR , 0 ,
dsi_parent , ARRAY_SIZE ( dsi_parent ) , 12 , 3 ) ,
2010-11-17 10:59:31 +00:00
} ;
2012-01-22 21:10:02 -08:00
/* DSI DIV */
static unsigned long dsiphy_recalc ( struct clk * clk )
{
u32 value ;
value = __raw_readl ( clk - > mapping - > base ) ;
/* FIXME */
if ( ! ( value & 0x000B8000 ) )
return clk - > parent - > rate ;
value & = 0x3f ;
value + = 1 ;
if ( ( value < 12 ) | |
( value > 33 ) ) {
pr_err ( " DSIPHY has wrong value (%d) " , value ) ;
return 0 ;
}
return clk - > parent - > rate / value ;
}
static long dsiphy_round_rate ( struct clk * clk , unsigned long rate )
{
return clk_rate_mult_range_round ( clk , 12 , 33 , rate ) ;
}
static void dsiphy_disable ( struct clk * clk )
{
u32 value ;
value = __raw_readl ( clk - > mapping - > base ) ;
value & = ~ 0x000B8000 ;
__raw_writel ( value , clk - > mapping - > base ) ;
}
static int dsiphy_enable ( struct clk * clk )
{
u32 value ;
int multi ;
value = __raw_readl ( clk - > mapping - > base ) ;
multi = ( value & 0x3f ) + 1 ;
if ( ( multi < 12 ) | | ( multi > 33 ) )
return - EIO ;
__raw_writel ( value | 0x000B8000 , clk - > mapping - > base ) ;
return 0 ;
}
static int dsiphy_set_rate ( struct clk * clk , unsigned long rate )
{
u32 value ;
int idx ;
idx = rate / clk - > parent - > rate ;
if ( ( idx < 12 ) | | ( idx > 33 ) )
return - EINVAL ;
idx + = - 1 ;
value = __raw_readl ( clk - > mapping - > base ) ;
value = ( value & ~ 0x3f ) + idx ;
__raw_writel ( value , clk - > mapping - > base ) ;
return 0 ;
}
2012-02-29 22:16:52 +09:00
static struct sh_clk_ops dsiphy_clk_ops = {
2012-01-22 21:10:02 -08:00
. recalc = dsiphy_recalc ,
. round_rate = dsiphy_round_rate ,
. set_rate = dsiphy_set_rate ,
. enable = dsiphy_enable ,
. disable = dsiphy_disable ,
} ;
static struct clk_mapping dsi0phy_clk_mapping = {
. phys = DSI0PHYCR ,
. len = 4 ,
} ;
static struct clk_mapping dsi1phy_clk_mapping = {
. phys = DSI1PHYCR ,
. len = 4 ,
} ;
static struct clk dsi0phy_clk = {
. ops = & dsiphy_clk_ops ,
. parent = & div6_clks [ DIV6_DSI0P ] , /* late install */
. mapping = & dsi0phy_clk_mapping ,
} ;
static struct clk dsi1phy_clk = {
. ops = & dsiphy_clk_ops ,
. parent = & div6_clks [ DIV6_DSI1P ] , /* late install */
. mapping = & dsi1phy_clk_mapping ,
} ;
static struct clk * late_main_clks [ ] = {
& dsi0phy_clk ,
& dsi1phy_clk ,
2013-03-07 20:00:48 +01:00
& twd_clk ,
2012-01-22 21:10:02 -08:00
} ;
2010-12-03 07:22:31 +00:00
enum { MSTP001 ,
2013-04-05 12:00:36 +02:00
MSTP129 , MSTP128 , MSTP127 , MSTP126 , MSTP125 , MSTP118 , MSTP116 , MSTP112 , MSTP100 ,
2012-06-25 03:39:20 -07:00
MSTP219 , MSTP218 , MSTP217 ,
2010-12-03 07:22:31 +00:00
MSTP207 , MSTP206 , MSTP204 , MSTP203 , MSTP202 , MSTP201 , MSTP200 ,
2012-06-25 03:34:49 -07:00
MSTP331 , MSTP329 , MSTP328 , MSTP325 , MSTP323 , MSTP322 ,
2011-05-24 10:37:16 +00:00
MSTP314 , MSTP313 , MSTP312 , MSTP311 ,
2013-07-16 12:32:06 +02:00
MSTP304 , MSTP303 , MSTP302 , MSTP301 , MSTP300 ,
2010-11-24 07:41:14 +00:00
MSTP411 , MSTP410 , MSTP403 ,
2010-11-17 10:59:31 +00: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 07:22:31 +00:00
[ MSTP001 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR0 , 1 , 0 ) , /* IIC2 */
2011-01-28 10:04:25 +00:00
[ MSTP129 ] = MSTP ( & div4_clks [ DIV4_B ] , SMSTPCR1 , 29 , 0 ) , /* CEU1 */
[ MSTP128 ] = MSTP ( & div4_clks [ DIV4_B ] , SMSTPCR1 , 28 , 0 ) , /* CSI2-RX1 */
[ MSTP127 ] = MSTP ( & div4_clks [ DIV4_B ] , SMSTPCR1 , 27 , 0 ) , /* CEU0 */
[ MSTP126 ] = MSTP ( & div4_clks [ DIV4_B ] , SMSTPCR1 , 26 , 0 ) , /* CSI2-RX0 */
2010-12-21 08:40:59 +00:00
[ MSTP125 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR1 , 25 , 0 ) , /* TMU0 */
2011-01-20 08:41:03 +00:00
[ MSTP118 ] = MSTP ( & div4_clks [ DIV4_B ] , SMSTPCR1 , 18 , 0 ) , /* DSITX0 */
2010-12-03 07:22:31 +00:00
[ MSTP116 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR1 , 16 , 0 ) , /* IIC0 */
2013-04-05 12:00:36 +02:00
[ MSTP112 ] = MSTP ( & div4_clks [ DIV4_ZG ] , SMSTPCR1 , 12 , 0 ) , /* SGX */
2011-01-20 08:41:03 +00:00
[ MSTP100 ] = MSTP ( & div4_clks [ DIV4_B ] , SMSTPCR1 , 0 , 0 ) , /* LCDC0 */
2010-12-03 07:22:31 +00:00
[ MSTP219 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR2 , 19 , 0 ) , /* SCIFA7 */
2012-06-20 11:30:25 +02:00
[ MSTP218 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR2 , 18 , 0 ) , /* SY-DMAC */
2012-06-25 03:39:20 -07:00
[ MSTP217 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR2 , 17 , 0 ) , /* MP-DMAC */
2010-12-03 07:22:31 +00:00
[ 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 10:59:31 +00:00
[ MSTP329 ] = MSTP ( & r_clk , SMSTPCR3 , 29 , 0 ) , /* CMT10 */
2012-06-12 02:43:40 -07:00
[ MSTP328 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR3 , 28 , 0 ) , /*FSI*/
2011-01-18 08:48:17 +00:00
[ MSTP325 ] = MSTP ( & div6_clks [ DIV6_SUB ] , SMSTPCR3 , 25 , 0 ) , /* IrDA */
2010-12-03 07:22:31 +00:00
[ MSTP323 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR3 , 23 , 0 ) , /* IIC1 */
2012-06-25 03:34:49 -07:00
[ MSTP322 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR3 , 22 , 0 ) , /* USB */
2011-05-23 05:10:36 +00:00
[ MSTP314 ] = MSTP ( & div6_clks [ DIV6_SDHI0 ] , SMSTPCR3 , 14 , 0 ) , /* SDHI0 */
[ MSTP313 ] = MSTP ( & div6_clks [ DIV6_SDHI1 ] , SMSTPCR3 , 13 , 0 ) , /* SDHI1 */
2010-12-22 06:35:30 +00:00
[ MSTP312 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR3 , 12 , 0 ) , /* MMCIF0 */
2011-05-23 05:10:36 +00:00
[ MSTP311 ] = MSTP ( & div6_clks [ DIV6_SDHI2 ] , SMSTPCR3 , 11 , 0 ) , /* SDHI2 */
2013-07-16 12:32:06 +02:00
[ MSTP304 ] = MSTP ( & main_div2_clk , SMSTPCR3 , 4 , 0 ) , /* TPU0 */
2011-11-22 15:44:58 +09:00
[ MSTP303 ] = MSTP ( & main_div2_clk , SMSTPCR3 , 3 , 0 ) , /* TPU1 */
[ MSTP302 ] = MSTP ( & main_div2_clk , SMSTPCR3 , 2 , 0 ) , /* TPU2 */
[ MSTP301 ] = MSTP ( & main_div2_clk , SMSTPCR3 , 1 , 0 ) , /* TPU3 */
[ MSTP300 ] = MSTP ( & main_div2_clk , SMSTPCR3 , 0 , 0 ) , /* TPU4 */
2010-12-03 07:22:31 +00:00
[ MSTP411 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR4 , 11 , 0 ) , /* IIC3 */
[ MSTP410 ] = MSTP ( & div4_clks [ DIV4_HP ] , SMSTPCR4 , 10 , 0 ) , /* IIC4 */
2010-12-22 06:14:05 +00:00
[ MSTP403 ] = MSTP ( & r_clk , SMSTPCR4 , 3 , 0 ) , /* KEYSC */
2010-11-17 10:59:31 +00:00
} ;
2012-11-21 22:00:15 +09:00
/* The lookups structure below includes duplicate entries for some clocks
* with alternate names .
* - The traditional name used when a device is initialised with platform data
* - The name used when a device is initialised using device tree
* The longer - term aim is to remove these duplicates , and indeed the
* lookups table entirely , by describing clocks using device tree .
*/
2010-11-17 10:59:31 +00:00
static struct clk_lookup lookups [ ] = {
2010-12-03 07:22:31 +00:00
/* main clocks */
CLKDEV_CON_ID ( " r_clk " , & r_clk ) ,
2013-03-07 20:00:48 +01:00
CLKDEV_DEV_ID ( " smp_twd " , & twd_clk ) , /* smp_twd */
2010-12-03 07:22:31 +00:00
2013-04-05 12:00:36 +02:00
/* DIV4 clocks */
2013-09-10 18:59:49 +01:00
CLKDEV_DEV_ID ( " cpu0 " , & div4_clks [ DIV4_Z ] ) ,
2013-04-05 12:00:36 +02:00
2011-01-20 08:41:03 +00:00
/* DIV6 clocks */
2011-01-28 10:04:25 +00:00
CLKDEV_CON_ID ( " vck1_clk " , & div6_clks [ DIV6_VCK1 ] ) ,
CLKDEV_CON_ID ( " vck2_clk " , & div6_clks [ DIV6_VCK2 ] ) ,
CLKDEV_CON_ID ( " vck3_clk " , & div6_clks [ DIV6_VCK3 ] ) ,
2011-05-23 05:10:36 +00:00
CLKDEV_CON_ID ( " sdhi0_clk " , & div6_clks [ DIV6_SDHI0 ] ) ,
CLKDEV_CON_ID ( " sdhi1_clk " , & div6_clks [ DIV6_SDHI1 ] ) ,
CLKDEV_CON_ID ( " sdhi2_clk " , & div6_clks [ DIV6_SDHI2 ] ) ,
2011-01-20 08:41:03 +00:00
CLKDEV_ICK_ID ( " dsit_clk " , " sh-mipi-dsi.0 " , & div6_clks [ DIV6_DSIT ] ) ,
CLKDEV_ICK_ID ( " dsit_clk " , " sh-mipi-dsi.1 " , & div6_clks [ DIV6_DSIT ] ) ,
2011-11-08 20:33:47 -08:00
CLKDEV_ICK_ID ( " dsip_clk " , " sh-mipi-dsi.0 " , & div6_clks [ DIV6_DSI0P ] ) ,
CLKDEV_ICK_ID ( " dsip_clk " , " sh-mipi-dsi.1 " , & div6_clks [ DIV6_DSI1P ] ) ,
2012-01-22 21:10:02 -08:00
CLKDEV_ICK_ID ( " dsiphy_clk " , " sh-mipi-dsi.0 " , & dsi0phy_clk ) ,
CLKDEV_ICK_ID ( " dsiphy_clk " , " sh-mipi-dsi.1 " , & dsi1phy_clk ) ,
2011-01-20 08:41:03 +00:00
2010-11-17 10:59:31 +00:00
/* MSTP32 clocks */
2010-11-24 07:41:14 +00:00
CLKDEV_DEV_ID ( " i2c-sh_mobile.2 " , & mstp_clks [ MSTP001 ] ) , /* I2C2 */
2012-11-21 22:00:15 +09:00
CLKDEV_DEV_ID ( " e6824000.i2c " , & mstp_clks [ MSTP001 ] ) , /* I2C2 */
2011-01-28 10:04:25 +00:00
CLKDEV_DEV_ID ( " sh_mobile_ceu.1 " , & mstp_clks [ MSTP129 ] ) , /* CEU1 */
CLKDEV_DEV_ID ( " sh-mobile-csi2.1 " , & mstp_clks [ MSTP128 ] ) , /* CSI2-RX1 */
CLKDEV_DEV_ID ( " sh_mobile_ceu.0 " , & mstp_clks [ MSTP127 ] ) , /* CEU0 */
CLKDEV_DEV_ID ( " sh-mobile-csi2.0 " , & mstp_clks [ MSTP126 ] ) , /* CSI2-RX0 */
2010-12-21 08:40:59 +00:00
CLKDEV_DEV_ID ( " sh_tmu.0 " , & mstp_clks [ MSTP125 ] ) , /* TMU00 */
CLKDEV_DEV_ID ( " sh_tmu.1 " , & mstp_clks [ MSTP125 ] ) , /* TMU01 */
2011-01-20 08:41:03 +00:00
CLKDEV_DEV_ID ( " sh-mipi-dsi.0 " , & mstp_clks [ MSTP118 ] ) , /* DSITX */
2011-01-28 10:04:25 +00:00
CLKDEV_DEV_ID ( " i2c-sh_mobile.0 " , & mstp_clks [ MSTP116 ] ) , /* I2C0 */
2012-11-21 22:00:15 +09:00
CLKDEV_DEV_ID ( " e6820000.i2c " , & mstp_clks [ MSTP116 ] ) , /* I2C0 */
2011-01-28 10:04:25 +00:00
CLKDEV_DEV_ID ( " sh_mobile_lcdc_fb.0 " , & mstp_clks [ MSTP100 ] ) , /* LCDC0 */
2010-11-17 10:59:31 +00:00
CLKDEV_DEV_ID ( " sh-sci.7 " , & mstp_clks [ MSTP219 ] ) , /* SCIFA7 */
2012-06-20 11:30:25 +02:00
CLKDEV_DEV_ID ( " sh-dma-engine.0 " , & mstp_clks [ MSTP218 ] ) , /* SY-DMAC */
2012-06-25 03:39:20 -07:00
CLKDEV_DEV_ID ( " sh-dma-engine.1 " , & mstp_clks [ MSTP217 ] ) , /* MP-DMAC */
2010-11-17 10:59:31 +00:00
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 */
2012-06-12 02:43:40 -07:00
CLKDEV_DEV_ID ( " sh_fsi2 " , & mstp_clks [ MSTP328 ] ) , /* FSI */
2011-01-14 11:00:41 +00:00
CLKDEV_DEV_ID ( " sh_irda.0 " , & mstp_clks [ MSTP325 ] ) , /* IrDA */
2010-11-19 13:20:45 +00:00
CLKDEV_DEV_ID ( " i2c-sh_mobile.1 " , & mstp_clks [ MSTP323 ] ) , /* I2C1 */
2012-11-21 22:00:15 +09:00
CLKDEV_DEV_ID ( " e6822000.i2c " , & mstp_clks [ MSTP323 ] ) , /* I2C1 */
2012-06-25 03:34:49 -07:00
CLKDEV_DEV_ID ( " renesas_usbhs " , & mstp_clks [ MSTP322 ] ) , /* USB */
2011-05-23 05:10:36 +00:00
CLKDEV_DEV_ID ( " sh_mobile_sdhi.0 " , & mstp_clks [ MSTP314 ] ) , /* SDHI0 */
2013-10-21 19:36:22 -07:00
CLKDEV_DEV_ID ( " ee100000.sd " , & mstp_clks [ MSTP314 ] ) , /* SDHI0 */
2011-05-23 05:10:36 +00:00
CLKDEV_DEV_ID ( " sh_mobile_sdhi.1 " , & mstp_clks [ MSTP313 ] ) , /* SDHI1 */
2013-10-21 19:36:22 -07:00
CLKDEV_DEV_ID ( " ee120000.sd " , & mstp_clks [ MSTP313 ] ) , /* SDHI1 */
2010-12-22 06:35:30 +00:00
CLKDEV_DEV_ID ( " sh_mmcif.0 " , & mstp_clks [ MSTP312 ] ) , /* MMCIF0 */
2013-10-21 19:36:22 -07:00
CLKDEV_DEV_ID ( " e6bd0000.mmc " , & mstp_clks [ MSTP312 ] ) , /* MMCIF0 */
2011-05-23 05:10:36 +00:00
CLKDEV_DEV_ID ( " sh_mobile_sdhi.2 " , & mstp_clks [ MSTP311 ] ) , /* SDHI2 */
2013-10-21 19:36:22 -07:00
CLKDEV_DEV_ID ( " ee140000.sd " , & mstp_clks [ MSTP311 ] ) , /* SDHI2 */
2013-07-16 12:32:06 +02:00
CLKDEV_DEV_ID ( " renesas-tpu-pwm.0 " , & mstp_clks [ MSTP304 ] ) , /* TPU0 */
CLKDEV_DEV_ID ( " renesas-tpu-pwm.1 " , & mstp_clks [ MSTP303 ] ) , /* TPU1 */
CLKDEV_DEV_ID ( " renesas-tpu-pwm.2 " , & mstp_clks [ MSTP302 ] ) , /* TPU2 */
CLKDEV_DEV_ID ( " renesas-tpu-pwm.3 " , & mstp_clks [ MSTP301 ] ) , /* TPU3 */
CLKDEV_DEV_ID ( " renesas-tpu-pwm.4 " , & mstp_clks [ MSTP300 ] ) , /* TPU4 */
2010-11-19 13:20:45 +00:00
CLKDEV_DEV_ID ( " i2c-sh_mobile.3 " , & mstp_clks [ MSTP411 ] ) , /* I2C3 */
2012-11-21 22:00:15 +09:00
CLKDEV_DEV_ID ( " e6826000.i2c " , & mstp_clks [ MSTP411 ] ) , /* I2C3 */
2010-11-19 13:20:45 +00:00
CLKDEV_DEV_ID ( " i2c-sh_mobile.4 " , & mstp_clks [ MSTP410 ] ) , /* I2C4 */
2012-11-21 22:00:15 +09:00
CLKDEV_DEV_ID ( " e6828000.i2c " , & mstp_clks [ MSTP410 ] ) , /* I2C4 */
2010-12-22 06:14:05 +00:00
CLKDEV_DEV_ID ( " sh_keysc.0 " , & mstp_clks [ MSTP403 ] ) , /* KEYSC */
2010-11-17 10:59:31 +00:00
} ;
void __init sh73a0_clock_init ( void )
{
int k , ret = 0 ;
2011-05-23 05:10:36 +00:00
/* Set SDHI clocks to a known state */
__raw_writel ( 0x108 , SD0CKCR ) ;
__raw_writel ( 0x108 , SD1CKCR ) ;
__raw_writel ( 0x108 , SD2CKCR ) ;
2010-12-03 07:22:31 +00:00
/* detect main clock parent */
2011-08-26 07:27:45 +00:00
switch ( ( __raw_readl ( CKSCR ) > > 28 ) & 0x03 ) {
2010-12-03 07:22:31 +00:00
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 10:59:31 +00:00
for ( k = 0 ; ! ret & & ( k < ARRAY_SIZE ( main_clks ) ) ; k + + )
ret = clk_register ( main_clks [ k ] ) ;
2013-04-05 12:00:36 +02:00
if ( ! ret ) {
2010-12-03 07:22:31 +00:00
ret = sh_clk_div4_register ( div4_clks , DIV4_NR , & div4_table ) ;
2013-04-05 12:00:36 +02:00
if ( ! ret )
2013-05-23 00:10:00 +02:00
div4_clk_extend ( ) ;
2013-04-05 12:00:36 +02:00
}
2010-12-03 07:22:31 +00:00
if ( ! ret )
2011-12-05 22:29:15 -08:00
ret = sh_clk_div6_reparent_register ( div6_clks , DIV6_NR ) ;
2010-12-03 07:22:31 +00:00
2010-11-17 10:59:31 +00:00
if ( ! ret )
2012-06-27 09:59:00 +09:00
ret = sh_clk_mstp_register ( mstp_clks , MSTP_NR ) ;
2010-11-17 10:59:31 +00:00
2012-01-22 21:10:02 -08:00
for ( k = 0 ; ! ret & & ( k < ARRAY_SIZE ( late_main_clks ) ) ; k + + )
ret = clk_register ( late_main_clks [ k ] ) ;
2010-11-17 10:59:31 +00:00
clkdev_add_table ( lookups , ARRAY_SIZE ( lookups ) ) ;
if ( ! ret )
2012-02-29 21:41:30 +09:00
shmobile_clk_init ( ) ;
2010-11-17 10:59:31 +00:00
else
panic ( " failed to setup sh73a0 clocks \n " ) ;
}