2009-04-23 10:21:30 +01:00
/*
*
* arch / arm / mach - u300 / clock . c
*
*
* Copyright ( C ) 2007 - 2009 ST - Ericsson AB
* License terms : GNU General Public License ( GPL ) version 2
* Define clocks in the app platform .
* Author : Linus Walleij < linus . walleij @ stericsson . com >
* Author : Jonas Aaberg < jonas . aberg @ stericsson . com >
*
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/errno.h>
# include <linux/err.h>
# include <linux/string.h>
# include <linux/clk.h>
# include <linux/mutex.h>
# include <linux/spinlock.h>
# include <linux/debugfs.h>
# include <linux/device.h>
# include <linux/init.h>
# include <linux/timer.h>
# include <linux/io.h>
2009-07-02 00:27:57 +01:00
# include <linux/seq_file.h>
2010-11-17 10:04:33 +01:00
# include <linux/clkdev.h>
2009-04-23 10:21:30 +01:00
# include <mach/hardware.h>
# include <mach/syscon.h>
# include "clock.h"
/*
* TODO :
* - move all handling of the CCR register into this file and create
* a spinlock for the CCR register
* - switch to the clkdevice lookup mechanism that maps clocks to
* device ID : s instead when it becomes available in kernel 2.6 .29 .
* - implement rate get / set for all clocks that need it .
*/
/*
* Syscon clock I / O registers lock so clock requests don ' t collide
* NOTE : this is a local lock only used to lock access to clock and
* reset registers in syscon .
*/
static DEFINE_SPINLOCK ( syscon_clkreg_lock ) ;
static DEFINE_SPINLOCK ( syscon_resetreg_lock ) ;
/*
* The clocking hierarchy currently looks like this .
* NOTE : the idea is NOT to show how the clocks are routed on the chip !
* The ideas is to show dependencies , so a clock higher up in the
* hierarchy has to be on in order for another clock to be on . Now ,
* both CPU and DMA can actually be on top of the hierarchy , and that
* is not modeled currently . Instead we have the backbone AMBA bus on
* top . This bus cannot be programmed in any way but conceptually it
* needs to be active for the bridges and devices to transport data .
*
* Please be aware that a few clocks are hw controlled , which mean that
* the hw itself can turn on / off or change the rate of the clock when
* needed !
*
* AMBA bus
* |
* + - CPU
2010-09-13 00:35:37 +02:00
* + - FSMC NANDIF NAND Flash interface
2009-04-23 10:21:30 +01:00
* + - SEMI Shared Memory interface
* + - ISP Image Signal Processor ( U335 only )
* + - CDS ( U335 only )
* + - DMA Direct Memory Access Controller
* + - AAIF APP / ACC Inteface ( Mobile Scalable Link , MSL )
* + - APEX
* + - VIDEO_ENC AVE2 / 3 Video Encoder
* + - XGAM Graphics Accelerator Controller
* + - AHB
* |
* + - ahb : 0 AHB Bridge
* | |
* | + - ahb : 1 INTCON Interrupt controller
* | + - ahb : 3 MSPRO Memory Stick Pro controller
* | + - ahb : 4 EMIF External Memory interface
* |
* + - fast : 0 FAST bridge
* | |
* | + - fast : 1 MMCSD MMC / SD card reader controller
* | + - fast : 2 I2S0 PCM I2S channel 0 controller
* | + - fast : 3 I2S1 PCM I2S channel 1 controller
* | + - fast : 4 I2C0 I2C channel 0 controller
* | + - fast : 5 I2C1 I2C channel 1 controller
* | + - fast : 6 SPI SPI controller
* | + - fast : 7 UART1 Secondary UART ( U335 only )
* |
* + - slow : 0 SLOW bridge
* |
* + - slow : 1 SYSCON ( not possible to control )
* + - slow : 2 WDOG Watchdog
* + - slow : 3 UART0 primary UART
* + - slow : 4 TIMER_APP Application timer - used in Linux
* + - slow : 5 KEYPAD controller
* + - slow : 6 GPIO controller
* + - slow : 7 RTC controller
* + - slow : 8 BT Bus Tracer ( not used currently )
* + - slow : 9 EH Event Handler ( not used currently )
* + - slow : a TIMER_ACC Access style timer ( not used currently )
* + - slow : b PPM ( U335 only , what is that ? )
*/
/*
* Reset control functions . We remember if a block has been
* taken out of reset and don ' t remove the reset assertion again
* and vice versa . Currently we only remove resets so the
* enablement function is defined out .
*/
static void syscon_block_reset_enable ( struct clk * clk )
{
u16 val ;
unsigned long iflags ;
/* Not all blocks support resetting */
if ( ! clk - > res_reg | | ! clk - > res_mask )
return ;
spin_lock_irqsave ( & syscon_resetreg_lock , iflags ) ;
val = readw ( clk - > res_reg ) ;
val | = clk - > res_mask ;
writew ( val , clk - > res_reg ) ;
spin_unlock_irqrestore ( & syscon_resetreg_lock , iflags ) ;
clk - > reset = true ;
}
static void syscon_block_reset_disable ( struct clk * clk )
{
u16 val ;
unsigned long iflags ;
/* Not all blocks support resetting */
if ( ! clk - > res_reg | | ! clk - > res_mask )
return ;
spin_lock_irqsave ( & syscon_resetreg_lock , iflags ) ;
val = readw ( clk - > res_reg ) ;
val & = ~ clk - > res_mask ;
writew ( val , clk - > res_reg ) ;
spin_unlock_irqrestore ( & syscon_resetreg_lock , iflags ) ;
clk - > reset = false ;
}
int __clk_get ( struct clk * clk )
{
u16 val ;
/* The MMC and MSPRO clocks need some special set-up */
if ( ! strcmp ( clk - > name , " MCLK " ) ) {
/* Set default MMC clock divisor to 18.9 MHz */
writew ( 0x0054U , U300_SYSCON_VBASE + U300_SYSCON_MMF0R ) ;
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_MMCR ) ;
/* Disable the MMC feedback clock */
val & = ~ U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE ;
/* Disable MSPRO frequency */
val & = ~ U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_MMCR ) ;
}
if ( ! strcmp ( clk - > name , " MSPRO " ) ) {
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_MMCR ) ;
/* Disable the MMC feedback clock */
val & = ~ U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE ;
/* Enable MSPRO frequency */
val | = U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_MMCR ) ;
}
return 1 ;
}
EXPORT_SYMBOL ( __clk_get ) ;
void __clk_put ( struct clk * clk )
{
}
EXPORT_SYMBOL ( __clk_put ) ;
static void syscon_clk_disable ( struct clk * clk )
{
unsigned long iflags ;
/* Don't touch the hardware controlled clocks */
if ( clk - > hw_ctrld )
return ;
spin_lock_irqsave ( & syscon_clkreg_lock , iflags ) ;
writew ( clk - > clk_val , U300_SYSCON_VBASE + U300_SYSCON_SBCDR ) ;
spin_unlock_irqrestore ( & syscon_clkreg_lock , iflags ) ;
}
static void syscon_clk_enable ( struct clk * clk )
{
unsigned long iflags ;
/* Don't touch the hardware controlled clocks */
if ( clk - > hw_ctrld )
return ;
spin_lock_irqsave ( & syscon_clkreg_lock , iflags ) ;
writew ( clk - > clk_val , U300_SYSCON_VBASE + U300_SYSCON_SBCER ) ;
spin_unlock_irqrestore ( & syscon_clkreg_lock , iflags ) ;
}
static u16 syscon_clk_get_rate ( void )
{
u16 val ;
unsigned long iflags ;
spin_lock_irqsave ( & syscon_clkreg_lock , iflags ) ;
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
val & = U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK ;
spin_unlock_irqrestore ( & syscon_clkreg_lock , iflags ) ;
return val ;
}
# ifdef CONFIG_MACH_U300_USE_I2S_AS_MASTER
static void enable_i2s0_vcxo ( void )
{
u16 val ;
unsigned long iflags ;
spin_lock_irqsave ( & syscon_clkreg_lock , iflags ) ;
/* Set I2S0 to use the VCXO 26 MHz clock */
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
val | = U300_SYSCON_CCR_TURN_VCXO_ON ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
val | = U300_SYSCON_CCR_I2S0_USE_VCXO ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_CEFR ) ;
val | = U300_SYSCON_CEFR_I2S0_CLK_EN ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CEFR ) ;
spin_unlock_irqrestore ( & syscon_clkreg_lock , iflags ) ;
}
static void enable_i2s1_vcxo ( void )
{
u16 val ;
unsigned long iflags ;
spin_lock_irqsave ( & syscon_clkreg_lock , iflags ) ;
/* Set I2S1 to use the VCXO 26 MHz clock */
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
val | = U300_SYSCON_CCR_TURN_VCXO_ON ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
val | = U300_SYSCON_CCR_I2S1_USE_VCXO ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_CEFR ) ;
val | = U300_SYSCON_CEFR_I2S1_CLK_EN ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CEFR ) ;
spin_unlock_irqrestore ( & syscon_clkreg_lock , iflags ) ;
}
static void disable_i2s0_vcxo ( void )
{
u16 val ;
unsigned long iflags ;
spin_lock_irqsave ( & syscon_clkreg_lock , iflags ) ;
/* Disable I2S0 use of the VCXO 26 MHz clock */
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
val & = ~ U300_SYSCON_CCR_I2S0_USE_VCXO ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
2011-03-30 22:57:33 -03:00
/* Deactivate VCXO if no one else is using VCXO */
2009-04-23 10:21:30 +01:00
if ( ! ( val & U300_SYSCON_CCR_I2S1_USE_VCXO ) )
val & = ~ U300_SYSCON_CCR_TURN_VCXO_ON ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_CEFR ) ;
val & = ~ U300_SYSCON_CEFR_I2S0_CLK_EN ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CEFR ) ;
spin_unlock_irqrestore ( & syscon_clkreg_lock , iflags ) ;
}
static void disable_i2s1_vcxo ( void )
{
u16 val ;
unsigned long iflags ;
spin_lock_irqsave ( & syscon_clkreg_lock , iflags ) ;
/* Disable I2S1 use of the VCXO 26 MHz clock */
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
val & = ~ U300_SYSCON_CCR_I2S1_USE_VCXO ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
2011-03-30 22:57:33 -03:00
/* Deactivate VCXO if no one else is using VCXO */
2009-04-23 10:21:30 +01:00
if ( ! ( val & U300_SYSCON_CCR_I2S0_USE_VCXO ) )
val & = ~ U300_SYSCON_CCR_TURN_VCXO_ON ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_CEFR ) ;
val & = ~ U300_SYSCON_CEFR_I2S0_CLK_EN ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CEFR ) ;
spin_unlock_irqrestore ( & syscon_clkreg_lock , iflags ) ;
}
# endif /* CONFIG_MACH_U300_USE_I2S_AS_MASTER */
static void syscon_clk_rate_set_mclk ( unsigned long rate )
{
u16 val ;
u32 reg ;
unsigned long iflags ;
switch ( rate ) {
case 18900000 :
val = 0x0054 ;
break ;
case 20800000 :
val = 0x0044 ;
break ;
case 23100000 :
val = 0x0043 ;
break ;
case 26000000 :
val = 0x0033 ;
break ;
case 29700000 :
val = 0x0032 ;
break ;
case 34700000 :
val = 0x0022 ;
break ;
case 41600000 :
val = 0x0021 ;
break ;
case 52000000 :
val = 0x0011 ;
break ;
case 104000000 :
val = 0x0000 ;
break ;
default :
printk ( KERN_ERR " Trying to set MCLK to unknown speed! %ld \n " ,
rate ) ;
return ;
}
spin_lock_irqsave ( & syscon_clkreg_lock , iflags ) ;
reg = readw ( U300_SYSCON_VBASE + U300_SYSCON_MMF0R ) &
~ U300_SYSCON_MMF0R_MASK ;
writew ( reg | val , U300_SYSCON_VBASE + U300_SYSCON_MMF0R ) ;
spin_unlock_irqrestore ( & syscon_clkreg_lock , iflags ) ;
}
void syscon_clk_rate_set_cpuclk ( unsigned long rate )
{
u16 val ;
unsigned long iflags ;
switch ( rate ) {
case 13000000 :
val = U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER ;
break ;
case 52000000 :
val = U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE ;
break ;
case 104000000 :
val = U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH ;
break ;
case 208000000 :
val = U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST ;
break ;
default :
return ;
}
spin_lock_irqsave ( & syscon_clkreg_lock , iflags ) ;
val | = readw ( U300_SYSCON_VBASE + U300_SYSCON_CCR ) &
~ U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
spin_unlock_irqrestore ( & syscon_clkreg_lock , iflags ) ;
}
EXPORT_SYMBOL ( syscon_clk_rate_set_cpuclk ) ;
void clk_disable ( struct clk * clk )
{
unsigned long iflags ;
spin_lock_irqsave ( & clk - > lock , iflags ) ;
if ( clk - > usecount > 0 & & ! ( - - clk - > usecount ) ) {
/* some blocks lack clocking registers and cannot be disabled */
if ( clk - > disable )
clk - > disable ( clk ) ;
if ( likely ( ( u32 ) clk - > parent ) )
clk_disable ( clk - > parent ) ;
}
# ifdef CONFIG_MACH_U300_USE_I2S_AS_MASTER
if ( unlikely ( ! strcmp ( clk - > name , " I2S0 " ) ) )
disable_i2s0_vcxo ( ) ;
if ( unlikely ( ! strcmp ( clk - > name , " I2S1 " ) ) )
disable_i2s1_vcxo ( ) ;
# endif
spin_unlock_irqrestore ( & clk - > lock , iflags ) ;
}
EXPORT_SYMBOL ( clk_disable ) ;
int clk_enable ( struct clk * clk )
{
int ret = 0 ;
unsigned long iflags ;
spin_lock_irqsave ( & clk - > lock , iflags ) ;
if ( clk - > usecount + + = = 0 ) {
if ( likely ( ( u32 ) clk - > parent ) )
ret = clk_enable ( clk - > parent ) ;
if ( unlikely ( ret ! = 0 ) )
clk - > usecount - - ;
else {
/* remove reset line (we never enable reset again) */
syscon_block_reset_disable ( clk ) ;
/* clocks without enable function are always on */
if ( clk - > enable )
clk - > enable ( clk ) ;
# ifdef CONFIG_MACH_U300_USE_I2S_AS_MASTER
if ( unlikely ( ! strcmp ( clk - > name , " I2S0 " ) ) )
enable_i2s0_vcxo ( ) ;
if ( unlikely ( ! strcmp ( clk - > name , " I2S1 " ) ) )
enable_i2s1_vcxo ( ) ;
# endif
}
}
spin_unlock_irqrestore ( & clk - > lock , iflags ) ;
return ret ;
}
EXPORT_SYMBOL ( clk_enable ) ;
/* Returns the clock rate in Hz */
static unsigned long clk_get_rate_cpuclk ( struct clk * clk )
{
u16 val ;
val = syscon_clk_get_rate ( ) ;
switch ( val ) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW :
return 13000000 ;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE :
return 52000000 ;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH :
return 104000000 ;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST :
return 208000000 ;
default :
break ;
}
return clk - > rate ;
}
static unsigned long clk_get_rate_ahb_clk ( struct clk * clk )
{
u16 val ;
val = syscon_clk_get_rate ( ) ;
switch ( val ) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW :
return 6500000 ;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE :
return 26000000 ;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST :
return 52000000 ;
default :
break ;
}
return clk - > rate ;
}
static unsigned long clk_get_rate_emif_clk ( struct clk * clk )
{
u16 val ;
val = syscon_clk_get_rate ( ) ;
switch ( val ) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW :
return 13000000 ;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE :
return 52000000 ;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST :
return 104000000 ;
default :
break ;
}
return clk - > rate ;
}
static unsigned long clk_get_rate_xgamclk ( struct clk * clk )
{
u16 val ;
val = syscon_clk_get_rate ( ) ;
switch ( val ) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW :
return 6500000 ;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE :
return 26000000 ;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST :
return 52000000 ;
default :
break ;
}
return clk - > rate ;
}
static unsigned long clk_get_rate_mclk ( struct clk * clk )
{
u16 val ;
val = syscon_clk_get_rate ( ) ;
switch ( val ) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER :
/*
* Here , the 208 MHz PLL gets shut down and the always
* on 13 MHz PLL used for RTC etc kicks into use
* instead .
*/
return 13000000 ;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST :
{
/*
* This clock is under program control . The register is
* divided in two nybbles , bit 7 - 4 gives cycles - 1 to count
* high , bit 3 - 0 gives cycles - 1 to count low . Distribute
* these with no more than 1 cycle difference between
* low and high and add low and high to get the actual
* divisor . The base PLL is 208 MHz . Writing 0x00 will
* divide by 1 and 1 so the highest frequency possible
* is 104 MHz .
*
* e . g . 0x54 = >
* f = 208 / ( ( 5 + 1 ) + ( 4 + 1 ) ) = 208 / 11 = 18.9 MHz
*/
u16 val = readw ( U300_SYSCON_VBASE + U300_SYSCON_MMF0R ) &
U300_SYSCON_MMF0R_MASK ;
switch ( val ) {
case 0x0054 :
return 18900000 ;
case 0x0044 :
return 20800000 ;
case 0x0043 :
return 23100000 ;
case 0x0033 :
return 26000000 ;
case 0x0032 :
return 29700000 ;
case 0x0022 :
return 34700000 ;
case 0x0021 :
return 41600000 ;
case 0x0011 :
return 52000000 ;
case 0x0000 :
return 104000000 ;
default :
break ;
}
}
default :
break ;
}
return clk - > rate ;
}
static unsigned long clk_get_rate_i2s_i2c_spi ( struct clk * clk )
{
u16 val ;
val = syscon_clk_get_rate ( ) ;
switch ( val ) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW :
return 13000000 ;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH :
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST :
return 26000000 ;
default :
break ;
}
return clk - > rate ;
}
unsigned long clk_get_rate ( struct clk * clk )
{
if ( clk - > get_rate )
return clk - > get_rate ( clk ) ;
else
return clk - > rate ;
}
EXPORT_SYMBOL ( clk_get_rate ) ;
static unsigned long clk_round_rate_mclk ( struct clk * clk , unsigned long rate )
{
2010-02-24 21:49:53 +01:00
if ( rate < = 18900000 )
2009-04-23 10:21:30 +01:00
return 18900000 ;
2010-02-24 21:49:53 +01:00
if ( rate < = 20800000 )
2009-04-23 10:21:30 +01:00
return 20800000 ;
2010-02-24 21:49:53 +01:00
if ( rate < = 23100000 )
2009-04-23 10:21:30 +01:00
return 23100000 ;
2010-02-24 21:49:53 +01:00
if ( rate < = 26000000 )
2009-04-23 10:21:30 +01:00
return 26000000 ;
2010-02-24 21:49:53 +01:00
if ( rate < = 29700000 )
2009-04-23 10:21:30 +01:00
return 29700000 ;
2010-02-24 21:49:53 +01:00
if ( rate < = 34700000 )
2009-04-23 10:21:30 +01:00
return 34700000 ;
2010-02-24 21:49:53 +01:00
if ( rate < = 41600000 )
2009-04-23 10:21:30 +01:00
return 41600000 ;
2010-02-24 21:49:53 +01:00
if ( rate < = 52000000 )
2009-04-23 10:21:30 +01:00
return 52000000 ;
return - EINVAL ;
}
static unsigned long clk_round_rate_cpuclk ( struct clk * clk , unsigned long rate )
{
2010-02-24 21:49:53 +01:00
if ( rate < = 13000000 )
2009-04-23 10:21:30 +01:00
return 13000000 ;
2010-02-24 21:49:53 +01:00
if ( rate < = 52000000 )
2009-04-23 10:21:30 +01:00
return 52000000 ;
2010-02-24 21:49:53 +01:00
if ( rate < = 104000000 )
2009-04-23 10:21:30 +01:00
return 104000000 ;
2010-02-24 21:49:53 +01:00
if ( rate < = 208000000 )
2009-04-23 10:21:30 +01:00
return 208000000 ;
return - EINVAL ;
}
/*
* This adjusts a requested rate to the closest exact rate
* a certain clock can provide . For a fixed clock it ' s
* mostly clk - > rate .
*/
long clk_round_rate ( struct clk * clk , unsigned long rate )
{
2011-03-30 22:57:33 -03:00
/* TODO: get appropriate switches for EMIFCLK, AHBCLK and MCLK */
2009-04-23 10:21:30 +01:00
/* Else default to fixed value */
if ( clk - > round_rate ) {
return ( long ) clk - > round_rate ( clk , rate ) ;
} else {
printk ( KERN_ERR " clock: Failed to round rate of %s \n " ,
clk - > name ) ;
}
return ( long ) clk - > rate ;
}
EXPORT_SYMBOL ( clk_round_rate ) ;
static int clk_set_rate_mclk ( struct clk * clk , unsigned long rate )
{
syscon_clk_rate_set_mclk ( clk_round_rate ( clk , rate ) ) ;
return 0 ;
}
static int clk_set_rate_cpuclk ( struct clk * clk , unsigned long rate )
{
syscon_clk_rate_set_cpuclk ( clk_round_rate ( clk , rate ) ) ;
return 0 ;
}
int clk_set_rate ( struct clk * clk , unsigned long rate )
{
/* TODO: set for EMIFCLK and AHBCLK */
/* Else assume the clock is fixed and fail */
if ( clk - > set_rate ) {
return clk - > set_rate ( clk , rate ) ;
} else {
printk ( KERN_ERR " clock: Failed to set %s to %ld hz \n " ,
clk - > name , rate ) ;
2009-05-31 15:08:11 +01:00
return - EINVAL ;
2009-04-23 10:21:30 +01:00
}
}
EXPORT_SYMBOL ( clk_set_rate ) ;
/*
* Clock definitions . The clock parents are set to respective
* bridge and the clock framework makes sure that the clocks have
* parents activated and are brought out of reset when in use .
*
* Clocks that have hw_ctrld = true are hw controlled , and the hw
* can by itself turn these clocks on and off .
* So in other words , we don ' t really have to care about them .
*/
static struct clk amba_clk = {
. name = " AMBA " ,
. rate = 52000000 , /* this varies! */
. hw_ctrld = true ,
. reset = false ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( amba_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
/*
* These blocks are connected directly to the AMBA bus
* with no bridge .
*/
static struct clk cpu_clk = {
. name = " CPU " ,
. parent = & amba_clk ,
. rate = 208000000 , /* this varies! */
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
. res_mask = U300_SYSCON_RRR_CPU_RESET_EN ,
. set_rate = clk_set_rate_cpuclk ,
. get_rate = clk_get_rate_cpuclk ,
. round_rate = clk_round_rate_cpuclk ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( cpu_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk nandif_clk = {
2010-09-13 00:35:37 +02:00
. name = " FSMC " ,
2009-04-23 10:21:30 +01:00
. parent = & amba_clk ,
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
. res_mask = U300_SYSCON_RRR_NANDIF_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_NANDIF_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( nandif_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk semi_clk = {
. name = " SEMI " ,
. parent = & amba_clk ,
. rate = 0 , /* FIXME */
/* It is not possible to reset SEMI */
. hw_ctrld = false ,
. reset = false ,
. clk_val = U300_SYSCON_SBCER_SEMI_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( semi_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
# ifdef CONFIG_MACH_U300_BS335
static struct clk isp_clk = {
. name = " ISP " ,
. parent = & amba_clk ,
. rate = 0 , /* FIXME */
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
. res_mask = U300_SYSCON_RRR_ISP_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_ISP_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( isp_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk cds_clk = {
. name = " CDS " ,
. parent = & amba_clk ,
. rate = 0 , /* FIXME */
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
. res_mask = U300_SYSCON_RRR_CDS_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_CDS_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( cds_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
# endif
static struct clk dma_clk = {
. name = " DMA " ,
. parent = & amba_clk ,
. rate = 52000000 , /* this varies! */
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
. res_mask = U300_SYSCON_RRR_DMAC_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_DMAC_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( dma_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk aaif_clk = {
. name = " AAIF " ,
. parent = & amba_clk ,
. rate = 52000000 , /* this varies! */
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
. res_mask = U300_SYSCON_RRR_AAIF_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_AAIF_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( aaif_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk apex_clk = {
. name = " APEX " ,
. parent = & amba_clk ,
. rate = 0 , /* FIXME */
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
. res_mask = U300_SYSCON_RRR_APEX_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_APEX_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( apex_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk video_enc_clk = {
. name = " VIDEO_ENC " ,
. parent = & amba_clk ,
. rate = 208000000 , /* this varies! */
. hw_ctrld = false ,
. reset = false ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
/* This has XGAM in the name but refers to the video encoder */
. res_mask = U300_SYSCON_RRR_XGAM_VC_SYNC_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_VIDEO_ENC_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( video_enc_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk xgam_clk = {
. name = " XGAMCLK " ,
. parent = & amba_clk ,
. rate = 52000000 , /* this varies! */
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
. res_mask = U300_SYSCON_RRR_XGAM_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_XGAM_CLK_EN ,
. get_rate = clk_get_rate_xgamclk ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( xgam_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
/* This clock is used to activate the video encoder */
static struct clk ahb_clk = {
. name = " AHB " ,
. parent = & amba_clk ,
. rate = 52000000 , /* this varies! */
. hw_ctrld = false , /* This one is set to false due to HW bug */
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
. res_mask = U300_SYSCON_RRR_AHB_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_AHB_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
. get_rate = clk_get_rate_ahb_clk ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( ahb_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
/*
* Clocks on the AHB bridge
*/
static struct clk ahb_subsys_clk = {
. name = " AHB_SUBSYS " ,
. parent = & amba_clk ,
. rate = 52000000 , /* this varies! */
. hw_ctrld = true ,
. reset = false ,
. clk_val = U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
. get_rate = clk_get_rate_ahb_clk ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( ahb_subsys_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk intcon_clk = {
. name = " INTCON " ,
. parent = & ahb_subsys_clk ,
. rate = 52000000 , /* this varies! */
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
. res_mask = U300_SYSCON_RRR_INTCON_RESET_EN ,
/* INTCON can be reset but not clock-gated */
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( intcon_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk mspro_clk = {
. name = " MSPRO " ,
. parent = & ahb_subsys_clk ,
. rate = 0 , /* FIXME */
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
. res_mask = U300_SYSCON_RRR_MSPRO_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_MSPRO_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( mspro_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk emif_clk = {
. name = " EMIF " ,
. parent = & ahb_subsys_clk ,
. rate = 104000000 , /* this varies! */
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR ,
. res_mask = U300_SYSCON_RRR_EMIF_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_EMIF_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
. get_rate = clk_get_rate_emif_clk ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( emif_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
/*
* Clocks on the FAST bridge
*/
static struct clk fast_clk = {
. name = " FAST_BRIDGE " ,
. parent = & amba_clk ,
. rate = 13000000 , /* this varies! */
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR ,
. res_mask = U300_SYSCON_RFR_FAST_BRIDGE_RESET_ENABLE ,
. clk_val = U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( fast_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
2010-08-05 07:58:13 +01:00
/*
* The MMCI apb_pclk is hardwired to the same terminal as the
* external MCI clock . Thus this will be referenced twice .
*/
2009-04-23 10:21:30 +01:00
static struct clk mmcsd_clk = {
. name = " MCLK " ,
. parent = & fast_clk ,
. rate = 18900000 , /* this varies! */
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR ,
. res_mask = U300_SYSCON_RFR_MMC_RESET_ENABLE ,
. clk_val = U300_SYSCON_SBCER_MMC_CLK_EN ,
. get_rate = clk_get_rate_mclk ,
. set_rate = clk_set_rate_mclk ,
. round_rate = clk_round_rate_mclk ,
. disable = syscon_clk_disable ,
. enable = syscon_clk_enable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( mmcsd_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk i2s0_clk = {
. name = " i2s0 " ,
. parent = & fast_clk ,
. rate = 26000000 , /* this varies! */
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR ,
. res_mask = U300_SYSCON_RFR_PCM_I2S0_RESET_ENABLE ,
. clk_val = U300_SYSCON_SBCER_I2S0_CORE_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
. get_rate = clk_get_rate_i2s_i2c_spi ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( i2s0_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk i2s1_clk = {
. name = " i2s1 " ,
. parent = & fast_clk ,
. rate = 26000000 , /* this varies! */
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR ,
. res_mask = U300_SYSCON_RFR_PCM_I2S1_RESET_ENABLE ,
. clk_val = U300_SYSCON_SBCER_I2S1_CORE_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
. get_rate = clk_get_rate_i2s_i2c_spi ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( i2s1_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk i2c0_clk = {
. name = " I2C0 " ,
. parent = & fast_clk ,
. rate = 26000000 , /* this varies! */
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR ,
. res_mask = U300_SYSCON_RFR_I2C0_RESET_ENABLE ,
. clk_val = U300_SYSCON_SBCER_I2C0_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
. get_rate = clk_get_rate_i2s_i2c_spi ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( i2c0_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk i2c1_clk = {
. name = " I2C1 " ,
. parent = & fast_clk ,
. rate = 26000000 , /* this varies! */
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR ,
. res_mask = U300_SYSCON_RFR_I2C1_RESET_ENABLE ,
. clk_val = U300_SYSCON_SBCER_I2C1_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
. get_rate = clk_get_rate_i2s_i2c_spi ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( i2c1_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
2010-08-05 07:58:13 +01:00
/*
* The SPI apb_pclk is hardwired to the same terminal as the
* external SPI clock . Thus this will be referenced twice .
*/
2009-04-23 10:21:30 +01:00
static struct clk spi_clk = {
. name = " SPI " ,
. parent = & fast_clk ,
. rate = 26000000 , /* this varies! */
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR ,
. res_mask = U300_SYSCON_RFR_SPI_RESET_ENABLE ,
. clk_val = U300_SYSCON_SBCER_SPI_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
. get_rate = clk_get_rate_i2s_i2c_spi ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( spi_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
# ifdef CONFIG_MACH_U300_BS335
2010-08-05 07:58:13 +01:00
static struct clk uart1_pclk = {
. name = " UART1_PCLK " ,
2009-04-23 10:21:30 +01:00
. parent = & fast_clk ,
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR ,
. res_mask = U300_SYSCON_RFR_UART1_RESET_ENABLE ,
. clk_val = U300_SYSCON_SBCER_UART1_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2010-08-05 07:58:13 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( uart1_pclk . lock ) ,
} ;
/* This one is hardwired to PLL13 */
static struct clk uart1_clk = {
. name = " UART1_CLK " ,
. rate = 13000000 ,
. hw_ctrld = true ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( uart1_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
# endif
/*
* Clocks on the SLOW bridge
*/
static struct clk slow_clk = {
. name = " SLOW_BRIDGE " ,
. parent = & amba_clk ,
. rate = 13000000 ,
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR ,
. res_mask = U300_SYSCON_RSR_SLOW_BRIDGE_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( slow_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
/* TODO: implement SYSCON clock? */
static struct clk wdog_clk = {
. name = " WDOG " ,
. parent = & slow_clk ,
. hw_ctrld = false ,
. rate = 32768 ,
. reset = false ,
/* This is always on, cannot be enabled/disabled or reset */
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( wdog_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
2010-08-05 07:58:13 +01:00
static struct clk uart0_pclk = {
. name = " UART0_PCLK " ,
2009-04-23 10:21:30 +01:00
. parent = & slow_clk ,
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR ,
. res_mask = U300_SYSCON_RSR_UART_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_UART_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2010-08-05 07:58:13 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( uart0_pclk . lock ) ,
} ;
/* This one is hardwired to PLL13 */
static struct clk uart0_clk = {
. name = " UART0_CLK " ,
. parent = & slow_clk ,
. rate = 13000000 ,
. hw_ctrld = true ,
. lock = __SPIN_LOCK_UNLOCKED ( uart0_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk keypad_clk = {
. name = " KEYPAD " ,
. parent = & slow_clk ,
. rate = 32768 ,
. hw_ctrld = false ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR ,
. res_mask = U300_SYSCON_RSR_KEYPAD_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_KEYPAD_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( keypad_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk gpio_clk = {
. name = " GPIO " ,
. parent = & slow_clk ,
. rate = 13000000 ,
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR ,
. res_mask = U300_SYSCON_RSR_GPIO_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_GPIO_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( gpio_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk rtc_clk = {
. name = " RTC " ,
. parent = & slow_clk ,
. rate = 32768 ,
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR ,
. res_mask = U300_SYSCON_RSR_RTC_RESET_EN ,
/* This clock is always on, cannot be enabled/disabled */
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( rtc_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk bustr_clk = {
. name = " BUSTR " ,
. parent = & slow_clk ,
. rate = 13000000 ,
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR ,
. res_mask = U300_SYSCON_RSR_BTR_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_BTR_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( bustr_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk evhist_clk = {
. name = " EVHIST " ,
. parent = & slow_clk ,
. rate = 13000000 ,
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR ,
. res_mask = U300_SYSCON_RSR_EH_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_EH_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( evhist_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
static struct clk timer_clk = {
. name = " TIMER " ,
. parent = & slow_clk ,
. rate = 13000000 ,
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR ,
. res_mask = U300_SYSCON_RSR_ACC_TMR_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_ACC_TMR_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( timer_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
2010-08-05 07:59:54 +01:00
/*
* There is a binary divider in the hardware that divides
* the 13 MHz PLL by 13 down to 1 MHz .
*/
2009-04-23 10:21:30 +01:00
static struct clk app_timer_clk = {
. name = " TIMER_APP " ,
. parent = & slow_clk ,
2010-08-05 07:59:54 +01:00
. rate = 1000000 ,
2009-04-23 10:21:30 +01:00
. hw_ctrld = true ,
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR ,
. res_mask = U300_SYSCON_RSR_APP_TMR_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_APP_TMR_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( app_timer_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
# ifdef CONFIG_MACH_U300_BS335
static struct clk ppm_clk = {
. name = " PPM " ,
. parent = & slow_clk ,
. rate = 0 , /* FIXME */
. hw_ctrld = true , /* TODO: Look up if it is hw ctrld or not */
. reset = true ,
. res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR ,
. res_mask = U300_SYSCON_RSR_PPM_RESET_EN ,
. clk_val = U300_SYSCON_SBCER_PPM_CLK_EN ,
. enable = syscon_clk_enable ,
. disable = syscon_clk_disable ,
2009-07-02 00:27:57 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( ppm_clk . lock ) ,
2009-04-23 10:21:30 +01:00
} ;
# endif
# define DEF_LOOKUP(devid, clkref) \
{ \
. dev_id = devid , \
. clk = clkref , \
}
2010-08-05 07:58:13 +01:00
# define DEF_LOOKUP_CON(devid, conid, clkref) \
{ \
. dev_id = devid , \
. con_id = conid , \
. clk = clkref , \
}
2009-04-23 10:21:30 +01:00
/*
* Here we only define clocks that are meaningful to
* look up through clockdevice .
*/
static struct clk_lookup lookups [ ] = {
/* Connected directly to the AMBA bus */
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " amba " , & amba_clk ) ,
DEF_LOOKUP ( " cpu " , & cpu_clk ) ,
2010-09-13 00:35:37 +02:00
DEF_LOOKUP ( " fsmc-nand " , & nandif_clk ) ,
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " semi " , & semi_clk ) ,
2009-04-23 10:21:30 +01:00
# ifdef CONFIG_MACH_U300_BS335
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " isp " , & isp_clk ) ,
DEF_LOOKUP ( " cds " , & cds_clk ) ,
2009-04-23 10:21:30 +01:00
# endif
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " dma " , & dma_clk ) ,
DEF_LOOKUP ( " msl " , & aaif_clk ) ,
DEF_LOOKUP ( " apex " , & apex_clk ) ,
2009-04-23 10:21:30 +01:00
DEF_LOOKUP ( " video_enc " , & video_enc_clk ) ,
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " xgam " , & xgam_clk ) ,
DEF_LOOKUP ( " ahb " , & ahb_clk ) ,
2009-04-23 10:21:30 +01:00
/* AHB bridge clocks */
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " ahb_subsys " , & ahb_subsys_clk ) ,
DEF_LOOKUP ( " intcon " , & intcon_clk ) ,
2010-08-05 07:58:13 +01:00
DEF_LOOKUP_CON ( " intcon " , " apb_pclk " , & intcon_clk ) ,
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " mspro " , & mspro_clk ) ,
DEF_LOOKUP ( " pl172 " , & emif_clk ) ,
2010-08-05 07:58:13 +01:00
DEF_LOOKUP_CON ( " pl172 " , " apb_pclk " , & emif_clk ) ,
2009-04-23 10:21:30 +01:00
/* FAST bridge clocks */
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " fast " , & fast_clk ) ,
DEF_LOOKUP ( " mmci " , & mmcsd_clk ) ,
2010-08-05 07:58:13 +01:00
DEF_LOOKUP_CON ( " mmci " , " apb_pclk " , & mmcsd_clk ) ,
2009-04-23 10:21:30 +01:00
/*
* The .0 and .1 identifiers on these comes from the platform device
* . id field and are assigned when the platform devices are registered .
*/
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " i2s.0 " , & i2s0_clk ) ,
DEF_LOOKUP ( " i2s.1 " , & i2s1_clk ) ,
DEF_LOOKUP ( " stu300.0 " , & i2c0_clk ) ,
DEF_LOOKUP ( " stu300.1 " , & i2c1_clk ) ,
DEF_LOOKUP ( " pl022 " , & spi_clk ) ,
2010-08-05 07:58:13 +01:00
DEF_LOOKUP_CON ( " pl022 " , " apb_pclk " , & spi_clk ) ,
2009-04-23 10:21:30 +01:00
# ifdef CONFIG_MACH_U300_BS335
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " uart1 " , & uart1_clk ) ,
2010-08-05 07:58:13 +01:00
DEF_LOOKUP_CON ( " uart1 " , " apb_pclk " , & uart1_pclk ) ,
2009-04-23 10:21:30 +01:00
# endif
/* SLOW bridge clocks */
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " slow " , & slow_clk ) ,
DEF_LOOKUP ( " coh901327_wdog " , & wdog_clk ) ,
2010-08-05 07:58:13 +01:00
DEF_LOOKUP ( " uart0 " , & uart0_clk ) ,
DEF_LOOKUP_CON ( " uart0 " , " apb_pclk " , & uart0_pclk ) ,
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " apptimer " , & app_timer_clk ) ,
DEF_LOOKUP ( " coh901461-keypad " , & keypad_clk ) ,
2009-04-23 10:21:30 +01:00
DEF_LOOKUP ( " u300-gpio " , & gpio_clk ) ,
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " rtc-coh901331 " , & rtc_clk ) ,
DEF_LOOKUP ( " bustr " , & bustr_clk ) ,
DEF_LOOKUP ( " evhist " , & evhist_clk ) ,
DEF_LOOKUP ( " timer " , & timer_clk ) ,
2009-04-23 10:21:30 +01:00
# ifdef CONFIG_MACH_U300_BS335
2009-07-02 00:27:57 +01:00
DEF_LOOKUP ( " ppm " , & ppm_clk ) ,
2009-04-23 10:21:30 +01:00
# endif
} ;
static void __init clk_register ( void )
{
/* Register the lookups */
2010-01-12 12:28:00 +00:00
clkdev_add_table ( lookups , ARRAY_SIZE ( lookups ) ) ;
2009-04-23 10:21:30 +01:00
}
# if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG))
/*
* The following makes it possible to view the status ( especially
* reference count and reset status ) for the clocks in the platform
* by looking into the special file < debugfs > / u300_clocks
*/
/* A list of all clocks in the platform */
static struct clk * clks [ ] = {
/* Top node clock for the AMBA bus */
& amba_clk ,
/* Connected directly to the AMBA bus */
& cpu_clk ,
& nandif_clk ,
& semi_clk ,
# ifdef CONFIG_MACH_U300_BS335
& isp_clk ,
& cds_clk ,
# endif
& dma_clk ,
& aaif_clk ,
& apex_clk ,
& video_enc_clk ,
& xgam_clk ,
& ahb_clk ,
/* AHB bridge clocks */
& ahb_subsys_clk ,
& intcon_clk ,
& mspro_clk ,
& emif_clk ,
/* FAST bridge clocks */
& fast_clk ,
& mmcsd_clk ,
& i2s0_clk ,
& i2s1_clk ,
& i2c0_clk ,
& i2c1_clk ,
& spi_clk ,
# ifdef CONFIG_MACH_U300_BS335
& uart1_clk ,
2010-08-05 07:58:13 +01:00
& uart1_pclk ,
2009-04-23 10:21:30 +01:00
# endif
/* SLOW bridge clocks */
& slow_clk ,
& wdog_clk ,
2010-08-05 07:58:13 +01:00
& uart0_clk ,
& uart0_pclk ,
2009-04-23 10:21:30 +01:00
& app_timer_clk ,
& keypad_clk ,
& gpio_clk ,
& rtc_clk ,
& bustr_clk ,
& evhist_clk ,
& timer_clk ,
# ifdef CONFIG_MACH_U300_BS335
& ppm_clk ,
# endif
} ;
static int u300_clocks_show ( struct seq_file * s , void * data )
{
struct clk * clk ;
int i ;
seq_printf ( s , " CLOCK DEVICE RESET STATE \t " \
" ACTIVE \t USERS \t HW CTRL FREQ \n " ) ;
seq_printf ( s , " --------------------------------------------- " \
" ----------------------------------------- \n " ) ;
for ( i = 0 ; i < ARRAY_SIZE ( clks ) ; i + + ) {
clk = clks [ i ] ;
if ( clk ! = ERR_PTR ( - ENOENT ) ) {
/* Format clock and device name nicely */
char cdp [ 33 ] ;
int chars ;
chars = snprintf ( & cdp [ 0 ] , 17 , " %s " , clk - > name ) ;
while ( chars < 16 ) {
cdp [ chars ] = ' ' ;
chars + + ;
}
chars = snprintf ( & cdp [ 16 ] , 17 , " %s " , clk - > dev ?
dev_name ( clk - > dev ) : " N/A " ) ;
while ( chars < 16 ) {
cdp [ chars + 16 ] = ' ' ;
chars + + ;
}
cdp [ 32 ] = ' \0 ' ;
2010-08-05 07:58:13 +01:00
if ( clk - > get_rate | | clk - > rate ! = 0 )
2009-04-23 10:21:30 +01:00
seq_printf ( s ,
" %s%s \t %s \t %d \t %s \t %lu Hz \n " ,
& cdp [ 0 ] ,
clk - > reset ?
" ASSERTED " : " RELEASED " ,
clk - > usecount ? " ON " : " OFF " ,
clk - > usecount ,
clk - > hw_ctrld ? " YES " : " NO " ,
2010-08-05 07:58:13 +01:00
clk_get_rate ( clk ) ) ;
2009-04-23 10:21:30 +01:00
else
seq_printf ( s ,
" %s%s \t %s \t %d \t %s \t " \
" (unknown rate) \n " ,
& cdp [ 0 ] ,
clk - > reset ?
" ASSERTED " : " RELEASED " ,
clk - > usecount ? " ON " : " OFF " ,
clk - > usecount ,
clk - > hw_ctrld ? " YES " : " NO " ) ;
}
}
return 0 ;
}
static int u300_clocks_open ( struct inode * inode , struct file * file )
{
return single_open ( file , u300_clocks_show , NULL ) ;
}
static const struct file_operations u300_clocks_operations = {
. open = u300_clocks_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
2009-07-02 00:27:57 +01:00
static int __init init_clk_read_debugfs ( void )
2009-04-23 10:21:30 +01:00
{
/* Expose a simple debugfs interface to view all clocks */
( void ) debugfs_create_file ( " u300_clocks " , S_IFREG | S_IRUGO ,
2009-07-02 00:27:57 +01:00
NULL , NULL ,
& u300_clocks_operations ) ;
return 0 ;
2009-04-23 10:21:30 +01:00
}
2009-07-02 00:27:57 +01:00
/*
* This needs to come in after the core_initcall ( ) for the
* overall clocks , because debugfs is not available until
* the subsystems come up .
*/
module_init ( init_clk_read_debugfs ) ;
2009-04-23 10:21:30 +01:00
# endif
2010-08-05 07:58:13 +01:00
int __init u300_clock_init ( void )
2009-04-23 10:21:30 +01:00
{
u16 val ;
/*
* FIXME : shall all this powermanagement stuff really live here ? ? ?
*/
/* Set system to run at PLL208, max performance, a known state. */
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
val & = ~ U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_CCR ) ;
/* Wait for the PLL208 to lock if not locked in yet */
while ( ! ( readw ( U300_SYSCON_VBASE + U300_SYSCON_CSR ) &
U300_SYSCON_CSR_PLL208_LOCK_IND ) ) ;
/* Power management enable */
val = readw ( U300_SYSCON_VBASE + U300_SYSCON_PMCR ) ;
val | = U300_SYSCON_PMCR_PWR_MGNT_ENABLE ;
writew ( val , U300_SYSCON_VBASE + U300_SYSCON_PMCR ) ;
clk_register ( ) ;
/*
* Some of these may be on when we boot the system so make sure they
* are turned OFF .
*/
syscon_block_reset_enable ( & timer_clk ) ;
timer_clk . disable ( & timer_clk ) ;
/*
* These shall be turned on by default when we boot the system
* so make sure they are ON . ( Adding CPU here is a bit too much . )
* These clocks will be claimed by drivers later .
*/
syscon_block_reset_disable ( & semi_clk ) ;
syscon_block_reset_disable ( & emif_clk ) ;
2010-08-05 07:58:13 +01:00
clk_enable ( & semi_clk ) ;
clk_enable ( & emif_clk ) ;
2009-04-23 10:21:30 +01:00
return 0 ;
}