2010-01-29 08:40:29 +08:00
/*
* arch / arm / mach - tegra / tegra2_clocks . c
*
* Copyright ( C ) 2010 Google , Inc .
*
* Author :
* Colin Cross < ccross @ google . com >
*
* This software is licensed under the terms of the GNU General Public
* License version 2 , as published by the Free Software Foundation , and
* may be copied , distributed , and modified under those terms .
*
* 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 .
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/list.h>
# include <linux/spinlock.h>
# include <linux/delay.h>
# include <linux/io.h>
# include <linux/hrtimer.h>
2010-11-17 17:04:33 +08:00
# include <linux/clkdev.h>
2010-01-29 08:40:29 +08:00
# include <mach/iomap.h>
# include "clock.h"
2010-06-08 11:49:46 +08:00
# include "fuse.h"
# include "tegra2_dvfs.h"
2010-01-29 08:40:29 +08:00
# define RST_DEVICES 0x004
# define RST_DEVICES_SET 0x300
# define RST_DEVICES_CLR 0x304
2010-06-08 11:49:46 +08:00
# define RST_DEVICES_NUM 3
2010-01-29 08:40:29 +08:00
# define CLK_OUT_ENB 0x010
# define CLK_OUT_ENB_SET 0x320
# define CLK_OUT_ENB_CLR 0x324
2010-06-08 11:49:46 +08:00
# define CLK_OUT_ENB_NUM 3
# define CLK_MASK_ARM 0x44
# define MISC_CLK_ENB 0x48
2010-01-29 08:40:29 +08:00
# define OSC_CTRL 0x50
# define OSC_CTRL_OSC_FREQ_MASK (3<<30)
# define OSC_CTRL_OSC_FREQ_13MHZ (0<<30)
# define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30)
# define OSC_CTRL_OSC_FREQ_12MHZ (2<<30)
# define OSC_CTRL_OSC_FREQ_26MHZ (3<<30)
2010-06-08 11:49:46 +08:00
# define OSC_CTRL_MASK 0x3f2
2010-01-29 08:40:29 +08:00
# define OSC_FREQ_DET 0x58
# define OSC_FREQ_DET_TRIG (1<<31)
# define OSC_FREQ_DET_STATUS 0x5C
# define OSC_FREQ_DET_BUSY (1<<31)
# define OSC_FREQ_DET_CNT_MASK 0xFFFF
2010-06-08 11:49:46 +08:00
# define PERIPH_CLK_SOURCE_I2S1 0x100
# define PERIPH_CLK_SOURCE_EMC 0x19c
# define PERIPH_CLK_SOURCE_OSC 0x1fc
# define PERIPH_CLK_SOURCE_NUM \
( ( PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1 ) / 4 )
2010-01-29 08:40:29 +08:00
# define PERIPH_CLK_SOURCE_MASK (3<<30)
# define PERIPH_CLK_SOURCE_SHIFT 30
# define PERIPH_CLK_SOURCE_ENABLE (1<<28)
2010-06-08 11:49:46 +08:00
# define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF
# define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
2010-01-29 08:40:29 +08:00
# define PERIPH_CLK_SOURCE_DIV_SHIFT 0
# define PLL_BASE 0x0
# define PLL_BASE_BYPASS (1<<31)
# define PLL_BASE_ENABLE (1<<30)
# define PLL_BASE_REF_ENABLE (1<<29)
# define PLL_BASE_OVERRIDE (1<<28)
# define PLL_BASE_LOCK (1<<27)
# define PLL_BASE_DIVP_MASK (0x7<<20)
# define PLL_BASE_DIVP_SHIFT 20
# define PLL_BASE_DIVN_MASK (0x3FF<<8)
# define PLL_BASE_DIVN_SHIFT 8
# define PLL_BASE_DIVM_MASK (0x1F)
# define PLL_BASE_DIVM_SHIFT 0
# define PLL_OUT_RATIO_MASK (0xFF<<8)
# define PLL_OUT_RATIO_SHIFT 8
# define PLL_OUT_OVERRIDE (1<<2)
# define PLL_OUT_CLKEN (1<<1)
# define PLL_OUT_RESET_DISABLE (1<<0)
# define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
2010-06-08 11:49:46 +08:00
# define PLL_MISC_LOCK_ENABLE(c) (((c)->flags & PLLU) ? (1<<22) : (1<<18))
2010-01-29 08:40:29 +08:00
# define PLL_MISC_DCCON_SHIFT 20
# define PLL_MISC_CPCON_SHIFT 8
# define PLL_MISC_CPCON_MASK (0xF<<PLL_MISC_CPCON_SHIFT)
# define PLL_MISC_LFCON_SHIFT 4
# define PLL_MISC_LFCON_MASK (0xF<<PLL_MISC_LFCON_SHIFT)
# define PLL_MISC_VCOCON_SHIFT 0
# define PLL_MISC_VCOCON_MASK (0xF<<PLL_MISC_VCOCON_SHIFT)
2010-06-08 11:49:46 +08:00
# define PLLU_BASE_POST_DIV (1<<20)
2010-01-29 08:40:29 +08:00
# define PLLD_MISC_CLKENABLE (1<<30)
# define PLLD_MISC_DIV_RST (1<<23)
# define PLLD_MISC_DCCON_SHIFT 12
2010-09-27 17:26:32 +08:00
# define PLLE_MISC_READY (1 << 15)
2010-01-29 08:40:29 +08:00
# define PERIPH_CLK_TO_ENB_REG(c) ((c->clk_num / 32) * 4)
# define PERIPH_CLK_TO_ENB_SET_REG(c) ((c->clk_num / 32) * 8)
# define PERIPH_CLK_TO_ENB_BIT(c) (1 << (c->clk_num % 32))
# define SUPER_CLK_MUX 0x00
# define SUPER_STATE_SHIFT 28
# define SUPER_STATE_MASK (0xF << SUPER_STATE_SHIFT)
# define SUPER_STATE_STANDBY (0x0 << SUPER_STATE_SHIFT)
# define SUPER_STATE_IDLE (0x1 << SUPER_STATE_SHIFT)
# define SUPER_STATE_RUN (0x2 << SUPER_STATE_SHIFT)
# define SUPER_STATE_IRQ (0x3 << SUPER_STATE_SHIFT)
# define SUPER_STATE_FIQ (0x4 << SUPER_STATE_SHIFT)
# define SUPER_SOURCE_MASK 0xF
# define SUPER_FIQ_SOURCE_SHIFT 12
# define SUPER_IRQ_SOURCE_SHIFT 8
# define SUPER_RUN_SOURCE_SHIFT 4
# define SUPER_IDLE_SOURCE_SHIFT 0
# define SUPER_CLK_DIVIDER 0x04
# define BUS_CLK_DISABLE (1<<3)
# define BUS_CLK_DIV_MASK 0x3
static void __iomem * reg_clk_base = IO_ADDRESS ( TEGRA_CLK_RESET_BASE ) ;
# define clk_writel(value, reg) \
__raw_writel ( value , ( u32 ) reg_clk_base + ( reg ) )
# define clk_readl(reg) \
__raw_readl ( ( u32 ) reg_clk_base + ( reg ) )
unsigned long clk_measure_input_freq ( void )
{
u32 clock_autodetect ;
clk_writel ( OSC_FREQ_DET_TRIG | 1 , OSC_FREQ_DET ) ;
do { } while ( clk_readl ( OSC_FREQ_DET_STATUS ) & OSC_FREQ_DET_BUSY ) ;
clock_autodetect = clk_readl ( OSC_FREQ_DET_STATUS ) ;
if ( clock_autodetect > = 732 - 3 & & clock_autodetect < = 732 + 3 ) {
return 12000000 ;
} else if ( clock_autodetect > = 794 - 3 & & clock_autodetect < = 794 + 3 ) {
return 13000000 ;
} else if ( clock_autodetect > = 1172 - 3 & & clock_autodetect < = 1172 + 3 ) {
return 19200000 ;
} else if ( clock_autodetect > = 1587 - 3 & & clock_autodetect < = 1587 + 3 ) {
return 26000000 ;
} else {
pr_err ( " %s: Unexpected clock autodetect value %d " , __func__ , clock_autodetect ) ;
BUG ( ) ;
return 0 ;
}
}
2010-06-08 11:49:46 +08:00
static int clk_div71_get_divider ( unsigned long parent_rate , unsigned long rate )
2010-01-29 08:40:29 +08:00
{
2010-06-08 11:49:46 +08:00
s64 divider_u71 = parent_rate * 2 ;
divider_u71 + = rate - 1 ;
do_div ( divider_u71 , rate ) ;
2010-01-29 08:40:29 +08:00
2010-06-08 11:49:46 +08:00
if ( divider_u71 - 2 < 0 )
return 0 ;
2010-01-29 08:40:29 +08:00
2010-06-08 11:49:46 +08:00
if ( divider_u71 - 2 > 255 )
2010-01-29 08:40:29 +08:00
return - EINVAL ;
return divider_u71 - 2 ;
}
2010-06-08 11:49:46 +08:00
static int clk_div16_get_divider ( unsigned long parent_rate , unsigned long rate )
2010-01-29 08:40:29 +08:00
{
2010-06-08 11:49:46 +08:00
s64 divider_u16 ;
2010-01-29 08:40:29 +08:00
2010-06-08 11:49:46 +08:00
divider_u16 = parent_rate ;
divider_u16 + = rate - 1 ;
do_div ( divider_u16 , rate ) ;
2010-01-29 08:40:29 +08:00
2010-06-08 11:49:46 +08:00
if ( divider_u16 - 1 < 0 )
return 0 ;
if ( divider_u16 - 1 > 255 )
return - EINVAL ;
return divider_u16 - 1 ;
}
2010-01-29 08:40:29 +08:00
/* clk_m functions */
static unsigned long tegra2_clk_m_autodetect_rate ( struct clk * c )
{
u32 auto_clock_control = clk_readl ( OSC_CTRL ) & ~ OSC_CTRL_OSC_FREQ_MASK ;
c - > rate = clk_measure_input_freq ( ) ;
switch ( c - > rate ) {
case 12000000 :
auto_clock_control | = OSC_CTRL_OSC_FREQ_12MHZ ;
break ;
case 13000000 :
auto_clock_control | = OSC_CTRL_OSC_FREQ_13MHZ ;
break ;
case 19200000 :
auto_clock_control | = OSC_CTRL_OSC_FREQ_19_2MHZ ;
break ;
case 26000000 :
auto_clock_control | = OSC_CTRL_OSC_FREQ_26MHZ ;
break ;
default :
pr_err ( " %s: Unexpected clock rate %ld " , __func__ , c - > rate ) ;
BUG ( ) ;
}
clk_writel ( auto_clock_control , OSC_CTRL ) ;
return c - > rate ;
}
static void tegra2_clk_m_init ( struct clk * c )
{
pr_debug ( " %s on clock %s \n " , __func__ , c - > name ) ;
tegra2_clk_m_autodetect_rate ( c ) ;
}
static int tegra2_clk_m_enable ( struct clk * c )
{
pr_debug ( " %s on clock %s \n " , __func__ , c - > name ) ;
return 0 ;
}
static void tegra2_clk_m_disable ( struct clk * c )
{
pr_debug ( " %s on clock %s \n " , __func__ , c - > name ) ;
BUG ( ) ;
}
static struct clk_ops tegra_clk_m_ops = {
. init = tegra2_clk_m_init ,
. enable = tegra2_clk_m_enable ,
. disable = tegra2_clk_m_disable ,
} ;
/* super clock functions */
/* "super clocks" on tegra have two-stage muxes and a clock skipping
* super divider . We will ignore the clock skipping divider , since we
* can ' t lower the voltage when using the clock skip , but we can if we
* lower the PLL frequency .
*/
static void tegra2_super_clk_init ( struct clk * c )
{
u32 val ;
int source ;
int shift ;
const struct clk_mux_sel * sel ;
val = clk_readl ( c - > reg + SUPER_CLK_MUX ) ;
c - > state = ON ;
BUG_ON ( ( ( val & SUPER_STATE_MASK ) ! = SUPER_STATE_RUN ) & &
( ( val & SUPER_STATE_MASK ) ! = SUPER_STATE_IDLE ) ) ;
shift = ( ( val & SUPER_STATE_MASK ) = = SUPER_STATE_IDLE ) ?
SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT ;
source = ( val > > shift ) & SUPER_SOURCE_MASK ;
for ( sel = c - > inputs ; sel - > input ! = NULL ; sel + + ) {
if ( sel - > value = = source )
break ;
}
BUG_ON ( sel - > input = = NULL ) ;
c - > parent = sel - > input ;
}
static int tegra2_super_clk_enable ( struct clk * c )
{
clk_writel ( 0 , c - > reg + SUPER_CLK_DIVIDER ) ;
return 0 ;
}
static void tegra2_super_clk_disable ( struct clk * c )
{
pr_debug ( " %s on clock %s \n " , __func__ , c - > name ) ;
/* oops - don't disable the CPU clock! */
BUG ( ) ;
}
static int tegra2_super_clk_set_parent ( struct clk * c , struct clk * p )
{
u32 val ;
const struct clk_mux_sel * sel ;
int shift ;
2010-06-08 11:49:46 +08:00
2010-01-29 08:40:29 +08:00
val = clk_readl ( c - > reg + SUPER_CLK_MUX ) ; ;
BUG_ON ( ( ( val & SUPER_STATE_MASK ) ! = SUPER_STATE_RUN ) & &
( ( val & SUPER_STATE_MASK ) ! = SUPER_STATE_IDLE ) ) ;
shift = ( ( val & SUPER_STATE_MASK ) = = SUPER_STATE_IDLE ) ?
SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT ;
for ( sel = c - > inputs ; sel - > input ! = NULL ; sel + + ) {
if ( sel - > input = = p ) {
val & = ~ ( SUPER_SOURCE_MASK < < shift ) ;
val | = sel - > value < < shift ;
2010-06-08 11:49:46 +08:00
if ( c - > refcnt )
clk_enable_locked ( p ) ;
2010-01-29 08:40:29 +08:00
clk_writel ( val , c - > reg ) ;
2010-06-08 11:49:46 +08:00
if ( c - > refcnt & & c - > parent )
clk_disable_locked ( c - > parent ) ;
clk_reparent ( c , p ) ;
2010-01-29 08:40:29 +08:00
return 0 ;
}
}
return - EINVAL ;
}
static struct clk_ops tegra_super_ops = {
. init = tegra2_super_clk_init ,
. enable = tegra2_super_clk_enable ,
. disable = tegra2_super_clk_disable ,
. set_parent = tegra2_super_clk_set_parent ,
2010-06-08 11:49:46 +08:00
} ;
/* virtual cpu clock functions */
/* some clocks can not be stopped (cpu, memory bus) while the SoC is running.
To change the frequency of these clocks , the parent pll may need to be
reprogrammed , so the clock must be moved off the pll , the pll reprogrammed ,
and then the clock moved back to the pll . To hide this sequence , a virtual
clock handles it .
*/
static void tegra2_cpu_clk_init ( struct clk * c )
{
}
static int tegra2_cpu_clk_enable ( struct clk * c )
{
return 0 ;
}
static void tegra2_cpu_clk_disable ( struct clk * c )
{
pr_debug ( " %s on clock %s \n " , __func__ , c - > name ) ;
/* oops - don't disable the CPU clock! */
BUG ( ) ;
}
static int tegra2_cpu_clk_set_rate ( struct clk * c , unsigned long rate )
{
int ret ;
ret = clk_set_parent_locked ( c - > parent , c - > backup ) ;
if ( ret ) {
pr_err ( " Failed to switch cpu to clock %s \n " , c - > backup - > name ) ;
return ret ;
}
ret = clk_set_rate_locked ( c - > main , rate ) ;
if ( ret ) {
pr_err ( " Failed to change cpu pll to %lu \n " , rate ) ;
return ret ;
}
ret = clk_set_parent_locked ( c - > parent , c - > main ) ;
if ( ret ) {
pr_err ( " Failed to switch cpu to clock %s \n " , c - > main - > name ) ;
return ret ;
}
return 0 ;
}
static struct clk_ops tegra_cpu_ops = {
. init = tegra2_cpu_clk_init ,
. enable = tegra2_cpu_clk_enable ,
. disable = tegra2_cpu_clk_disable ,
. set_rate = tegra2_cpu_clk_set_rate ,
2010-01-29 08:40:29 +08:00
} ;
/* bus clock functions */
static void tegra2_bus_clk_init ( struct clk * c )
{
u32 val = clk_readl ( c - > reg ) ;
c - > state = ( ( val > > c - > reg_shift ) & BUS_CLK_DISABLE ) ? OFF : ON ;
c - > div = ( ( val > > c - > reg_shift ) & BUS_CLK_DIV_MASK ) + 1 ;
c - > mul = 1 ;
}
static int tegra2_bus_clk_enable ( struct clk * c )
{
u32 val = clk_readl ( c - > reg ) ;
val & = ~ ( BUS_CLK_DISABLE < < c - > reg_shift ) ;
clk_writel ( val , c - > reg ) ;
return 0 ;
}
static void tegra2_bus_clk_disable ( struct clk * c )
{
u32 val = clk_readl ( c - > reg ) ;
val | = BUS_CLK_DISABLE < < c - > reg_shift ;
clk_writel ( val , c - > reg ) ;
}
static int tegra2_bus_clk_set_rate ( struct clk * c , unsigned long rate )
{
u32 val = clk_readl ( c - > reg ) ;
unsigned long parent_rate = c - > parent - > rate ;
int i ;
for ( i = 1 ; i < = 4 ; i + + ) {
if ( rate = = parent_rate / i ) {
val & = ~ ( BUS_CLK_DIV_MASK < < c - > reg_shift ) ;
val | = ( i - 1 ) < < c - > reg_shift ;
clk_writel ( val , c - > reg ) ;
c - > div = i ;
c - > mul = 1 ;
return 0 ;
}
}
return - EINVAL ;
}
static struct clk_ops tegra_bus_ops = {
. init = tegra2_bus_clk_init ,
. enable = tegra2_bus_clk_enable ,
. disable = tegra2_bus_clk_disable ,
. set_rate = tegra2_bus_clk_set_rate ,
} ;
/* PLL Functions */
static int tegra2_pll_clk_wait_for_lock ( struct clk * c )
{
ktime_t before ;
before = ktime_get ( ) ;
2010-06-08 11:49:46 +08:00
2010-01-29 08:40:29 +08:00
while ( ! ( clk_readl ( c - > reg + PLL_BASE ) & PLL_BASE_LOCK ) ) {
if ( ktime_us_delta ( ktime_get ( ) , before ) > 5000 ) {
pr_err ( " Timed out waiting for lock bit on pll %s " ,
c - > name ) ;
return - 1 ;
}
}
return 0 ;
}
static void tegra2_pll_clk_init ( struct clk * c )
{
u32 val = clk_readl ( c - > reg + PLL_BASE ) ;
c - > state = ( val & PLL_BASE_ENABLE ) ? ON : OFF ;
if ( c - > flags & PLL_FIXED & & ! ( val & PLL_BASE_OVERRIDE ) ) {
pr_warning ( " Clock %s has unknown fixed frequency \n " , c - > name ) ;
2010-06-08 11:49:46 +08:00
c - > mul = 1 ;
c - > div = 1 ;
2010-01-29 08:40:29 +08:00
} else if ( val & PLL_BASE_BYPASS ) {
2010-06-08 11:49:46 +08:00
c - > mul = 1 ;
c - > div = 1 ;
2010-01-29 08:40:29 +08:00
} else {
2010-06-08 11:49:46 +08:00
c - > mul = ( val & PLL_BASE_DIVN_MASK ) > > PLL_BASE_DIVN_SHIFT ;
c - > div = ( val & PLL_BASE_DIVM_MASK ) > > PLL_BASE_DIVM_SHIFT ;
if ( c - > flags & PLLU )
c - > div * = ( val & PLLU_BASE_POST_DIV ) ? 1 : 2 ;
else
c - > div * = ( val & PLL_BASE_DIVP_MASK ) ? 2 : 1 ;
2010-01-29 08:40:29 +08:00
}
}
static int tegra2_pll_clk_enable ( struct clk * c )
{
u32 val ;
pr_debug ( " %s on clock %s \n " , __func__ , c - > name ) ;
val = clk_readl ( c - > reg + PLL_BASE ) ;
val & = ~ PLL_BASE_BYPASS ;
val | = PLL_BASE_ENABLE ;
clk_writel ( val , c - > reg + PLL_BASE ) ;
val = clk_readl ( c - > reg + PLL_MISC ( c ) ) ;
2010-06-08 11:49:46 +08:00
val | = PLL_MISC_LOCK_ENABLE ( c ) ;
2010-01-29 08:40:29 +08:00
clk_writel ( val , c - > reg + PLL_MISC ( c ) ) ;
tegra2_pll_clk_wait_for_lock ( c ) ;
return 0 ;
}
static void tegra2_pll_clk_disable ( struct clk * c )
{
u32 val ;
pr_debug ( " %s on clock %s \n " , __func__ , c - > name ) ;
val = clk_readl ( c - > reg ) ;
val & = ~ ( PLL_BASE_BYPASS | PLL_BASE_ENABLE ) ;
clk_writel ( val , c - > reg ) ;
}
static int tegra2_pll_clk_set_rate ( struct clk * c , unsigned long rate )
{
u32 val ;
unsigned long input_rate ;
const struct clk_pll_table * sel ;
pr_debug ( " %s: %s %lu \n " , __func__ , c - > name , rate ) ;
BUG_ON ( c - > refcnt ! = 0 ) ;
input_rate = c - > parent - > rate ;
for ( sel = c - > pll_table ; sel - > input_rate ! = 0 ; sel + + ) {
if ( sel - > input_rate = = input_rate & & sel - > output_rate = = rate ) {
2010-06-08 11:49:46 +08:00
c - > mul = sel - > n ;
c - > div = sel - > m * sel - > p ;
2010-01-29 08:40:29 +08:00
val = clk_readl ( c - > reg + PLL_BASE ) ;
if ( c - > flags & PLL_FIXED )
val | = PLL_BASE_OVERRIDE ;
val & = ~ ( PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK |
PLL_BASE_DIVM_MASK ) ;
2010-06-08 11:49:46 +08:00
val | = ( sel - > m < < PLL_BASE_DIVM_SHIFT ) |
( sel - > n < < PLL_BASE_DIVN_SHIFT ) ;
BUG_ON ( sel - > p < 1 | | sel - > p > 2 ) ;
if ( c - > flags & PLLU ) {
if ( sel - > p = = 1 )
val | = PLLU_BASE_POST_DIV ;
} else {
if ( sel - > p = = 2 )
val | = 1 < < PLL_BASE_DIVP_SHIFT ;
}
2010-01-29 08:40:29 +08:00
clk_writel ( val , c - > reg + PLL_BASE ) ;
if ( c - > flags & PLL_HAS_CPCON ) {
2010-06-08 11:49:46 +08:00
val = clk_readl ( c - > reg + PLL_MISC ( c ) ) ;
val & = ~ PLL_MISC_CPCON_MASK ;
val | = sel - > cpcon < < PLL_MISC_CPCON_SHIFT ;
2010-01-29 08:40:29 +08:00
clk_writel ( val , c - > reg + PLL_MISC ( c ) ) ;
}
if ( c - > state = = ON )
tegra2_pll_clk_enable ( c ) ;
return 0 ;
}
}
return - EINVAL ;
}
static struct clk_ops tegra_pll_ops = {
. init = tegra2_pll_clk_init ,
. enable = tegra2_pll_clk_enable ,
. disable = tegra2_pll_clk_disable ,
. set_rate = tegra2_pll_clk_set_rate ,
2010-06-08 11:49:46 +08:00
} ;
static void tegra2_pllx_clk_init ( struct clk * c )
{
tegra2_pll_clk_init ( c ) ;
if ( tegra_sku_id ( ) = = 7 )
c - > max_rate = 750000000 ;
}
static struct clk_ops tegra_pllx_ops = {
. init = tegra2_pllx_clk_init ,
. enable = tegra2_pll_clk_enable ,
. disable = tegra2_pll_clk_disable ,
. set_rate = tegra2_pll_clk_set_rate ,
2010-01-29 08:40:29 +08:00
} ;
2010-09-27 17:26:32 +08:00
static int tegra2_plle_clk_enable ( struct clk * c )
{
u32 val ;
pr_debug ( " %s on clock %s \n " , __func__ , c - > name ) ;
mdelay ( 1 ) ;
val = clk_readl ( c - > reg + PLL_BASE ) ;
if ( ! ( val & PLLE_MISC_READY ) )
return - EBUSY ;
val = clk_readl ( c - > reg + PLL_BASE ) ;
val | = PLL_BASE_ENABLE | PLL_BASE_BYPASS ;
clk_writel ( val , c - > reg + PLL_BASE ) ;
return 0 ;
}
static struct clk_ops tegra_plle_ops = {
. init = tegra2_pll_clk_init ,
. enable = tegra2_plle_clk_enable ,
. set_rate = tegra2_pll_clk_set_rate ,
} ;
2010-01-29 08:40:29 +08:00
/* Clock divider ops */
static void tegra2_pll_div_clk_init ( struct clk * c )
{
u32 val = clk_readl ( c - > reg ) ;
u32 divu71 ;
val > > = c - > reg_shift ;
c - > state = ( val & PLL_OUT_CLKEN ) ? ON : OFF ;
if ( ! ( val & PLL_OUT_RESET_DISABLE ) )
c - > state = OFF ;
if ( c - > flags & DIV_U71 ) {
divu71 = ( val & PLL_OUT_RATIO_MASK ) > > PLL_OUT_RATIO_SHIFT ;
c - > div = ( divu71 + 2 ) ;
c - > mul = 2 ;
} else if ( c - > flags & DIV_2 ) {
c - > div = 2 ;
c - > mul = 1 ;
} else {
c - > div = 1 ;
c - > mul = 1 ;
}
}
static int tegra2_pll_div_clk_enable ( struct clk * c )
{
u32 val ;
u32 new_val ;
pr_debug ( " %s: %s \n " , __func__ , c - > name ) ;
if ( c - > flags & DIV_U71 ) {
val = clk_readl ( c - > reg ) ;
new_val = val > > c - > reg_shift ;
new_val & = 0xFFFF ;
new_val | = PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE ;
val & = ~ ( 0xFFFF < < c - > reg_shift ) ;
val | = new_val < < c - > reg_shift ;
clk_writel ( val , c - > reg ) ;
return 0 ;
} else if ( c - > flags & DIV_2 ) {
BUG_ON ( ! ( c - > flags & PLLD ) ) ;
val = clk_readl ( c - > reg ) ;
val & = ~ PLLD_MISC_DIV_RST ;
clk_writel ( val , c - > reg ) ;
return 0 ;
}
return - EINVAL ;
}
static void tegra2_pll_div_clk_disable ( struct clk * c )
{
u32 val ;
u32 new_val ;
pr_debug ( " %s: %s \n " , __func__ , c - > name ) ;
if ( c - > flags & DIV_U71 ) {
val = clk_readl ( c - > reg ) ;
new_val = val > > c - > reg_shift ;
new_val & = 0xFFFF ;
new_val & = ~ ( PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE ) ;
val & = ~ ( 0xFFFF < < c - > reg_shift ) ;
val | = new_val < < c - > reg_shift ;
clk_writel ( val , c - > reg ) ;
} else if ( c - > flags & DIV_2 ) {
BUG_ON ( ! ( c - > flags & PLLD ) ) ;
val = clk_readl ( c - > reg ) ;
val | = PLLD_MISC_DIV_RST ;
clk_writel ( val , c - > reg ) ;
}
}
static int tegra2_pll_div_clk_set_rate ( struct clk * c , unsigned long rate )
{
u32 val ;
u32 new_val ;
int divider_u71 ;
pr_debug ( " %s: %s %lu \n " , __func__ , c - > name , rate ) ;
if ( c - > flags & DIV_U71 ) {
2010-06-08 11:49:46 +08:00
divider_u71 = clk_div71_get_divider ( c - > parent - > rate , rate ) ;
2010-01-29 08:40:29 +08:00
if ( divider_u71 > = 0 ) {
val = clk_readl ( c - > reg ) ;
new_val = val > > c - > reg_shift ;
new_val & = 0xFFFF ;
if ( c - > flags & DIV_U71_FIXED )
new_val | = PLL_OUT_OVERRIDE ;
new_val & = ~ PLL_OUT_RATIO_MASK ;
new_val | = divider_u71 < < PLL_OUT_RATIO_SHIFT ;
val & = ~ ( 0xFFFF < < c - > reg_shift ) ;
val | = new_val < < c - > reg_shift ;
clk_writel ( val , c - > reg ) ;
c - > div = divider_u71 + 2 ;
c - > mul = 2 ;
return 0 ;
}
} else if ( c - > flags & DIV_2 ) {
2010-06-08 11:49:46 +08:00
if ( c - > parent - > rate = = rate * 2 )
2010-01-29 08:40:29 +08:00
return 0 ;
}
return - EINVAL ;
}
2010-06-08 11:49:46 +08:00
static long tegra2_pll_div_clk_round_rate ( struct clk * c , unsigned long rate )
{
int divider ;
pr_debug ( " %s: %s %lu \n " , __func__ , c - > name , rate ) ;
if ( c - > flags & DIV_U71 ) {
divider = clk_div71_get_divider ( c - > parent - > rate , rate ) ;
if ( divider < 0 )
return divider ;
return c - > parent - > rate * 2 / ( divider + 2 ) ;
} else if ( c - > flags & DIV_2 ) {
return c - > parent - > rate / 2 ;
}
return - EINVAL ;
}
2010-01-29 08:40:29 +08:00
static struct clk_ops tegra_pll_div_ops = {
. init = tegra2_pll_div_clk_init ,
. enable = tegra2_pll_div_clk_enable ,
. disable = tegra2_pll_div_clk_disable ,
. set_rate = tegra2_pll_div_clk_set_rate ,
2010-06-08 11:49:46 +08:00
. round_rate = tegra2_pll_div_clk_round_rate ,
2010-01-29 08:40:29 +08:00
} ;
/* Periph clk ops */
static void tegra2_periph_clk_init ( struct clk * c )
{
u32 val = clk_readl ( c - > reg ) ;
const struct clk_mux_sel * mux = 0 ;
const struct clk_mux_sel * sel ;
if ( c - > flags & MUX ) {
for ( sel = c - > inputs ; sel - > input ! = NULL ; sel + + ) {
if ( val > > PERIPH_CLK_SOURCE_SHIFT = = sel - > value )
mux = sel ;
}
BUG_ON ( ! mux ) ;
c - > parent = mux - > input ;
} else {
c - > parent = c - > inputs [ 0 ] . input ;
}
if ( c - > flags & DIV_U71 ) {
2010-06-08 11:49:46 +08:00
u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK ;
2010-01-29 08:40:29 +08:00
c - > div = divu71 + 2 ;
c - > mul = 2 ;
2010-06-08 11:49:46 +08:00
} else if ( c - > flags & DIV_U16 ) {
u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK ;
c - > div = divu16 + 1 ;
c - > mul = 1 ;
2010-01-29 08:40:29 +08:00
} else {
c - > div = 1 ;
c - > mul = 1 ;
}
c - > state = ON ;
if ( ! ( clk_readl ( CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG ( c ) ) &
PERIPH_CLK_TO_ENB_BIT ( c ) ) )
c - > state = OFF ;
if ( ! ( c - > flags & PERIPH_NO_RESET ) )
if ( clk_readl ( RST_DEVICES + PERIPH_CLK_TO_ENB_REG ( c ) ) &
PERIPH_CLK_TO_ENB_BIT ( c ) )
c - > state = OFF ;
}
static int tegra2_periph_clk_enable ( struct clk * c )
{
u32 val ;
pr_debug ( " %s on clock %s \n " , __func__ , c - > name ) ;
clk_writel ( PERIPH_CLK_TO_ENB_BIT ( c ) ,
CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG ( c ) ) ;
if ( ! ( c - > flags & PERIPH_NO_RESET ) & & ! ( c - > flags & PERIPH_MANUAL_RESET ) )
clk_writel ( PERIPH_CLK_TO_ENB_BIT ( c ) ,
RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG ( c ) ) ;
if ( c - > flags & PERIPH_EMC_ENB ) {
/* The EMC peripheral clock has 2 extra enable bits */
/* FIXME: Do they need to be disabled? */
val = clk_readl ( c - > reg ) ;
val | = 0x3 < < 24 ;
clk_writel ( val , c - > reg ) ;
}
return 0 ;
}
static void tegra2_periph_clk_disable ( struct clk * c )
{
pr_debug ( " %s on clock %s \n " , __func__ , c - > name ) ;
clk_writel ( PERIPH_CLK_TO_ENB_BIT ( c ) ,
CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG ( c ) ) ;
}
void tegra2_periph_reset_deassert ( struct clk * c )
{
pr_debug ( " %s on clock %s \n " , __func__ , c - > name ) ;
if ( ! ( c - > flags & PERIPH_NO_RESET ) )
clk_writel ( PERIPH_CLK_TO_ENB_BIT ( c ) ,
RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG ( c ) ) ;
}
void tegra2_periph_reset_assert ( struct clk * c )
{
pr_debug ( " %s on clock %s \n " , __func__ , c - > name ) ;
if ( ! ( c - > flags & PERIPH_NO_RESET ) )
clk_writel ( PERIPH_CLK_TO_ENB_BIT ( c ) ,
RST_DEVICES_SET + PERIPH_CLK_TO_ENB_SET_REG ( c ) ) ;
}
static int tegra2_periph_clk_set_parent ( struct clk * c , struct clk * p )
{
u32 val ;
const struct clk_mux_sel * sel ;
pr_debug ( " %s: %s %s \n " , __func__ , c - > name , p - > name ) ;
for ( sel = c - > inputs ; sel - > input ! = NULL ; sel + + ) {
if ( sel - > input = = p ) {
val = clk_readl ( c - > reg ) ;
val & = ~ PERIPH_CLK_SOURCE_MASK ;
val | = ( sel - > value ) < < PERIPH_CLK_SOURCE_SHIFT ;
2010-06-08 11:49:46 +08:00
if ( c - > refcnt )
clk_enable_locked ( p ) ;
2010-01-29 08:40:29 +08:00
clk_writel ( val , c - > reg ) ;
2010-06-08 11:49:46 +08:00
if ( c - > refcnt & & c - > parent )
clk_disable_locked ( c - > parent ) ;
clk_reparent ( c , p ) ;
2010-01-29 08:40:29 +08:00
return 0 ;
}
}
return - EINVAL ;
}
static int tegra2_periph_clk_set_rate ( struct clk * c , unsigned long rate )
{
u32 val ;
2010-06-08 11:49:46 +08:00
int divider ;
2010-01-29 08:40:29 +08:00
pr_debug ( " %s: %lu \n " , __func__ , rate ) ;
if ( c - > flags & DIV_U71 ) {
2010-06-08 11:49:46 +08:00
divider = clk_div71_get_divider ( c - > parent - > rate , rate ) ;
if ( divider > = 0 ) {
2010-01-29 08:40:29 +08:00
val = clk_readl ( c - > reg ) ;
2010-06-08 11:49:46 +08:00
val & = ~ PERIPH_CLK_SOURCE_DIVU71_MASK ;
val | = divider ;
2010-01-29 08:40:29 +08:00
clk_writel ( val , c - > reg ) ;
2010-06-08 11:49:46 +08:00
c - > div = divider + 2 ;
2010-01-29 08:40:29 +08:00
c - > mul = 2 ;
return 0 ;
}
2010-06-08 11:49:46 +08:00
} else if ( c - > flags & DIV_U16 ) {
divider = clk_div16_get_divider ( c - > parent - > rate , rate ) ;
if ( divider > = 0 ) {
val = clk_readl ( c - > reg ) ;
val & = ~ PERIPH_CLK_SOURCE_DIVU16_MASK ;
val | = divider ;
clk_writel ( val , c - > reg ) ;
c - > div = divider + 1 ;
c - > mul = 1 ;
return 0 ;
}
} else if ( c - > parent - > rate < = rate ) {
c - > div = 1 ;
c - > mul = 1 ;
return 0 ;
}
return - EINVAL ;
}
static long tegra2_periph_clk_round_rate ( struct clk * c ,
unsigned long rate )
{
int divider ;
pr_debug ( " %s: %s %lu \n " , __func__ , c - > name , rate ) ;
if ( c - > flags & DIV_U71 ) {
divider = clk_div71_get_divider ( c - > parent - > rate , rate ) ;
if ( divider < 0 )
return divider ;
return c - > parent - > rate * 2 / ( divider + 2 ) ;
} else if ( c - > flags & DIV_U16 ) {
divider = clk_div16_get_divider ( c - > parent - > rate , rate ) ;
if ( divider < 0 )
return divider ;
return c - > parent - > rate / ( divider + 1 ) ;
2010-01-29 08:40:29 +08:00
}
return - EINVAL ;
}
static struct clk_ops tegra_periph_clk_ops = {
. init = & tegra2_periph_clk_init ,
. enable = & tegra2_periph_clk_enable ,
. disable = & tegra2_periph_clk_disable ,
. set_parent = & tegra2_periph_clk_set_parent ,
. set_rate = & tegra2_periph_clk_set_rate ,
2010-06-08 11:49:46 +08:00
. round_rate = & tegra2_periph_clk_round_rate ,
2010-01-29 08:40:29 +08:00
} ;
/* Clock doubler ops */
static void tegra2_clk_double_init ( struct clk * c )
{
c - > mul = 2 ;
c - > div = 1 ;
c - > state = ON ;
if ( ! ( clk_readl ( CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG ( c ) ) &
PERIPH_CLK_TO_ENB_BIT ( c ) ) )
c - > state = OFF ;
} ;
2010-06-08 11:49:46 +08:00
static int tegra2_clk_double_set_rate ( struct clk * c , unsigned long rate )
{
if ( rate ! = 2 * c - > parent - > rate )
return - EINVAL ;
c - > mul = 2 ;
c - > div = 1 ;
return 0 ;
}
2010-01-29 08:40:29 +08:00
static struct clk_ops tegra_clk_double_ops = {
. init = & tegra2_clk_double_init ,
. enable = & tegra2_periph_clk_enable ,
. disable = & tegra2_periph_clk_disable ,
2010-06-08 11:49:46 +08:00
. set_rate = & tegra2_clk_double_set_rate ,
} ;
static void tegra2_audio_sync_clk_init ( struct clk * c )
{
int source ;
const struct clk_mux_sel * sel ;
u32 val = clk_readl ( c - > reg ) ;
c - > state = ( val & ( 1 < < 4 ) ) ? OFF : ON ;
source = val & 0xf ;
for ( sel = c - > inputs ; sel - > input ! = NULL ; sel + + )
if ( sel - > value = = source )
break ;
BUG_ON ( sel - > input = = NULL ) ;
c - > parent = sel - > input ;
}
static int tegra2_audio_sync_clk_enable ( struct clk * c )
{
clk_writel ( 0 , c - > reg ) ;
return 0 ;
}
static void tegra2_audio_sync_clk_disable ( struct clk * c )
{
clk_writel ( 1 , c - > reg ) ;
}
static int tegra2_audio_sync_clk_set_parent ( struct clk * c , struct clk * p )
{
u32 val ;
const struct clk_mux_sel * sel ;
for ( sel = c - > inputs ; sel - > input ! = NULL ; sel + + ) {
if ( sel - > input = = p ) {
val = clk_readl ( c - > reg ) ;
val & = ~ 0xf ;
val | = sel - > value ;
if ( c - > refcnt )
clk_enable_locked ( p ) ;
clk_writel ( val , c - > reg ) ;
if ( c - > refcnt & & c - > parent )
clk_disable_locked ( c - > parent ) ;
clk_reparent ( c , p ) ;
return 0 ;
}
}
return - EINVAL ;
}
static int tegra2_audio_sync_clk_set_rate ( struct clk * c , unsigned long rate )
{
unsigned long parent_rate ;
if ( ! c - > parent ) {
pr_err ( " %s: clock has no parent \n " , __func__ ) ;
return - EINVAL ;
}
parent_rate = c - > parent - > rate ;
if ( rate ! = parent_rate ) {
pr_err ( " %s: %s/%ld differs from parent %s/%ld \n " ,
__func__ ,
c - > name , rate ,
c - > parent - > name , parent_rate ) ;
return - EINVAL ;
}
c - > rate = parent_rate ;
return 0 ;
}
static struct clk_ops tegra_audio_sync_clk_ops = {
. init = tegra2_audio_sync_clk_init ,
. enable = tegra2_audio_sync_clk_enable ,
. disable = tegra2_audio_sync_clk_disable ,
. set_rate = tegra2_audio_sync_clk_set_rate ,
. set_parent = tegra2_audio_sync_clk_set_parent ,
2010-01-29 08:40:29 +08:00
} ;
/* Clock definitions */
static struct clk tegra_clk_32k = {
. name = " clk_32k " ,
2010-06-08 11:49:46 +08:00
. rate = 32768 ,
2010-01-29 08:40:29 +08:00
. ops = NULL ,
2010-06-08 11:49:46 +08:00
. max_rate = 32768 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk_pll_table tegra_pll_s_table [ ] = {
{ 32768 , 12000000 , 366 , 1 , 1 , 0 } ,
{ 32768 , 13000000 , 397 , 1 , 1 , 0 } ,
{ 32768 , 19200000 , 586 , 1 , 1 , 0 } ,
{ 32768 , 26000000 , 793 , 1 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 } ,
} ;
static struct clk tegra_pll_s = {
. name = " pll_s " ,
. flags = PLL_ALT_MISC_REG ,
. ops = & tegra_pll_ops ,
. reg = 0xf0 ,
. input_min = 32768 ,
. input_max = 32768 ,
. parent = & tegra_clk_32k ,
. cf_min = 0 , /* FIXME */
. cf_max = 0 , /* FIXME */
. vco_min = 12000000 ,
. vco_max = 26000000 ,
. pll_table = tegra_pll_s_table ,
2010-06-08 11:49:46 +08:00
. max_rate = 26000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk_mux_sel tegra_clk_m_sel [ ] = {
{ . input = & tegra_clk_32k , . value = 0 } ,
{ . input = & tegra_pll_s , . value = 1 } ,
{ 0 , 0 } ,
} ;
static struct clk tegra_clk_m = {
. name = " clk_m " ,
. flags = ENABLE_ON_INIT ,
. ops = & tegra_clk_m_ops ,
. inputs = tegra_clk_m_sel ,
. reg = 0x1fc ,
. reg_mask = ( 1 < < 28 ) ,
. reg_shift = 28 ,
2010-06-08 11:49:46 +08:00
. max_rate = 26000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk_pll_table tegra_pll_c_table [ ] = {
{ 0 , 0 , 0 , 0 , 0 , 0 } ,
} ;
static struct clk tegra_pll_c = {
. name = " pll_c " ,
. flags = PLL_HAS_CPCON ,
. ops = & tegra_pll_ops ,
. reg = 0x80 ,
. input_min = 2000000 ,
. input_max = 31000000 ,
. parent = & tegra_clk_m ,
. cf_min = 1000000 ,
. cf_max = 6000000 ,
. vco_min = 20000000 ,
. vco_max = 1400000000 ,
. pll_table = tegra_pll_c_table ,
2010-06-08 11:49:46 +08:00
. max_rate = 600000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk tegra_pll_c_out1 = {
. name = " pll_c_out1 " ,
. ops = & tegra_pll_div_ops ,
. flags = DIV_U71 ,
. parent = & tegra_pll_c ,
. reg = 0x84 ,
. reg_shift = 0 ,
2010-06-08 11:49:46 +08:00
. max_rate = 600000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk_pll_table tegra_pll_m_table [ ] = {
2010-06-08 11:49:46 +08:00
{ 12000000 , 666000000 , 666 , 12 , 1 , 8 } ,
{ 13000000 , 666000000 , 666 , 13 , 1 , 8 } ,
{ 19200000 , 666000000 , 555 , 16 , 1 , 8 } ,
{ 26000000 , 666000000 , 666 , 26 , 1 , 8 } ,
{ 12000000 , 600000000 , 600 , 12 , 1 , 8 } ,
{ 13000000 , 600000000 , 600 , 13 , 1 , 8 } ,
{ 19200000 , 600000000 , 375 , 12 , 1 , 6 } ,
{ 26000000 , 600000000 , 600 , 26 , 1 , 8 } ,
2010-01-29 08:40:29 +08:00
{ 0 , 0 , 0 , 0 , 0 , 0 } ,
} ;
static struct clk tegra_pll_m = {
. name = " pll_m " ,
. flags = PLL_HAS_CPCON ,
. ops = & tegra_pll_ops ,
. reg = 0x90 ,
. input_min = 2000000 ,
. input_max = 31000000 ,
. parent = & tegra_clk_m ,
. cf_min = 1000000 ,
. cf_max = 6000000 ,
. vco_min = 20000000 ,
. vco_max = 1200000000 ,
. pll_table = tegra_pll_m_table ,
2010-06-08 11:49:46 +08:00
. max_rate = 800000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk tegra_pll_m_out1 = {
. name = " pll_m_out1 " ,
. ops = & tegra_pll_div_ops ,
. flags = DIV_U71 ,
. parent = & tegra_pll_m ,
. reg = 0x94 ,
. reg_shift = 0 ,
2010-06-08 11:49:46 +08:00
. max_rate = 600000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk_pll_table tegra_pll_p_table [ ] = {
{ 12000000 , 216000000 , 432 , 12 , 2 , 8 } ,
{ 13000000 , 216000000 , 432 , 13 , 2 , 8 } ,
{ 19200000 , 216000000 , 90 , 4 , 2 , 1 } ,
{ 26000000 , 216000000 , 432 , 26 , 2 , 8 } ,
{ 12000000 , 432000000 , 432 , 12 , 1 , 8 } ,
{ 13000000 , 432000000 , 432 , 13 , 1 , 8 } ,
{ 19200000 , 432000000 , 90 , 4 , 1 , 1 } ,
{ 26000000 , 432000000 , 432 , 26 , 1 , 8 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 } ,
} ;
static struct clk tegra_pll_p = {
. name = " pll_p " ,
. flags = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON ,
. ops = & tegra_pll_ops ,
. reg = 0xa0 ,
. input_min = 2000000 ,
. input_max = 31000000 ,
. parent = & tegra_clk_m ,
. cf_min = 1000000 ,
. cf_max = 6000000 ,
. vco_min = 20000000 ,
. vco_max = 1400000000 ,
. pll_table = tegra_pll_p_table ,
2010-06-08 11:49:46 +08:00
. max_rate = 432000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk tegra_pll_p_out1 = {
. name = " pll_p_out1 " ,
. ops = & tegra_pll_div_ops ,
. flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED ,
. parent = & tegra_pll_p ,
. reg = 0xa4 ,
. reg_shift = 0 ,
2010-06-08 11:49:46 +08:00
. max_rate = 432000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk tegra_pll_p_out2 = {
. name = " pll_p_out2 " ,
. ops = & tegra_pll_div_ops ,
. flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED ,
. parent = & tegra_pll_p ,
. reg = 0xa4 ,
. reg_shift = 16 ,
2010-06-08 11:49:46 +08:00
. max_rate = 432000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk tegra_pll_p_out3 = {
. name = " pll_p_out3 " ,
. ops = & tegra_pll_div_ops ,
. flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED ,
. parent = & tegra_pll_p ,
. reg = 0xa8 ,
. reg_shift = 0 ,
2010-06-08 11:49:46 +08:00
. max_rate = 432000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk tegra_pll_p_out4 = {
. name = " pll_p_out4 " ,
. ops = & tegra_pll_div_ops ,
. flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED ,
. parent = & tegra_pll_p ,
. reg = 0xa8 ,
. reg_shift = 16 ,
2010-06-08 11:49:46 +08:00
. max_rate = 432000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk_pll_table tegra_pll_a_table [ ] = {
{ 28800000 , 56448000 , 49 , 25 , 1 , 1 } ,
{ 28800000 , 73728000 , 64 , 25 , 1 , 1 } ,
{ 28800000 , 11289600 , 49 , 25 , 1 , 1 } ,
{ 28800000 , 12288000 , 64 , 25 , 1 , 1 } ,
2010-06-08 11:49:46 +08:00
{ 28800000 , 24000000 , 5 , 6 , 1 , 1 } ,
2010-01-29 08:40:29 +08:00
{ 0 , 0 , 0 , 0 , 0 , 0 } ,
} ;
static struct clk tegra_pll_a = {
. name = " pll_a " ,
. flags = PLL_HAS_CPCON ,
. ops = & tegra_pll_ops ,
. reg = 0xb0 ,
. input_min = 2000000 ,
. input_max = 31000000 ,
. parent = & tegra_pll_p_out1 ,
. cf_min = 1000000 ,
. cf_max = 6000000 ,
. vco_min = 20000000 ,
. vco_max = 1400000000 ,
. pll_table = tegra_pll_a_table ,
2010-06-08 11:49:46 +08:00
. max_rate = 56448000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk tegra_pll_a_out0 = {
. name = " pll_a_out0 " ,
. ops = & tegra_pll_div_ops ,
. flags = DIV_U71 ,
. parent = & tegra_pll_a ,
. reg = 0xb4 ,
. reg_shift = 0 ,
2010-06-08 11:49:46 +08:00
. max_rate = 56448000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk_pll_table tegra_pll_d_table [ ] = {
{ 12000000 , 1000000000 , 1000 , 12 , 1 , 12 } ,
{ 13000000 , 1000000000 , 1000 , 13 , 1 , 12 } ,
{ 19200000 , 1000000000 , 625 , 12 , 1 , 8 } ,
{ 26000000 , 1000000000 , 1000 , 26 , 1 , 12 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 } ,
} ;
static struct clk tegra_pll_d = {
. name = " pll_d " ,
. flags = PLL_HAS_CPCON | PLLD ,
. ops = & tegra_pll_ops ,
. reg = 0xd0 ,
. input_min = 2000000 ,
. input_max = 40000000 ,
. parent = & tegra_clk_m ,
. cf_min = 1000000 ,
. cf_max = 6000000 ,
. vco_min = 40000000 ,
. vco_max = 1000000000 ,
. pll_table = tegra_pll_d_table ,
2010-06-08 11:49:46 +08:00
. max_rate = 1000000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk tegra_pll_d_out0 = {
. name = " pll_d_out0 " ,
. ops = & tegra_pll_div_ops ,
. flags = DIV_2 | PLLD ,
. parent = & tegra_pll_d ,
2010-06-08 11:49:46 +08:00
. max_rate = 500000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk_pll_table tegra_pll_u_table [ ] = {
2010-06-08 11:49:46 +08:00
{ 12000000 , 480000000 , 960 , 12 , 2 , 0 } ,
{ 13000000 , 480000000 , 960 , 13 , 2 , 0 } ,
{ 19200000 , 480000000 , 200 , 4 , 2 , 0 } ,
{ 26000000 , 480000000 , 960 , 26 , 2 , 0 } ,
2010-01-29 08:40:29 +08:00
{ 0 , 0 , 0 , 0 , 0 , 0 } ,
} ;
static struct clk tegra_pll_u = {
. name = " pll_u " ,
2010-06-08 11:49:46 +08:00
. flags = PLLU ,
2010-01-29 08:40:29 +08:00
. ops = & tegra_pll_ops ,
. reg = 0xc0 ,
. input_min = 2000000 ,
. input_max = 40000000 ,
. parent = & tegra_clk_m ,
. cf_min = 1000000 ,
. cf_max = 6000000 ,
. vco_min = 480000000 ,
. vco_max = 960000000 ,
. pll_table = tegra_pll_u_table ,
2010-06-08 11:49:46 +08:00
. max_rate = 480000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk_pll_table tegra_pll_x_table [ ] = {
2010-06-08 11:49:46 +08:00
/* 1 GHz */
2010-01-29 08:40:29 +08:00
{ 12000000 , 1000000000 , 1000 , 12 , 1 , 12 } ,
{ 13000000 , 1000000000 , 1000 , 13 , 1 , 12 } ,
{ 19200000 , 1000000000 , 625 , 12 , 1 , 8 } ,
{ 26000000 , 1000000000 , 1000 , 26 , 1 , 12 } ,
2010-06-08 11:49:46 +08:00
/* 912 MHz */
{ 12000000 , 912000000 , 912 , 12 , 1 , 12 } ,
{ 13000000 , 912000000 , 912 , 13 , 1 , 12 } ,
{ 19200000 , 912000000 , 760 , 16 , 1 , 8 } ,
{ 26000000 , 912000000 , 912 , 26 , 1 , 12 } ,
/* 816 MHz */
{ 12000000 , 816000000 , 816 , 12 , 1 , 12 } ,
{ 13000000 , 816000000 , 816 , 13 , 1 , 12 } ,
{ 19200000 , 816000000 , 680 , 16 , 1 , 8 } ,
{ 26000000 , 816000000 , 816 , 26 , 1 , 12 } ,
/* 760 MHz */
{ 12000000 , 760000000 , 760 , 12 , 1 , 12 } ,
{ 13000000 , 760000000 , 760 , 13 , 1 , 12 } ,
{ 19200000 , 760000000 , 950 , 24 , 1 , 8 } ,
{ 26000000 , 760000000 , 760 , 26 , 1 , 12 } ,
/* 608 MHz */
{ 12000000 , 608000000 , 760 , 12 , 1 , 12 } ,
{ 13000000 , 608000000 , 760 , 13 , 1 , 12 } ,
{ 19200000 , 608000000 , 380 , 12 , 1 , 8 } ,
{ 26000000 , 608000000 , 760 , 26 , 1 , 12 } ,
/* 456 MHz */
{ 12000000 , 456000000 , 456 , 12 , 1 , 12 } ,
{ 13000000 , 456000000 , 456 , 13 , 1 , 12 } ,
{ 19200000 , 456000000 , 380 , 16 , 1 , 8 } ,
{ 26000000 , 456000000 , 456 , 26 , 1 , 12 } ,
/* 312 MHz */
{ 12000000 , 312000000 , 312 , 12 , 1 , 12 } ,
{ 13000000 , 312000000 , 312 , 13 , 1 , 12 } ,
{ 19200000 , 312000000 , 260 , 16 , 1 , 8 } ,
{ 26000000 , 312000000 , 312 , 26 , 1 , 12 } ,
2010-01-29 08:40:29 +08:00
{ 0 , 0 , 0 , 0 , 0 , 0 } ,
} ;
static struct clk tegra_pll_x = {
. name = " pll_x " ,
. flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG ,
2010-06-08 11:49:46 +08:00
. ops = & tegra_pllx_ops ,
2010-01-29 08:40:29 +08:00
. reg = 0xe0 ,
. input_min = 2000000 ,
. input_max = 31000000 ,
. parent = & tegra_clk_m ,
. cf_min = 1000000 ,
. cf_max = 6000000 ,
. vco_min = 20000000 ,
. vco_max = 1200000000 ,
. pll_table = tegra_pll_x_table ,
2010-06-08 11:49:46 +08:00
. max_rate = 1000000000 ,
2010-01-29 08:40:29 +08:00
} ;
2010-09-27 17:26:32 +08:00
static struct clk_pll_table tegra_pll_e_table [ ] = {
{ 12000000 , 100000000 , 200 , 24 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 } ,
} ;
static struct clk tegra_pll_e = {
. name = " pll_e " ,
. flags = PLL_ALT_MISC_REG ,
. ops = & tegra_plle_ops ,
. input_min = 12000000 ,
. input_max = 12000000 ,
. max_rate = 100000000 ,
. parent = & tegra_clk_m ,
. reg = 0xe8 ,
. pll_table = tegra_pll_e_table ,
} ;
2010-01-29 08:40:29 +08:00
static struct clk tegra_clk_d = {
. name = " clk_d " ,
. flags = PERIPH_NO_RESET ,
. ops = & tegra_clk_double_ops ,
. clk_num = 90 ,
. reg = 0x34 ,
. reg_shift = 12 ,
. parent = & tegra_clk_m ,
2010-06-08 11:49:46 +08:00
. max_rate = 52000000 ,
} ;
/* initialized before peripheral clocks */
static struct clk_mux_sel mux_audio_sync_clk [ 8 + 1 ] ;
static const struct audio_sources {
const char * name ;
int value ;
} mux_audio_sync_clk_sources [ ] = {
{ . name = " spdif_in " , . value = 0 } ,
{ . name = " i2s1 " , . value = 1 } ,
{ . name = " i2s2 " , . value = 2 } ,
{ . name = " pll_a_out0 " , . value = 4 } ,
#if 0 /* FIXME: not implemented */
{ . name = " ac97 " , . value = 3 } ,
{ . name = " ext_audio_clk2 " , . value = 5 } ,
{ . name = " ext_audio_clk1 " , . value = 6 } ,
{ . name = " ext_vimclk " , . value = 7 } ,
# endif
{ 0 , 0 }
} ;
static struct clk tegra_clk_audio = {
. name = " audio " ,
. inputs = mux_audio_sync_clk ,
. reg = 0x38 ,
. max_rate = 24000000 ,
. ops = & tegra_audio_sync_clk_ops
2010-01-29 08:40:29 +08:00
} ;
static struct clk tegra_clk_audio_2x = {
2010-06-08 11:49:46 +08:00
. name = " audio_2x " ,
2010-01-29 08:40:29 +08:00
. flags = PERIPH_NO_RESET ,
2010-06-08 11:49:46 +08:00
. max_rate = 48000000 ,
2010-01-29 08:40:29 +08:00
. ops = & tegra_clk_double_ops ,
. clk_num = 89 ,
. reg = 0x34 ,
. reg_shift = 8 ,
2010-06-08 11:49:46 +08:00
. parent = & tegra_clk_audio ,
} ;
struct clk_lookup tegra_audio_clk_lookups [ ] = {
{ . con_id = " audio " , . clk = & tegra_clk_audio } ,
{ . con_id = " audio_2x " , . clk = & tegra_clk_audio_2x }
} ;
/* This is called after peripheral clocks are initialized, as the
* audio_sync clock depends on some of the peripheral clocks .
*/
static void init_audio_sync_clock_mux ( void )
{
int i ;
struct clk_mux_sel * sel = mux_audio_sync_clk ;
const struct audio_sources * src = mux_audio_sync_clk_sources ;
struct clk_lookup * lookup ;
for ( i = 0 ; src - > name ; i + + , sel + + , src + + ) {
sel - > input = tegra_get_clock_by_name ( src - > name ) ;
if ( ! sel - > input )
pr_err ( " %s: could not find clk %s \n " , __func__ ,
src - > name ) ;
sel - > value = src - > value ;
}
lookup = tegra_audio_clk_lookups ;
for ( i = 0 ; i < ARRAY_SIZE ( tegra_audio_clk_lookups ) ; i + + , lookup + + ) {
clk_init ( lookup - > clk ) ;
clkdev_add ( lookup ) ;
}
2010-01-29 08:40:29 +08:00
}
static struct clk_mux_sel mux_cclk [ ] = {
{ . input = & tegra_clk_m , . value = 0 } ,
{ . input = & tegra_pll_c , . value = 1 } ,
{ . input = & tegra_clk_32k , . value = 2 } ,
{ . input = & tegra_pll_m , . value = 3 } ,
{ . input = & tegra_pll_p , . value = 4 } ,
{ . input = & tegra_pll_p_out4 , . value = 5 } ,
{ . input = & tegra_pll_p_out3 , . value = 6 } ,
{ . input = & tegra_clk_d , . value = 7 } ,
{ . input = & tegra_pll_x , . value = 8 } ,
{ 0 , 0 } ,
} ;
static struct clk_mux_sel mux_sclk [ ] = {
{ . input = & tegra_clk_m , . value = 0 } ,
{ . input = & tegra_pll_c_out1 , . value = 1 } ,
{ . input = & tegra_pll_p_out4 , . value = 2 } ,
{ . input = & tegra_pll_p_out3 , . value = 3 } ,
{ . input = & tegra_pll_p_out2 , . value = 4 } ,
{ . input = & tegra_clk_d , . value = 5 } ,
{ . input = & tegra_clk_32k , . value = 6 } ,
{ . input = & tegra_pll_m_out1 , . value = 7 } ,
{ 0 , 0 } ,
} ;
2010-06-08 11:49:46 +08:00
static struct clk tegra_clk_cclk = {
. name = " cclk " ,
2010-01-29 08:40:29 +08:00
. inputs = mux_cclk ,
. reg = 0x20 ,
. ops = & tegra_super_ops ,
2010-06-08 11:49:46 +08:00
. max_rate = 1000000000 ,
2010-01-29 08:40:29 +08:00
} ;
2010-06-08 11:49:46 +08:00
static struct clk tegra_clk_sclk = {
. name = " sclk " ,
2010-01-29 08:40:29 +08:00
. inputs = mux_sclk ,
. reg = 0x28 ,
. ops = & tegra_super_ops ,
2010-06-08 11:49:46 +08:00
. max_rate = 600000000 ,
} ;
static struct clk tegra_clk_virtual_cpu = {
. name = " cpu " ,
. parent = & tegra_clk_cclk ,
. main = & tegra_pll_x ,
. backup = & tegra_clk_m ,
. ops = & tegra_cpu_ops ,
. max_rate = 1000000000 ,
. dvfs = & tegra_dvfs_virtual_cpu_dvfs ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk tegra_clk_hclk = {
. name = " hclk " ,
. flags = DIV_BUS ,
2010-06-08 11:49:46 +08:00
. parent = & tegra_clk_sclk ,
2010-01-29 08:40:29 +08:00
. reg = 0x30 ,
. reg_shift = 4 ,
. ops = & tegra_bus_ops ,
2010-06-08 11:49:46 +08:00
. max_rate = 240000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk tegra_clk_pclk = {
. name = " pclk " ,
. flags = DIV_BUS ,
. parent = & tegra_clk_hclk ,
. reg = 0x30 ,
. reg_shift = 0 ,
. ops = & tegra_bus_ops ,
2010-06-08 11:49:46 +08:00
. max_rate = 108000000 ,
2010-01-29 08:40:29 +08:00
} ;
static struct clk_mux_sel mux_pllm_pllc_pllp_plla [ ] = {
{ . input = & tegra_pll_m , . value = 0 } ,
{ . input = & tegra_pll_c , . value = 1 } ,
{ . input = & tegra_pll_p , . value = 2 } ,
{ . input = & tegra_pll_a_out0 , . value = 3 } ,
{ 0 , 0 } ,
} ;
static struct clk_mux_sel mux_pllm_pllc_pllp_clkm [ ] = {
{ . input = & tegra_pll_m , . value = 0 } ,
{ . input = & tegra_pll_c , . value = 1 } ,
{ . input = & tegra_pll_p , . value = 2 } ,
{ . input = & tegra_clk_m , . value = 3 } ,
{ 0 , 0 } ,
} ;
static struct clk_mux_sel mux_pllp_pllc_pllm_clkm [ ] = {
{ . input = & tegra_pll_p , . value = 0 } ,
{ . input = & tegra_pll_c , . value = 1 } ,
{ . input = & tegra_pll_m , . value = 2 } ,
{ . input = & tegra_clk_m , . value = 3 } ,
{ 0 , 0 } ,
} ;
2010-06-08 11:49:46 +08:00
static struct clk_mux_sel mux_pllaout0_audio2x_pllp_clkm [ ] = {
{ . input = & tegra_pll_a_out0 , . value = 0 } ,
{ . input = & tegra_clk_audio_2x , . value = 1 } ,
2010-01-29 08:40:29 +08:00
{ . input = & tegra_pll_p , . value = 2 } ,
{ . input = & tegra_clk_m , . value = 3 } ,
{ 0 , 0 } ,
} ;
static struct clk_mux_sel mux_pllp_plld_pllc_clkm [ ] = {
{ . input = & tegra_pll_p , . value = 0 } ,
{ . input = & tegra_pll_d_out0 , . value = 1 } ,
{ . input = & tegra_pll_c , . value = 2 } ,
{ . input = & tegra_clk_m , . value = 3 } ,
{ 0 , 0 } ,
} ;
static struct clk_mux_sel mux_pllp_pllc_audio_clkm_clk32 [ ] = {
{ . input = & tegra_pll_p , . value = 0 } ,
{ . input = & tegra_pll_c , . value = 1 } ,
2010-06-08 11:49:46 +08:00
{ . input = & tegra_clk_audio , . value = 2 } ,
2010-01-29 08:40:29 +08:00
{ . input = & tegra_clk_m , . value = 3 } ,
{ . input = & tegra_clk_32k , . value = 4 } ,
{ 0 , 0 } ,
} ;
static struct clk_mux_sel mux_pllp_pllc_pllm [ ] = {
{ . input = & tegra_pll_p , . value = 0 } ,
{ . input = & tegra_pll_c , . value = 1 } ,
{ . input = & tegra_pll_m , . value = 2 } ,
{ 0 , 0 } ,
} ;
static struct clk_mux_sel mux_clk_m [ ] = {
{ . input = & tegra_clk_m , . value = 0 } ,
{ 0 , 0 } ,
} ;
static struct clk_mux_sel mux_pllp_out3 [ ] = {
{ . input = & tegra_pll_p_out3 , . value = 0 } ,
{ 0 , 0 } ,
} ;
static struct clk_mux_sel mux_plld [ ] = {
{ . input = & tegra_pll_d , . value = 0 } ,
{ 0 , 0 } ,
} ;
static struct clk_mux_sel mux_clk_32k [ ] = {
{ . input = & tegra_clk_32k , . value = 0 } ,
{ 0 , 0 } ,
} ;
2010-06-08 11:49:46 +08:00
# define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
2010-01-29 08:40:29 +08:00
{ \
. name = _name , \
. lookup = { \
. dev_id = _dev , \
. con_id = _con , \
} , \
. ops = & tegra_periph_clk_ops , \
. clk_num = _clk_num , \
. reg = _reg , \
. inputs = _inputs , \
. flags = _flags , \
2010-06-08 11:49:46 +08:00
. max_rate = _max , \
2010-01-29 08:40:29 +08:00
}
struct clk tegra_periph_clks [ ] = {
2010-06-08 11:49:46 +08:00
PERIPH_CLK ( " rtc " , " rtc-tegra " , NULL , 4 , 0 , 32768 , mux_clk_32k , PERIPH_NO_RESET ) ,
PERIPH_CLK ( " timer " , " timer " , NULL , 5 , 0 , 26000000 , mux_clk_m , 0 ) ,
PERIPH_CLK ( " i2s1 " , " i2s.0 " , NULL , 11 , 0x100 , 26000000 , mux_pllaout0_audio2x_pllp_clkm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " i2s2 " , " i2s.1 " , NULL , 18 , 0x104 , 26000000 , mux_pllaout0_audio2x_pllp_clkm , MUX | DIV_U71 ) ,
2010-01-29 08:40:29 +08:00
/* FIXME: spdif has 2 clocks but 1 enable */
2010-06-08 11:49:46 +08:00
PERIPH_CLK ( " spdif_out " , " spdif_out " , NULL , 10 , 0x108 , 100000000 , mux_pllaout0_audio2x_pllp_clkm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " spdif_in " , " spdif_in " , NULL , 10 , 0x10c , 100000000 , mux_pllp_pllc_pllm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " pwm " , " pwm " , NULL , 17 , 0x110 , 432000000 , mux_pllp_pllc_audio_clkm_clk32 , MUX | DIV_U71 ) ,
PERIPH_CLK ( " spi " , " spi " , NULL , 43 , 0x114 , 40000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " xio " , " xio " , NULL , 45 , 0x120 , 150000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " twc " , " twc " , NULL , 16 , 0x12c , 150000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " sbc1 " , " spi_tegra.0 " , NULL , 41 , 0x134 , 160000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " sbc2 " , " spi_tegra.1 " , NULL , 44 , 0x118 , 160000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " sbc3 " , " spi_tegra.2 " , NULL , 46 , 0x11c , 160000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " sbc4 " , " spi_tegra.3 " , NULL , 68 , 0x1b4 , 160000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " ide " , " ide " , NULL , 25 , 0x144 , 100000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) , /* requires min voltage */
PERIPH_CLK ( " ndflash " , " tegra_nand " , NULL , 13 , 0x160 , 164000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) , /* scales with voltage */
2010-01-29 08:40:29 +08:00
/* FIXME: vfir shares an enable with uartb */
2010-06-08 11:49:46 +08:00
PERIPH_CLK ( " vfir " , " vfir " , NULL , 7 , 0x168 , 72000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " sdmmc1 " , " sdhci-tegra.0 " , NULL , 14 , 0x150 , 52000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) , /* scales with voltage */
PERIPH_CLK ( " sdmmc2 " , " sdhci-tegra.1 " , NULL , 9 , 0x154 , 52000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) , /* scales with voltage */
PERIPH_CLK ( " sdmmc3 " , " sdhci-tegra.2 " , NULL , 69 , 0x1bc , 52000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) , /* scales with voltage */
PERIPH_CLK ( " sdmmc4 " , " sdhci-tegra.3 " , NULL , 15 , 0x160 , 52000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) , /* scales with voltage */
PERIPH_CLK ( " vde " , " vde " , NULL , 61 , 0x1c8 , 250000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) , /* scales with voltage and process_id */
PERIPH_CLK ( " csite " , " csite " , NULL , 73 , 0x1d4 , 144000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) , /* max rate ??? */
2010-01-29 08:40:29 +08:00
/* FIXME: what is la? */
2010-06-08 11:49:46 +08:00
PERIPH_CLK ( " la " , " la " , NULL , 76 , 0x1f8 , 26000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " owr " , " tegra_w1 " , NULL , 71 , 0x1cc , 26000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) ,
PERIPH_CLK ( " nor " , " nor " , NULL , 42 , 0x1d0 , 92000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) , /* requires min voltage */
PERIPH_CLK ( " mipi " , " mipi " , NULL , 50 , 0x174 , 60000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U71 ) , /* scales with voltage */
PERIPH_CLK ( " i2c1 " , " tegra-i2c.0 " , NULL , 12 , 0x124 , 26000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U16 ) ,
PERIPH_CLK ( " i2c2 " , " tegra-i2c.1 " , NULL , 54 , 0x198 , 26000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U16 ) ,
PERIPH_CLK ( " i2c3 " , " tegra-i2c.2 " , NULL , 67 , 0x1b8 , 26000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U16 ) ,
PERIPH_CLK ( " dvc " , " tegra-i2c.3 " , NULL , 47 , 0x128 , 26000000 , mux_pllp_pllc_pllm_clkm , MUX | DIV_U16 ) ,
PERIPH_CLK ( " i2c1_i2c " , " tegra-i2c.0 " , " i2c " , 0 , 0 , 72000000 , mux_pllp_out3 , 0 ) ,
PERIPH_CLK ( " i2c2_i2c " , " tegra-i2c.1 " , " i2c " , 0 , 0 , 72000000 , mux_pllp_out3 , 0 ) ,
PERIPH_CLK ( " i2c3_i2c " , " tegra-i2c.2 " , " i2c " , 0 , 0 , 72000000 , mux_pllp_out3 , 0 ) ,
PERIPH_CLK ( " dvc_i2c " , " tegra-i2c.3 " , " i2c " , 0 , 0 , 72000000 , mux_pllp_out3 , 0 ) ,
PERIPH_CLK ( " uarta " , " uart.0 " , NULL , 6 , 0x178 , 216000000 , mux_pllp_pllc_pllm_clkm , MUX ) ,
PERIPH_CLK ( " uartb " , " uart.1 " , NULL , 7 , 0x17c , 216000000 , mux_pllp_pllc_pllm_clkm , MUX ) ,
PERIPH_CLK ( " uartc " , " uart.2 " , NULL , 55 , 0x1a0 , 216000000 , mux_pllp_pllc_pllm_clkm , MUX ) ,
PERIPH_CLK ( " uartd " , " uart.3 " , NULL , 65 , 0x1c0 , 216000000 , mux_pllp_pllc_pllm_clkm , MUX ) ,
PERIPH_CLK ( " uarte " , " uart.4 " , NULL , 66 , 0x1c4 , 216000000 , mux_pllp_pllc_pllm_clkm , MUX ) ,
PERIPH_CLK ( " 3d " , " 3d " , NULL , 24 , 0x158 , 300000000 , mux_pllm_pllc_pllp_plla , MUX | DIV_U71 | PERIPH_MANUAL_RESET ) , /* scales with voltage and process_id */
PERIPH_CLK ( " 2d " , " 2d " , NULL , 21 , 0x15c , 300000000 , mux_pllm_pllc_pllp_plla , MUX | DIV_U71 ) , /* scales with voltage and process_id */
2010-01-29 08:40:29 +08:00
/* FIXME: vi and vi_sensor share an enable */
2010-06-08 11:49:46 +08:00
PERIPH_CLK ( " vi " , " vi " , NULL , 20 , 0x148 , 150000000 , mux_pllm_pllc_pllp_plla , MUX | DIV_U71 ) , /* scales with voltage and process_id */
PERIPH_CLK ( " vi_sensor " , " vi_sensor " , NULL , 20 , 0x1a8 , 150000000 , mux_pllm_pllc_pllp_plla , MUX | DIV_U71 | PERIPH_NO_RESET ) , /* scales with voltage and process_id */
PERIPH_CLK ( " epp " , " epp " , NULL , 19 , 0x16c , 300000000 , mux_pllm_pllc_pllp_plla , MUX | DIV_U71 ) , /* scales with voltage and process_id */
PERIPH_CLK ( " mpe " , " mpe " , NULL , 60 , 0x170 , 250000000 , mux_pllm_pllc_pllp_plla , MUX | DIV_U71 ) , /* scales with voltage and process_id */
PERIPH_CLK ( " host1x " , " host1x " , NULL , 28 , 0x180 , 166000000 , mux_pllm_pllc_pllp_plla , MUX | DIV_U71 ) , /* scales with voltage and process_id */
2010-01-29 08:40:29 +08:00
/* FIXME: cve and tvo share an enable */
2010-06-08 11:49:46 +08:00
PERIPH_CLK ( " cve " , " cve " , NULL , 49 , 0x140 , 250000000 , mux_pllp_plld_pllc_clkm , MUX | DIV_U71 ) , /* requires min voltage */
PERIPH_CLK ( " tvo " , " tvo " , NULL , 49 , 0x188 , 250000000 , mux_pllp_plld_pllc_clkm , MUX | DIV_U71 ) , /* requires min voltage */
PERIPH_CLK ( " hdmi " , " hdmi " , NULL , 51 , 0x18c , 148500000 , mux_pllp_plld_pllc_clkm , MUX | DIV_U71 ) , /* requires min voltage */
PERIPH_CLK ( " tvdac " , " tvdac " , NULL , 53 , 0x194 , 250000000 , mux_pllp_plld_pllc_clkm , MUX | DIV_U71 ) , /* requires min voltage */
PERIPH_CLK ( " disp1 " , " tegrafb.0 " , NULL , 27 , 0x138 , 190000000 , mux_pllp_plld_pllc_clkm , MUX | DIV_U71 ) , /* scales with voltage and process_id */
PERIPH_CLK ( " disp2 " , " tegrafb.1 " , NULL , 26 , 0x13c , 190000000 , mux_pllp_plld_pllc_clkm , MUX | DIV_U71 ) , /* scales with voltage and process_id */
PERIPH_CLK ( " usbd " , " fsl-tegra-udc " , NULL , 22 , 0 , 480000000 , mux_clk_m , 0 ) , /* requires min voltage */
PERIPH_CLK ( " usb2 " , " tegra-ehci.1 " , NULL , 58 , 0 , 480000000 , mux_clk_m , 0 ) , /* requires min voltage */
PERIPH_CLK ( " usb3 " , " tegra-ehci.2 " , NULL , 59 , 0 , 480000000 , mux_clk_m , 0 ) , /* requires min voltage */
PERIPH_CLK ( " emc " , " emc " , NULL , 57 , 0x19c , 800000000 , mux_pllm_pllc_pllp_clkm , MUX | DIV_U71 | PERIPH_EMC_ENB ) ,
PERIPH_CLK ( " dsi " , " dsi " , NULL , 48 , 0 , 500000000 , mux_plld , 0 ) , /* scales with voltage */
PERIPH_CLK ( " csi " , " csi " , NULL , 52 , 0 , 72000000 , mux_pllp_out3 , 0 ) ,
PERIPH_CLK ( " isp " , " isp " , NULL , 23 , 0 , 150000000 , mux_clk_m , 0 ) , /* same frequency as VI */
PERIPH_CLK ( " csus " , " csus " , NULL , 92 , 0 , 150000000 , mux_clk_m , PERIPH_NO_RESET ) ,
2010-09-27 17:26:32 +08:00
PERIPH_CLK ( " pex " , NULL , " pex " , 70 , 0 , 26000000 , mux_clk_m , PERIPH_MANUAL_RESET ) ,
PERIPH_CLK ( " afi " , NULL , " afi " , 72 , 0 , 26000000 , mux_clk_m , PERIPH_MANUAL_RESET ) ,
PERIPH_CLK ( " pcie_xclk " , NULL , " pcie_xclk " , 74 , 0 , 26000000 , mux_clk_m , PERIPH_MANUAL_RESET ) ,
2010-01-29 08:40:29 +08:00
} ;
# define CLK_DUPLICATE(_name, _dev, _con) \
{ \
. name = _name , \
. lookup = { \
. dev_id = _dev , \
. con_id = _con , \
} , \
}
/* Some clocks may be used by different drivers depending on the board
* configuration . List those here to register them twice in the clock lookup
* table under two names .
*/
struct clk_duplicate tegra_clk_duplicates [ ] = {
CLK_DUPLICATE ( " uarta " , " tegra_uart.0 " , NULL ) ,
CLK_DUPLICATE ( " uartb " , " tegra_uart.1 " , NULL ) ,
CLK_DUPLICATE ( " uartc " , " tegra_uart.2 " , NULL ) ,
CLK_DUPLICATE ( " uartd " , " tegra_uart.3 " , NULL ) ,
CLK_DUPLICATE ( " uarte " , " tegra_uart.4 " , NULL ) ,
2010-06-08 11:49:46 +08:00
CLK_DUPLICATE ( " host1x " , " tegrafb.0 " , " host1x " ) ,
CLK_DUPLICATE ( " host1x " , " tegrafb.1 " , " host1x " ) ,
CLK_DUPLICATE ( " usbd " , " tegra-ehci.0 " , NULL ) ,
2010-01-29 08:40:29 +08:00
} ;
# define CLK(dev, con, ck) \
{ \
. dev_id = dev , \
. con_id = con , \
. clk = ck , \
}
struct clk_lookup tegra_clk_lookups [ ] = {
/* external root sources */
CLK ( NULL , " 32k_clk " , & tegra_clk_32k ) ,
CLK ( NULL , " pll_s " , & tegra_pll_s ) ,
CLK ( NULL , " clk_m " , & tegra_clk_m ) ,
CLK ( NULL , " pll_m " , & tegra_pll_m ) ,
CLK ( NULL , " pll_m_out1 " , & tegra_pll_m_out1 ) ,
CLK ( NULL , " pll_c " , & tegra_pll_c ) ,
CLK ( NULL , " pll_c_out1 " , & tegra_pll_c_out1 ) ,
CLK ( NULL , " pll_p " , & tegra_pll_p ) ,
CLK ( NULL , " pll_p_out1 " , & tegra_pll_p_out1 ) ,
CLK ( NULL , " pll_p_out2 " , & tegra_pll_p_out2 ) ,
CLK ( NULL , " pll_p_out3 " , & tegra_pll_p_out3 ) ,
CLK ( NULL , " pll_p_out4 " , & tegra_pll_p_out4 ) ,
CLK ( NULL , " pll_a " , & tegra_pll_a ) ,
CLK ( NULL , " pll_a_out0 " , & tegra_pll_a_out0 ) ,
CLK ( NULL , " pll_d " , & tegra_pll_d ) ,
CLK ( NULL , " pll_d_out0 " , & tegra_pll_d_out0 ) ,
CLK ( NULL , " pll_u " , & tegra_pll_u ) ,
CLK ( NULL , " pll_x " , & tegra_pll_x ) ,
2010-09-27 17:26:32 +08:00
CLK ( NULL , " pll_e " , & tegra_pll_e ) ,
2010-06-08 11:49:46 +08:00
CLK ( NULL , " cclk " , & tegra_clk_cclk ) ,
CLK ( NULL , " sclk " , & tegra_clk_sclk ) ,
2010-01-29 08:40:29 +08:00
CLK ( NULL , " hclk " , & tegra_clk_hclk ) ,
CLK ( NULL , " pclk " , & tegra_clk_pclk ) ,
CLK ( NULL , " clk_d " , & tegra_clk_d ) ,
2010-06-08 11:49:46 +08:00
CLK ( NULL , " cpu " , & tegra_clk_virtual_cpu ) ,
2010-01-29 08:40:29 +08:00
} ;
void __init tegra2_init_clocks ( void )
{
int i ;
struct clk_lookup * cl ;
struct clk * c ;
struct clk_duplicate * cd ;
for ( i = 0 ; i < ARRAY_SIZE ( tegra_clk_lookups ) ; i + + ) {
cl = & tegra_clk_lookups [ i ] ;
clk_init ( cl - > clk ) ;
clkdev_add ( cl ) ;
}
for ( i = 0 ; i < ARRAY_SIZE ( tegra_periph_clks ) ; i + + ) {
c = & tegra_periph_clks [ i ] ;
cl = & c - > lookup ;
cl - > clk = c ;
clk_init ( cl - > clk ) ;
clkdev_add ( cl ) ;
}
for ( i = 0 ; i < ARRAY_SIZE ( tegra_clk_duplicates ) ; i + + ) {
cd = & tegra_clk_duplicates [ i ] ;
c = tegra_get_clock_by_name ( cd - > name ) ;
if ( c ) {
cl = & cd - > lookup ;
cl - > clk = c ;
clkdev_add ( cl ) ;
} else {
pr_err ( " %s: Unknown duplicate clock %s \n " , __func__ ,
cd - > name ) ;
}
}
2010-06-08 11:49:46 +08:00
init_audio_sync_clock_mux ( ) ;
}
# ifdef CONFIG_PM
static u32 clk_rst_suspend [ RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
PERIPH_CLK_SOURCE_NUM + 3 ] ;
void tegra_clk_suspend ( void )
{
unsigned long off , i ;
u32 * ctx = clk_rst_suspend ;
* ctx + + = clk_readl ( OSC_CTRL ) & OSC_CTRL_MASK ;
for ( off = PERIPH_CLK_SOURCE_I2S1 ; off < = PERIPH_CLK_SOURCE_OSC ;
off + = 4 ) {
if ( off = = PERIPH_CLK_SOURCE_EMC )
continue ;
* ctx + + = clk_readl ( off ) ;
}
off = RST_DEVICES ;
for ( i = 0 ; i < RST_DEVICES_NUM ; i + + , off + = 4 )
* ctx + + = clk_readl ( off ) ;
off = CLK_OUT_ENB ;
for ( i = 0 ; i < CLK_OUT_ENB_NUM ; i + + , off + = 4 )
* ctx + + = clk_readl ( off ) ;
* ctx + + = clk_readl ( MISC_CLK_ENB ) ;
* ctx + + = clk_readl ( CLK_MASK_ARM ) ;
}
void tegra_clk_resume ( void )
{
unsigned long off , i ;
const u32 * ctx = clk_rst_suspend ;
u32 val ;
val = clk_readl ( OSC_CTRL ) & ~ OSC_CTRL_MASK ;
val | = * ctx + + ;
clk_writel ( val , OSC_CTRL ) ;
/* enable all clocks before configuring clock sources */
clk_writel ( 0xbffffff9ul , CLK_OUT_ENB ) ;
clk_writel ( 0xfefffff7ul , CLK_OUT_ENB + 4 ) ;
clk_writel ( 0x77f01bfful , CLK_OUT_ENB + 8 ) ;
wmb ( ) ;
for ( off = PERIPH_CLK_SOURCE_I2S1 ; off < = PERIPH_CLK_SOURCE_OSC ;
off + = 4 ) {
if ( off = = PERIPH_CLK_SOURCE_EMC )
continue ;
clk_writel ( * ctx + + , off ) ;
}
wmb ( ) ;
off = RST_DEVICES ;
for ( i = 0 ; i < RST_DEVICES_NUM ; i + + , off + = 4 )
clk_writel ( * ctx + + , off ) ;
wmb ( ) ;
off = CLK_OUT_ENB ;
for ( i = 0 ; i < CLK_OUT_ENB_NUM ; i + + , off + = 4 )
clk_writel ( * ctx + + , off ) ;
wmb ( ) ;
clk_writel ( * ctx + + , MISC_CLK_ENB ) ;
clk_writel ( * ctx + + , CLK_MASK_ARM ) ;
2010-01-29 08:40:29 +08:00
}
2010-06-08 11:49:46 +08:00
# endif