2010-01-28 16:40:29 -08:00
/*
2012-08-06 11:57:43 +05:30
* arch / arm / mach - tegra / tegra20_clocks . c
2010-01-28 16:40:29 -08:00
*
* Copyright ( C ) 2010 Google , Inc .
2012-08-06 11:57:43 +05:30
* Copyright ( c ) 2010 - 2012 NVIDIA CORPORATION . All rights reserved .
2010-01-28 16:40:29 -08:00
*
* 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>
2010-11-17 10:04:33 +01:00
# include <linux/clkdev.h>
2011-02-12 16:43:05 -08:00
# include <linux/clk.h>
2010-01-28 16:40:29 -08:00
# include "clock.h"
2010-06-07 20:49:46 -07:00
# include "fuse.h"
2012-10-04 14:24:09 -06:00
# include "iomap.h"
2010-11-22 18:37:54 -08:00
# include "tegra2_emc.h"
2012-08-16 17:31:48 +08:00
# include "tegra_cpu_car.h"
2010-01-28 16:40:29 -08:00
# define RST_DEVICES 0x004
# define RST_DEVICES_SET 0x300
# define RST_DEVICES_CLR 0x304
2010-06-07 20:49:46 -07:00
# define RST_DEVICES_NUM 3
2010-01-28 16:40:29 -08:00
# define CLK_OUT_ENB 0x010
# define CLK_OUT_ENB_SET 0x320
# define CLK_OUT_ENB_CLR 0x324
2010-06-07 20:49:46 -07:00
# define CLK_OUT_ENB_NUM 3
# define CLK_MASK_ARM 0x44
# define MISC_CLK_ENB 0x48
2010-01-28 16: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-10-04 11:49:26 -07:00
# define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
2010-01-28 16: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-07 20:49:46 -07: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-28 16:40:29 -08:00
# define PERIPH_CLK_SOURCE_MASK (3<<30)
# define PERIPH_CLK_SOURCE_SHIFT 30
2011-12-16 20:11:22 +01:00
# define PERIPH_CLK_SOURCE_PWM_MASK (7<<28)
# define PERIPH_CLK_SOURCE_PWM_SHIFT 28
2010-01-28 16:40:29 -08:00
# define PERIPH_CLK_SOURCE_ENABLE (1<<28)
2010-06-07 20:49:46 -07:00
# define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF
# define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
2010-01-28 16:40:29 -08:00
# define PERIPH_CLK_SOURCE_DIV_SHIFT 0
2011-02-12 18:24:32 -08:00
# define SDMMC_CLK_INT_FB_SEL (1 << 23)
# define SDMMC_CLK_INT_FB_DLY_SHIFT 16
# define SDMMC_CLK_INT_FB_DLY_MASK (0xF << SDMMC_CLK_INT_FB_DLY_SHIFT)
2010-01-28 16:40:29 -08:00
# 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_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)
2012-08-06 11:57:43 +05:30
# define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
2010-06-07 20:49:46 -07:00
2010-01-28 16: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-07 20:49:46 -07:00
# define PLLU_BASE_POST_DIV (1<<20)
2010-01-28 16: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 11:26:32 +02:00
# define PLLE_MISC_READY (1 << 15)
2011-02-12 16:05:31 -08:00
# define PERIPH_CLK_TO_ENB_REG(c) ((c->u.periph.clk_num / 32) * 4)
# define PERIPH_CLK_TO_ENB_SET_REG(c) ((c->u.periph.clk_num / 32) * 8)
# define PERIPH_CLK_TO_ENB_BIT(c) (1 << (c->u.periph.clk_num % 32))
2010-01-28 16:40:29 -08:00
# 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
2010-10-04 11:49:26 -07:00
# define PMC_CTRL 0x0
# define PMC_CTRL_BLINK_ENB (1 << 7)
# define PMC_DPD_PADS_ORIDE 0x1c
# define PMC_DPD_PADS_ORIDE_BLINK_ENB (1 << 20)
# define PMC_BLINK_TIMER_DATA_ON_SHIFT 0
# define PMC_BLINK_TIMER_DATA_ON_MASK 0x7fff
# define PMC_BLINK_TIMER_ENB (1 << 15)
# define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16
# define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff
2012-08-16 17:31:48 +08:00
/* Tegra CPU clock and reset control regs */
# define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c
# define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340
# define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344
# define CPU_CLOCK(cpu) (0x1 << (8 + cpu))
# define CPU_RESET(cpu) (0x1111ul << (cpu))
2010-01-28 16:40:29 -08:00
static void __iomem * reg_clk_base = IO_ADDRESS ( TEGRA_CLK_RESET_BASE ) ;
2010-10-04 11:49:26 -07:00
static void __iomem * reg_pmc_base = IO_ADDRESS ( TEGRA_PMC_BASE ) ;
2010-01-28 16:40:29 -08:00
2011-02-12 16:43:05 -08:00
/*
* Some clocks share a register with other clocks . Any clock op that
* non - atomically modifies a register used by another clock must lock
* clock_register_lock first .
*/
static DEFINE_SPINLOCK ( clock_register_lock ) ;
2010-10-20 19:19:58 -07:00
/*
* Some peripheral clocks share an enable bit , so refcount the enable bits
* in registers CLK_ENABLE_L , CLK_ENABLE_H , and CLK_ENABLE_U
*/
static int tegra_periph_clk_enable_refcount [ 3 * 32 ] ;
2010-01-28 16:40:29 -08:00
# define clk_writel(value, reg) \
2011-09-08 17:56:59 -07:00
__raw_writel ( value , reg_clk_base + ( reg ) )
2010-01-28 16:40:29 -08:00
# define clk_readl(reg) \
2011-09-08 17:56:59 -07:00
__raw_readl ( reg_clk_base + ( reg ) )
2010-10-04 11:49:26 -07:00
# define pmc_writel(value, reg) \
2011-09-08 17:56:59 -07:00
__raw_writel ( value , reg_pmc_base + ( reg ) )
2010-10-04 11:49:26 -07:00
# define pmc_readl(reg) \
2011-09-08 17:56:59 -07:00
__raw_readl ( reg_pmc_base + ( reg ) )
2010-01-28 16:40:29 -08:00
2011-12-14 17:03:16 +02:00
static unsigned long clk_measure_input_freq ( void )
2010-01-28 16:40:29 -08:00
{
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 {
2012-08-06 11:57:43 +05:30
pr_err ( " %s: Unexpected clock autodetect value %d " ,
__func__ , clock_autodetect ) ;
2010-01-28 16:40:29 -08:00
BUG ( ) ;
return 0 ;
}
}
2010-06-07 20:49:46 -07:00
static int clk_div71_get_divider ( unsigned long parent_rate , unsigned long rate )
2010-01-28 16:40:29 -08:00
{
2010-06-07 20:49:46 -07:00
s64 divider_u71 = parent_rate * 2 ;
divider_u71 + = rate - 1 ;
do_div ( divider_u71 , rate ) ;
2010-01-28 16:40:29 -08:00
2010-06-07 20:49:46 -07:00
if ( divider_u71 - 2 < 0 )
return 0 ;
2010-01-28 16:40:29 -08:00
2010-06-07 20:49:46 -07:00
if ( divider_u71 - 2 > 255 )
2010-01-28 16:40:29 -08:00
return - EINVAL ;
return divider_u71 - 2 ;
}
2010-06-07 20:49:46 -07:00
static int clk_div16_get_divider ( unsigned long parent_rate , unsigned long rate )
2010-01-28 16:40:29 -08:00
{
2010-06-07 20:49:46 -07:00
s64 divider_u16 ;
2010-01-28 16:40:29 -08:00
2010-06-07 20:49:46 -07:00
divider_u16 = parent_rate ;
divider_u16 + = rate - 1 ;
do_div ( divider_u16 , rate ) ;
2010-01-28 16:40:29 -08:00
2010-06-07 20:49:46 -07:00
if ( divider_u16 - 1 < 0 )
return 0 ;
2012-07-24 15:48:12 -06:00
if ( divider_u16 - 1 > 0xFFFF )
2010-06-07 20:49:46 -07:00
return - EINVAL ;
return divider_u16 - 1 ;
}
2010-01-28 16:40:29 -08:00
2012-08-17 14:51:21 +08:00
static unsigned long tegra_clk_fixed_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
return to_clk_tegra ( hw ) - > fixed_rate ;
}
struct clk_ops tegra_clk_32k_ops = {
. recalc_rate = tegra_clk_fixed_recalc_rate ,
} ;
2010-01-28 16:40:29 -08:00
/* clk_m functions */
2012-08-06 11:57:43 +05:30
static unsigned long tegra20_clk_m_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
if ( ! to_clk_tegra ( hw ) - > fixed_rate )
to_clk_tegra ( hw ) - > fixed_rate = clk_measure_input_freq ( ) ;
return to_clk_tegra ( hw ) - > fixed_rate ;
}
static void tegra20_clk_m_init ( struct clk_hw * hw )
{
struct clk_tegra * c = to_clk_tegra ( hw ) ;
u32 osc_ctrl = clk_readl ( OSC_CTRL ) ;
u32 auto_clock_control = osc_ctrl & ~ OSC_CTRL_OSC_FREQ_MASK ;
2010-01-28 16:40:29 -08:00
2012-08-06 11:57:43 +05:30
switch ( c - > fixed_rate ) {
2010-01-28 16:40:29 -08:00
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 :
BUG ( ) ;
}
clk_writel ( auto_clock_control , OSC_CTRL ) ;
}
2012-08-06 11:57:40 +05:30
struct clk_ops tegra_clk_m_ops = {
2012-08-06 11:57:43 +05:30
. init = tegra20_clk_m_init ,
. recalc_rate = tegra20_clk_m_recalc_rate ,
2010-01-28 16:40:29 -08:00
} ;
/* 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 .
*/
2012-08-06 11:57:43 +05:30
static int tegra20_super_clk_is_enabled ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-01-28 16:40:29 -08:00
u32 val ;
2012-08-06 11:57:43 +05:30
2010-01-28 16: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 ) ) ;
2012-08-06 11:57:43 +05:30
c - > state = ON ;
return c - > state ;
2010-01-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
static int tegra20_super_clk_enable ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-01-28 16:40:29 -08:00
clk_writel ( 0 , c - > reg + SUPER_CLK_DIVIDER ) ;
return 0 ;
}
2012-08-06 11:57:43 +05:30
static void tegra20_super_clk_disable ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
pr_debug ( " %s on clock %s \n " , __func__ , __clk_get_name ( hw - > clk ) ) ;
2010-01-28 16:40:29 -08:00
/* oops - don't disable the CPU clock! */
BUG ( ) ;
}
2012-08-06 11:57:43 +05:30
static u8 tegra20_super_clk_get_parent ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
int val = clk_readl ( c - > reg + SUPER_CLK_MUX ) ;
int source ;
2010-01-28 16:40:29 -08:00
int shift ;
2010-06-07 20:49:46 -07:00
2010-01-28 16:40:29 -08:00
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 ;
2012-08-06 11:57:43 +05:30
source = ( val > > shift ) & SUPER_SOURCE_MASK ;
return source ;
}
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
static int tegra20_super_clk_set_parent ( struct clk_hw * hw , u8 index )
{
struct clk_tegra * c = to_clk_tegra ( hw ) ;
u32 val = clk_readl ( c - > reg + SUPER_CLK_MUX ) ;
int shift ;
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
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 ;
val & = ~ ( SUPER_SOURCE_MASK < < shift ) ;
val | = index < < shift ;
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
clk_writel ( val , c - > reg ) ;
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
return 0 ;
2010-01-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
/* FIX ME: Need to switch parents to change the source PLL rate */
static unsigned long tegra20_super_clk_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
2011-02-12 21:25:23 -08:00
{
2012-08-06 11:57:43 +05:30
return prate ;
2011-02-12 21:25:23 -08:00
}
2012-08-06 11:57:43 +05:30
static long tegra20_super_clk_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
2010-06-07 20:49:46 -07:00
{
2012-08-06 11:57:43 +05:30
return * prate ;
2010-06-07 20:49:46 -07:00
}
2012-08-06 11:57:43 +05:30
static int tegra20_super_clk_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
2010-06-07 20:49:46 -07:00
{
return 0 ;
}
2012-08-06 11:57:43 +05:30
struct clk_ops tegra_super_ops = {
. is_enabled = tegra20_super_clk_is_enabled ,
. enable = tegra20_super_clk_enable ,
. disable = tegra20_super_clk_disable ,
. set_parent = tegra20_super_clk_set_parent ,
. get_parent = tegra20_super_clk_get_parent ,
. set_rate = tegra20_super_clk_set_rate ,
. round_rate = tegra20_super_clk_round_rate ,
. recalc_rate = tegra20_super_clk_recalc_rate ,
} ;
2010-06-07 20:49:46 -07:00
2012-09-13 15:04:33 +05:30
static unsigned long tegra20_twd_clk_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_tegra * c = to_clk_tegra ( hw ) ;
u64 rate = parent_rate ;
if ( c - > mul ! = 0 & & c - > div ! = 0 ) {
rate * = c - > mul ;
rate + = c - > div - 1 ; /* round up */
do_div ( rate , c - > div ) ;
}
return rate ;
}
struct clk_ops tegra_twd_ops = {
. recalc_rate = tegra20_twd_clk_recalc_rate ,
} ;
2012-08-06 11:57:43 +05:30
static u8 tegra20_cop_clk_get_parent ( struct clk_hw * hw )
2010-06-07 20:49:46 -07:00
{
2012-08-06 11:57:43 +05:30
return 0 ;
2010-06-07 20:49:46 -07:00
}
2012-08-06 11:57:43 +05:30
struct clk_ops tegra_cop_ops = {
. get_parent = tegra20_cop_clk_get_parent ,
2010-01-28 16:40:29 -08:00
} ;
2011-02-12 21:25:23 -08:00
/* virtual cop clock functions. Used to acquire the fake 'cop' clock to
* reset the COP block ( i . e . AVP ) */
2012-08-06 11:57:43 +05:30
void tegra2_cop_clk_reset ( struct clk_hw * hw , bool assert )
2011-02-12 21:25:23 -08:00
{
unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR ;
pr_debug ( " %s %s \n " , __func__ , assert ? " assert " : " deassert " ) ;
clk_writel ( 1 < < 1 , reg ) ;
}
2010-01-28 16:40:29 -08:00
/* bus clock functions */
2012-08-06 11:57:43 +05:30
static int tegra20_bus_clk_is_enabled ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-01-28 16:40:29 -08:00
u32 val = clk_readl ( c - > reg ) ;
2012-08-06 11:57:43 +05:30
2010-01-28 16:40:29 -08:00
c - > state = ( ( val > > c - > reg_shift ) & BUS_CLK_DISABLE ) ? OFF : ON ;
2012-08-06 11:57:43 +05:30
return c - > state ;
2010-01-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
static int tegra20_bus_clk_enable ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2011-02-12 16:43:05 -08:00
unsigned long flags ;
2012-08-06 11:57:43 +05:30
u32 val ;
2011-02-12 16:43:05 -08:00
spin_lock_irqsave ( & clock_register_lock , flags ) ;
val = clk_readl ( c - > reg ) ;
2010-01-28 16:40:29 -08:00
val & = ~ ( BUS_CLK_DISABLE < < c - > reg_shift ) ;
clk_writel ( val , c - > reg ) ;
2011-02-12 16:43:05 -08:00
spin_unlock_irqrestore ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
return 0 ;
}
2012-08-06 11:57:43 +05:30
static void tegra20_bus_clk_disable ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2011-02-12 16:43:05 -08:00
unsigned long flags ;
2012-08-06 11:57:43 +05:30
u32 val ;
2011-02-12 16:43:05 -08:00
spin_lock_irqsave ( & clock_register_lock , flags ) ;
val = clk_readl ( c - > reg ) ;
2010-01-28 16:40:29 -08:00
val | = BUS_CLK_DISABLE < < c - > reg_shift ;
clk_writel ( val , c - > reg ) ;
2011-02-12 16:43:05 -08:00
spin_unlock_irqrestore ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
static unsigned long tegra20_bus_clk_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
u32 val = clk_readl ( c - > reg ) ;
u64 rate = prate ;
c - > div = ( ( val > > c - > reg_shift ) & BUS_CLK_DIV_MASK ) + 1 ;
c - > mul = 1 ;
if ( c - > mul ! = 0 & & c - > div ! = 0 ) {
rate * = c - > mul ;
rate + = c - > div - 1 ; /* round up */
do_div ( rate , c - > div ) ;
}
return rate ;
}
static int tegra20_bus_clk_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2011-02-12 16:43:05 -08:00
int ret = - EINVAL ;
2012-08-06 11:57:43 +05:30
unsigned long flags ;
u32 val ;
2010-01-28 16:40:29 -08:00
int i ;
2011-02-12 16:43:05 -08:00
spin_lock_irqsave ( & clock_register_lock , flags ) ;
val = clk_readl ( c - > reg ) ;
2010-01-28 16:40:29 -08:00
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 ;
2011-02-12 16:43:05 -08:00
ret = 0 ;
break ;
2010-01-28 16:40:29 -08:00
}
}
2011-02-12 16:43:05 -08:00
spin_unlock_irqrestore ( & clock_register_lock , flags ) ;
return ret ;
2010-01-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
static long tegra20_bus_clk_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
unsigned long parent_rate = * prate ;
s64 divider ;
if ( rate > = parent_rate )
return rate ;
divider = parent_rate ;
divider + = rate - 1 ;
do_div ( divider , rate ) ;
if ( divider < 0 )
return divider ;
if ( divider > 4 )
divider = 4 ;
do_div ( parent_rate , divider ) ;
return parent_rate ;
}
2012-08-06 11:57:40 +05:30
struct clk_ops tegra_bus_ops = {
2012-08-06 11:57:43 +05:30
. is_enabled = tegra20_bus_clk_is_enabled ,
. enable = tegra20_bus_clk_enable ,
. disable = tegra20_bus_clk_disable ,
. set_rate = tegra20_bus_clk_set_rate ,
. round_rate = tegra20_bus_clk_round_rate ,
. recalc_rate = tegra20_bus_clk_recalc_rate ,
2010-01-28 16:40:29 -08:00
} ;
2010-10-04 11:49:26 -07:00
/* Blink output functions */
2012-08-06 11:57:43 +05:30
static int tegra20_blink_clk_is_enabled ( struct clk_hw * hw )
2010-10-04 11:49:26 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-10-04 11:49:26 -07:00
u32 val ;
val = pmc_readl ( PMC_CTRL ) ;
c - > state = ( val & PMC_CTRL_BLINK_ENB ) ? ON : OFF ;
2012-08-06 11:57:43 +05:30
return c - > state ;
}
static unsigned long tegra20_blink_clk_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
{
struct clk_tegra * c = to_clk_tegra ( hw ) ;
u64 rate = prate ;
u32 val ;
2010-10-04 11:49:26 -07:00
c - > mul = 1 ;
val = pmc_readl ( c - > reg ) ;
if ( val & PMC_BLINK_TIMER_ENB ) {
unsigned int on_off ;
on_off = ( val > > PMC_BLINK_TIMER_DATA_ON_SHIFT ) &
PMC_BLINK_TIMER_DATA_ON_MASK ;
val > > = PMC_BLINK_TIMER_DATA_OFF_SHIFT ;
val & = PMC_BLINK_TIMER_DATA_OFF_MASK ;
on_off + = val ;
/* each tick in the blink timer is 4 32KHz clocks */
c - > div = on_off * 4 ;
} else {
c - > div = 1 ;
}
2012-08-06 11:57:43 +05:30
if ( c - > mul ! = 0 & & c - > div ! = 0 ) {
rate * = c - > mul ;
rate + = c - > div - 1 ; /* round up */
do_div ( rate , c - > div ) ;
}
return rate ;
2010-10-04 11:49:26 -07:00
}
2012-08-06 11:57:43 +05:30
static int tegra20_blink_clk_enable ( struct clk_hw * hw )
2010-10-04 11:49:26 -07:00
{
u32 val ;
val = pmc_readl ( PMC_DPD_PADS_ORIDE ) ;
pmc_writel ( val | PMC_DPD_PADS_ORIDE_BLINK_ENB , PMC_DPD_PADS_ORIDE ) ;
val = pmc_readl ( PMC_CTRL ) ;
pmc_writel ( val | PMC_CTRL_BLINK_ENB , PMC_CTRL ) ;
return 0 ;
}
2012-08-06 11:57:43 +05:30
static void tegra20_blink_clk_disable ( struct clk_hw * hw )
2010-10-04 11:49:26 -07:00
{
u32 val ;
val = pmc_readl ( PMC_CTRL ) ;
pmc_writel ( val & ~ PMC_CTRL_BLINK_ENB , PMC_CTRL ) ;
val = pmc_readl ( PMC_DPD_PADS_ORIDE ) ;
pmc_writel ( val & ~ PMC_DPD_PADS_ORIDE_BLINK_ENB , PMC_DPD_PADS_ORIDE ) ;
}
2012-08-06 11:57:43 +05:30
static int tegra20_blink_clk_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
2010-10-04 11:49:26 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2011-02-12 16:43:05 -08:00
if ( rate > = parent_rate ) {
2010-10-04 11:49:26 -07:00
c - > div = 1 ;
pmc_writel ( 0 , c - > reg ) ;
} else {
unsigned int on_off ;
u32 val ;
2011-02-12 16:43:05 -08:00
on_off = DIV_ROUND_UP ( parent_rate / 8 , rate ) ;
2010-10-04 11:49:26 -07:00
c - > div = on_off * 8 ;
val = ( on_off & PMC_BLINK_TIMER_DATA_ON_MASK ) < <
PMC_BLINK_TIMER_DATA_ON_SHIFT ;
on_off & = PMC_BLINK_TIMER_DATA_OFF_MASK ;
on_off < < = PMC_BLINK_TIMER_DATA_OFF_SHIFT ;
val | = on_off ;
val | = PMC_BLINK_TIMER_ENB ;
pmc_writel ( val , c - > reg ) ;
}
return 0 ;
}
2012-08-06 11:57:43 +05:30
static long tegra20_blink_clk_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
int div ;
int mul ;
long round_rate = * prate ;
mul = 1 ;
if ( rate > = * prate ) {
div = 1 ;
} else {
div = DIV_ROUND_UP ( * prate / 8 , rate ) ;
div * = 8 ;
}
round_rate * = mul ;
round_rate + = div - 1 ;
do_div ( round_rate , div ) ;
return round_rate ;
}
2012-08-06 11:57:40 +05:30
struct clk_ops tegra_blink_clk_ops = {
2012-08-06 11:57:43 +05:30
. is_enabled = tegra20_blink_clk_is_enabled ,
. enable = tegra20_blink_clk_enable ,
. disable = tegra20_blink_clk_disable ,
. set_rate = tegra20_blink_clk_set_rate ,
. round_rate = tegra20_blink_clk_round_rate ,
. recalc_rate = tegra20_blink_clk_recalc_rate ,
2010-10-04 11:49:26 -07:00
} ;
2010-01-28 16:40:29 -08:00
/* PLL Functions */
2012-08-06 11:57:43 +05:30
static int tegra20_pll_clk_wait_for_lock ( struct clk_tegra * c )
2010-01-28 16:40:29 -08:00
{
2011-02-12 16:05:31 -08:00
udelay ( c - > u . pll . lock_delay ) ;
2010-01-28 16:40:29 -08:00
return 0 ;
}
2012-08-06 11:57:43 +05:30
static int tegra20_pll_clk_is_enabled ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-01-28 16:40:29 -08:00
u32 val = clk_readl ( c - > reg + PLL_BASE ) ;
c - > state = ( val & PLL_BASE_ENABLE ) ? ON : OFF ;
2012-08-06 11:57:43 +05:30
return c - > state ;
}
static unsigned long tegra20_pll_clk_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
{
struct clk_tegra * c = to_clk_tegra ( hw ) ;
u32 val = clk_readl ( c - > reg + PLL_BASE ) ;
u64 rate = prate ;
2010-01-28 16:40:29 -08:00
if ( c - > flags & PLL_FIXED & & ! ( val & PLL_BASE_OVERRIDE ) ) {
2012-08-06 11:57:43 +05:30
const struct clk_pll_freq_table * sel ;
for ( sel = c - > u . pll . freq_table ; sel - > input_rate ! = 0 ; sel + + ) {
if ( sel - > input_rate = = prate & &
sel - > output_rate = = c - > u . pll . fixed_rate ) {
c - > mul = sel - > n ;
c - > div = sel - > m * sel - > p ;
break ;
}
}
pr_err ( " Clock %s has unknown fixed frequency \n " ,
__clk_get_name ( hw - > clk ) ) ;
BUG ( ) ;
2010-01-28 16:40:29 -08:00
} else if ( val & PLL_BASE_BYPASS ) {
2010-06-07 20:49:46 -07:00
c - > mul = 1 ;
c - > div = 1 ;
2010-01-28 16:40:29 -08:00
} else {
2010-06-07 20:49:46 -07: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-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
if ( c - > mul ! = 0 & & c - > div ! = 0 ) {
rate * = c - > mul ;
rate + = c - > div - 1 ; /* round up */
do_div ( rate , c - > div ) ;
}
return rate ;
2010-01-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
static int tegra20_pll_clk_enable ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-01-28 16:40:29 -08:00
u32 val ;
2012-08-06 11:57:43 +05:30
pr_debug ( " %s on clock %s \n " , __func__ , __clk_get_name ( hw - > clk ) ) ;
2010-01-28 16:40:29 -08:00
val = clk_readl ( c - > reg + PLL_BASE ) ;
val & = ~ PLL_BASE_BYPASS ;
val | = PLL_BASE_ENABLE ;
clk_writel ( val , c - > reg + PLL_BASE ) ;
2012-08-06 11:57:43 +05:30
tegra20_pll_clk_wait_for_lock ( c ) ;
2010-01-28 16:40:29 -08:00
return 0 ;
}
2012-08-06 11:57:43 +05:30
static void tegra20_pll_clk_disable ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-01-28 16:40:29 -08:00
u32 val ;
2012-08-06 11:57:43 +05:30
pr_debug ( " %s on clock %s \n " , __func__ , __clk_get_name ( hw - > clk ) ) ;
2010-01-28 16:40:29 -08:00
val = clk_readl ( c - > reg ) ;
val & = ~ ( PLL_BASE_BYPASS | PLL_BASE_ENABLE ) ;
clk_writel ( val , c - > reg ) ;
}
2012-08-06 11:57:43 +05:30
static int tegra20_pll_clk_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
unsigned long input_rate = parent_rate ;
2011-02-12 16:05:31 -08:00
const struct clk_pll_freq_table * sel ;
2012-08-06 11:57:43 +05:30
u32 val ;
2010-01-28 16:40:29 -08:00
2012-08-06 11:57:43 +05:30
pr_debug ( " %s: %s %lu \n " , __func__ , __clk_get_name ( hw - > clk ) , rate ) ;
if ( c - > flags & PLL_FIXED ) {
int ret = 0 ;
if ( rate ! = c - > u . pll . fixed_rate ) {
pr_err ( " %s: Can not change %s fixed rate %lu to %lu \n " ,
__func__ , __clk_get_name ( hw - > clk ) ,
c - > u . pll . fixed_rate , rate ) ;
ret = - EINVAL ;
}
return ret ;
}
2010-01-28 16:40:29 -08:00
2011-02-12 16:05:31 -08:00
for ( sel = c - > u . pll . freq_table ; sel - > input_rate ! = 0 ; sel + + ) {
2010-01-28 16:40:29 -08:00
if ( sel - > input_rate = = input_rate & & sel - > output_rate = = rate ) {
2010-06-07 20:49:46 -07:00
c - > mul = sel - > n ;
c - > div = sel - > m * sel - > p ;
2010-01-28 16: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-07 20:49:46 -07: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-28 16:40:29 -08:00
clk_writel ( val , c - > reg + PLL_BASE ) ;
if ( c - > flags & PLL_HAS_CPCON ) {
2010-06-07 20:49:46 -07:00
val = clk_readl ( c - > reg + PLL_MISC ( c ) ) ;
val & = ~ PLL_MISC_CPCON_MASK ;
val | = sel - > cpcon < < PLL_MISC_CPCON_SHIFT ;
2010-01-28 16:40:29 -08:00
clk_writel ( val , c - > reg + PLL_MISC ( c ) ) ;
}
if ( c - > state = = ON )
2012-08-06 11:57:43 +05:30
tegra20_pll_clk_enable ( hw ) ;
2010-01-28 16:40:29 -08:00
return 0 ;
}
}
return - EINVAL ;
}
2012-08-06 11:57:43 +05:30
static long tegra20_pll_clk_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
struct clk_tegra * c = to_clk_tegra ( hw ) ;
const struct clk_pll_freq_table * sel ;
unsigned long input_rate = * prate ;
2012-09-10 17:02:45 -06:00
u64 output_rate = * prate ;
2012-08-06 11:57:43 +05:30
int mul ;
int div ;
if ( c - > flags & PLL_FIXED )
return c - > u . pll . fixed_rate ;
for ( sel = c - > u . pll . freq_table ; sel - > input_rate ! = 0 ; sel + + )
if ( sel - > input_rate = = input_rate & & sel - > output_rate = = rate ) {
mul = sel - > n ;
div = sel - > m * sel - > p ;
break ;
}
if ( sel - > input_rate = = 0 )
return - EINVAL ;
output_rate * = mul ;
output_rate + = div - 1 ; /* round up */
do_div ( output_rate , div ) ;
return output_rate ;
}
2012-08-06 11:57:40 +05:30
struct clk_ops tegra_pll_ops = {
2012-08-06 11:57:43 +05:30
. is_enabled = tegra20_pll_clk_is_enabled ,
. enable = tegra20_pll_clk_enable ,
. disable = tegra20_pll_clk_disable ,
. set_rate = tegra20_pll_clk_set_rate ,
. recalc_rate = tegra20_pll_clk_recalc_rate ,
. round_rate = tegra20_pll_clk_round_rate ,
2010-06-07 20:49:46 -07:00
} ;
2012-08-06 11:57:43 +05:30
static void tegra20_pllx_clk_init ( struct clk_hw * hw )
2010-06-07 20:49:46 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-06-07 20:49:46 -07:00
2011-10-13 00:31:20 -07:00
if ( tegra_sku_id = = 7 )
2010-06-07 20:49:46 -07:00
c - > max_rate = 750000000 ;
}
2012-08-06 11:57:40 +05:30
struct clk_ops tegra_pllx_ops = {
2012-08-06 11:57:43 +05:30
. init = tegra20_pllx_clk_init ,
. is_enabled = tegra20_pll_clk_is_enabled ,
. enable = tegra20_pll_clk_enable ,
. disable = tegra20_pll_clk_disable ,
. set_rate = tegra20_pll_clk_set_rate ,
. recalc_rate = tegra20_pll_clk_recalc_rate ,
. round_rate = tegra20_pll_clk_round_rate ,
2010-01-28 16:40:29 -08:00
} ;
2012-08-06 11:57:43 +05:30
static int tegra20_plle_clk_enable ( struct clk_hw * hw )
2010-09-27 11:26:32 +02:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-09-27 11:26:32 +02:00
u32 val ;
2012-08-06 11:57:43 +05:30
pr_debug ( " %s on clock %s \n " , __func__ , __clk_get_name ( hw - > clk ) ) ;
2010-09-27 11:26:32 +02:00
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 ;
}
2012-08-06 11:57:40 +05:30
struct clk_ops tegra_plle_ops = {
2012-08-06 11:57:43 +05:30
. is_enabled = tegra20_pll_clk_is_enabled ,
. enable = tegra20_plle_clk_enable ,
. set_rate = tegra20_pll_clk_set_rate ,
. recalc_rate = tegra20_pll_clk_recalc_rate ,
. round_rate = tegra20_pll_clk_round_rate ,
2010-09-27 11:26:32 +02:00
} ;
2010-01-28 16:40:29 -08:00
/* Clock divider ops */
2012-08-06 11:57:43 +05:30
static int tegra20_pll_div_clk_is_enabled ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-01-28 16:40:29 -08:00
u32 val = clk_readl ( c - > reg ) ;
2012-08-06 11:57:43 +05:30
2010-01-28 16:40:29 -08:00
val > > = c - > reg_shift ;
c - > state = ( val & PLL_OUT_CLKEN ) ? ON : OFF ;
if ( ! ( val & PLL_OUT_RESET_DISABLE ) )
c - > state = OFF ;
2012-08-06 11:57:43 +05:30
return c - > state ;
}
static unsigned long tegra20_pll_div_clk_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
{
struct clk_tegra * c = to_clk_tegra ( hw ) ;
u64 rate = prate ;
u32 val = clk_readl ( c - > reg ) ;
u32 divu71 ;
val > > = c - > reg_shift ;
2010-01-28 16:40:29 -08:00
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 ;
}
2012-08-06 11:57:43 +05:30
rate * = c - > mul ;
rate + = c - > div - 1 ; /* round up */
do_div ( rate , c - > div ) ;
return rate ;
2010-01-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
static int tegra20_pll_div_clk_enable ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2011-02-12 16:43:05 -08:00
unsigned long flags ;
2012-08-06 11:57:43 +05:30
u32 new_val ;
u32 val ;
pr_debug ( " %s: %s \n " , __func__ , __clk_get_name ( hw - > clk ) ) ;
2010-01-28 16:40:29 -08:00
if ( c - > flags & DIV_U71 ) {
2011-02-12 16:43:05 -08:00
spin_lock_irqsave ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
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 ) ;
2011-02-12 16:43:05 -08:00
spin_unlock_irqrestore ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
return 0 ;
} else if ( c - > flags & DIV_2 ) {
BUG_ON ( ! ( c - > flags & PLLD ) ) ;
2011-02-12 16:43:05 -08:00
spin_lock_irqsave ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
val = clk_readl ( c - > reg ) ;
val & = ~ PLLD_MISC_DIV_RST ;
clk_writel ( val , c - > reg ) ;
2011-02-12 16:43:05 -08:00
spin_unlock_irqrestore ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
return 0 ;
}
return - EINVAL ;
}
2012-08-06 11:57:43 +05:30
static void tegra20_pll_div_clk_disable ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2011-02-12 16:43:05 -08:00
unsigned long flags ;
2012-08-06 11:57:43 +05:30
u32 new_val ;
u32 val ;
pr_debug ( " %s: %s \n " , __func__ , __clk_get_name ( hw - > clk ) ) ;
2010-01-28 16:40:29 -08:00
if ( c - > flags & DIV_U71 ) {
2011-02-12 16:43:05 -08:00
spin_lock_irqsave ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
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 ) ;
2011-02-12 16:43:05 -08:00
spin_unlock_irqrestore ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
} else if ( c - > flags & DIV_2 ) {
BUG_ON ( ! ( c - > flags & PLLD ) ) ;
2011-02-12 16:43:05 -08:00
spin_lock_irqsave ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
val = clk_readl ( c - > reg ) ;
val | = PLLD_MISC_DIV_RST ;
clk_writel ( val , c - > reg ) ;
2011-02-12 16:43:05 -08:00
spin_unlock_irqrestore ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
}
}
2012-08-06 11:57:43 +05:30
static int tegra20_pll_div_clk_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2011-02-12 16:43:05 -08:00
unsigned long flags ;
2012-08-06 11:57:43 +05:30
int divider_u71 ;
u32 new_val ;
u32 val ;
pr_debug ( " %s: %s %lu \n " , __func__ , __clk_get_name ( hw - > clk ) , rate ) ;
2011-02-12 16:43:05 -08:00
2010-01-28 16:40:29 -08:00
if ( c - > flags & DIV_U71 ) {
2011-02-12 16:43:05 -08:00
divider_u71 = clk_div71_get_divider ( parent_rate , rate ) ;
2010-01-28 16:40:29 -08:00
if ( divider_u71 > = 0 ) {
2011-02-12 16:43:05 -08:00
spin_lock_irqsave ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
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 ;
2011-02-12 16:43:05 -08:00
spin_unlock_irqrestore ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
return 0 ;
}
} else if ( c - > flags & DIV_2 ) {
2011-02-12 16:43:05 -08:00
if ( parent_rate = = rate * 2 )
2010-01-28 16:40:29 -08:00
return 0 ;
}
return - EINVAL ;
}
2012-08-06 11:57:43 +05:30
static long tegra20_pll_div_clk_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
2010-06-07 20:49:46 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
unsigned long parent_rate = * prate ;
2010-06-07 20:49:46 -07:00
int divider ;
2012-08-06 11:57:43 +05:30
pr_debug ( " %s: %s %lu \n " , __func__ , __clk_get_name ( hw - > clk ) , rate ) ;
2010-06-07 20:49:46 -07:00
if ( c - > flags & DIV_U71 ) {
2011-02-12 16:43:05 -08:00
divider = clk_div71_get_divider ( parent_rate , rate ) ;
2010-06-07 20:49:46 -07:00
if ( divider < 0 )
return divider ;
2011-02-12 18:21:47 -08:00
return DIV_ROUND_UP ( parent_rate * 2 , divider + 2 ) ;
2010-06-07 20:49:46 -07:00
} else if ( c - > flags & DIV_2 ) {
2011-02-12 18:21:47 -08:00
return DIV_ROUND_UP ( parent_rate , 2 ) ;
2010-06-07 20:49:46 -07:00
}
return - EINVAL ;
}
2010-01-28 16:40:29 -08:00
2012-08-06 11:57:40 +05:30
struct clk_ops tegra_pll_div_ops = {
2012-08-06 11:57:43 +05:30
. is_enabled = tegra20_pll_div_clk_is_enabled ,
. enable = tegra20_pll_div_clk_enable ,
. disable = tegra20_pll_div_clk_disable ,
. set_rate = tegra20_pll_div_clk_set_rate ,
. round_rate = tegra20_pll_div_clk_round_rate ,
. recalc_rate = tegra20_pll_div_clk_recalc_rate ,
2010-01-28 16:40:29 -08:00
} ;
/* Periph clk ops */
2012-08-06 11:57:43 +05:30
static int tegra20_periph_clk_is_enabled ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-01-28 16:40:29 -08:00
c - > state = ON ;
2011-02-21 16:44:07 -08:00
if ( ! c - > u . periph . clk_num )
2012-08-06 11:57:43 +05:30
goto out ;
2011-02-21 16:44:07 -08:00
2010-01-28 16:40:29 -08:00
if ( ! ( clk_readl ( CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG ( c ) ) &
PERIPH_CLK_TO_ENB_BIT ( c ) ) )
c - > state = OFF ;
2011-02-21 16:44:07 -08:00
2010-01-28 16:40:29 -08:00
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 ;
2012-08-06 11:57:43 +05:30
out :
return c - > state ;
2010-01-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
static int tegra20_periph_clk_enable ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-10-20 19:19:58 -07:00
unsigned long flags ;
2012-08-06 11:57:43 +05:30
u32 val ;
pr_debug ( " %s on clock %s \n " , __func__ , __clk_get_name ( hw - > clk ) ) ;
2010-01-28 16:40:29 -08:00
2011-02-21 16:44:07 -08:00
if ( ! c - > u . periph . clk_num )
return 0 ;
2012-08-06 11:57:43 +05:30
tegra_periph_clk_enable_refcount [ c - > u . periph . clk_num ] + + ;
if ( tegra_periph_clk_enable_refcount [ c - > u . periph . clk_num ] > 1 )
return 0 ;
2010-10-20 19:19:58 -07:00
2012-08-06 11:57:43 +05:30
spin_lock_irqsave ( & clock_register_lock , flags ) ;
2010-10-20 19:19:58 -07:00
2010-01-28 16:40:29 -08:00
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 ) ;
}
2010-10-20 19:19:58 -07:00
spin_unlock_irqrestore ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
return 0 ;
}
2012-08-06 11:57:43 +05:30
static void tegra20_periph_clk_disable ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-10-20 19:19:58 -07:00
unsigned long flags ;
2012-08-06 11:57:43 +05:30
pr_debug ( " %s on clock %s \n " , __func__ , __clk_get_name ( hw - > clk ) ) ;
2010-01-28 16:40:29 -08:00
2011-02-21 16:44:07 -08:00
if ( ! c - > u . periph . clk_num )
return ;
2012-08-06 11:57:43 +05:30
tegra_periph_clk_enable_refcount [ c - > u . periph . clk_num ] - - ;
2010-10-20 19:19:58 -07:00
2012-08-06 11:57:43 +05:30
if ( tegra_periph_clk_enable_refcount [ c - > u . periph . clk_num ] > 0 )
return ;
2010-10-20 19:19:58 -07:00
2012-08-06 11:57:43 +05:30
spin_lock_irqsave ( & clock_register_lock , flags ) ;
clk_writel ( PERIPH_CLK_TO_ENB_BIT ( c ) ,
CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG ( c ) ) ;
2010-10-20 19:19:58 -07:00
spin_unlock_irqrestore ( & clock_register_lock , flags ) ;
2010-01-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
void tegra2_periph_clk_reset ( struct clk_hw * hw , bool assert )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-09-02 19:11:11 -07:00
unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR ;
2010-01-28 16:40:29 -08:00
2010-09-02 19:11:11 -07:00
pr_debug ( " %s %s on clock %s \n " , __func__ ,
2012-08-06 11:57:43 +05:30
assert ? " assert " : " deassert " , __clk_get_name ( hw - > clk ) ) ;
2011-02-21 16:44:07 -08:00
BUG_ON ( ! c - > u . periph . clk_num ) ;
2010-01-28 16:40:29 -08:00
if ( ! ( c - > flags & PERIPH_NO_RESET ) )
clk_writel ( PERIPH_CLK_TO_ENB_BIT ( c ) ,
2010-09-02 19:11:11 -07:00
base + PERIPH_CLK_TO_ENB_SET_REG ( c ) ) ;
2010-01-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
static int tegra20_periph_clk_set_parent ( struct clk_hw * hw , u8 index )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-01-28 16:40:29 -08:00
u32 val ;
2012-08-06 11:57:43 +05:30
u32 mask ;
u32 shift ;
2011-12-16 20:11:22 +01:00
2012-08-06 11:57:43 +05:30
pr_debug ( " %s: %s %d \n " , __func__ , __clk_get_name ( hw - > clk ) , index ) ;
2011-12-16 20:11:22 +01:00
if ( c - > flags & MUX_PWM ) {
shift = PERIPH_CLK_SOURCE_PWM_SHIFT ;
mask = PERIPH_CLK_SOURCE_PWM_MASK ;
} else {
shift = PERIPH_CLK_SOURCE_SHIFT ;
mask = PERIPH_CLK_SOURCE_MASK ;
}
2012-08-06 11:57:43 +05:30
val = clk_readl ( c - > reg ) ;
val & = ~ mask ;
val | = ( index ) < < shift ;
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
clk_writel ( val , c - > reg ) ;
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
return 0 ;
}
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
static u8 tegra20_periph_clk_get_parent ( struct clk_hw * hw )
{
struct clk_tegra * c = to_clk_tegra ( hw ) ;
u32 val = clk_readl ( c - > reg ) ;
u32 mask ;
u32 shift ;
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
if ( c - > flags & MUX_PWM ) {
shift = PERIPH_CLK_SOURCE_PWM_SHIFT ;
mask = PERIPH_CLK_SOURCE_PWM_MASK ;
} else {
shift = PERIPH_CLK_SOURCE_SHIFT ;
mask = PERIPH_CLK_SOURCE_MASK ;
2010-01-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
if ( c - > flags & MUX )
return ( val & mask ) > > shift ;
else
return 0 ;
2010-01-28 16:40:29 -08:00
}
2012-08-06 11:57:43 +05:30
static unsigned long tegra20_periph_clk_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
unsigned long rate = prate ;
u32 val = clk_readl ( c - > reg ) ;
if ( c - > flags & DIV_U71 ) {
u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK ;
c - > div = divu71 + 2 ;
c - > mul = 2 ;
} else if ( c - > flags & DIV_U16 ) {
u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK ;
c - > div = divu16 + 1 ;
c - > mul = 1 ;
} else {
c - > div = 1 ;
c - > mul = 1 ;
return rate ;
}
if ( c - > mul ! = 0 & & c - > div ! = 0 ) {
rate * = c - > mul ;
rate + = c - > div - 1 ; /* round up */
do_div ( rate , c - > div ) ;
}
return rate ;
}
static int tegra20_periph_clk_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-01-28 16:40:29 -08:00
u32 val ;
2010-06-07 20:49:46 -07:00
int divider ;
2012-08-06 11:57:43 +05:30
val = clk_readl ( c - > reg ) ;
2011-02-12 16:43:05 -08:00
2010-01-28 16:40:29 -08:00
if ( c - > flags & DIV_U71 ) {
2011-02-12 16:43:05 -08:00
divider = clk_div71_get_divider ( parent_rate , rate ) ;
2012-08-06 11:57:43 +05:30
2010-06-07 20:49:46 -07:00
if ( divider > = 0 ) {
2010-01-28 16:40:29 -08:00
val = clk_readl ( c - > reg ) ;
2010-06-07 20:49:46 -07:00
val & = ~ PERIPH_CLK_SOURCE_DIVU71_MASK ;
val | = divider ;
2010-01-28 16:40:29 -08:00
clk_writel ( val , c - > reg ) ;
2010-06-07 20:49:46 -07:00
c - > div = divider + 2 ;
2010-01-28 16:40:29 -08:00
c - > mul = 2 ;
return 0 ;
}
2010-06-07 20:49:46 -07:00
} else if ( c - > flags & DIV_U16 ) {
2011-02-12 16:43:05 -08:00
divider = clk_div16_get_divider ( parent_rate , rate ) ;
2010-06-07 20:49:46 -07:00
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 ;
}
2011-02-12 16:43:05 -08:00
} else if ( parent_rate < = rate ) {
2010-06-07 20:49:46 -07:00
c - > div = 1 ;
c - > mul = 1 ;
return 0 ;
}
2012-08-06 11:57:43 +05:30
2010-06-07 20:49:46 -07:00
return - EINVAL ;
}
2012-08-06 11:57:43 +05:30
static long tegra20_periph_clk_round_rate ( struct clk_hw * hw ,
unsigned long rate , unsigned long * prate )
2010-06-07 20:49:46 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
unsigned long parent_rate = __clk_get_rate ( __clk_get_parent ( hw - > clk ) ) ;
2010-06-07 20:49:46 -07:00
int divider ;
2012-08-06 11:57:43 +05:30
pr_debug ( " %s: %s %lu \n " , __func__ , __clk_get_name ( hw - > clk ) , rate ) ;
if ( prate )
parent_rate = * prate ;
2010-06-07 20:49:46 -07:00
if ( c - > flags & DIV_U71 ) {
2011-02-12 16:43:05 -08:00
divider = clk_div71_get_divider ( parent_rate , rate ) ;
2010-06-07 20:49:46 -07:00
if ( divider < 0 )
return divider ;
2011-02-12 18:21:47 -08:00
return DIV_ROUND_UP ( parent_rate * 2 , divider + 2 ) ;
2010-06-07 20:49:46 -07:00
} else if ( c - > flags & DIV_U16 ) {
2011-02-12 16:43:05 -08:00
divider = clk_div16_get_divider ( parent_rate , rate ) ;
2010-06-07 20:49:46 -07:00
if ( divider < 0 )
return divider ;
2011-02-12 18:21:47 -08:00
return DIV_ROUND_UP ( parent_rate , divider + 1 ) ;
2010-01-28 16:40:29 -08:00
}
return - EINVAL ;
}
2012-08-06 11:57:40 +05:30
struct clk_ops tegra_periph_clk_ops = {
2012-08-06 11:57:43 +05:30
. is_enabled = tegra20_periph_clk_is_enabled ,
. enable = tegra20_periph_clk_enable ,
. disable = tegra20_periph_clk_disable ,
. set_parent = tegra20_periph_clk_set_parent ,
. get_parent = tegra20_periph_clk_get_parent ,
. set_rate = tegra20_periph_clk_set_rate ,
. round_rate = tegra20_periph_clk_round_rate ,
. recalc_rate = tegra20_periph_clk_recalc_rate ,
2010-01-28 16:40:29 -08:00
} ;
2010-11-22 18:37:54 -08:00
/* External memory controller clock ops */
2012-08-06 11:57:43 +05:30
static void tegra20_emc_clk_init ( struct clk_hw * hw )
2010-11-22 18:37:54 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
c - > max_rate = __clk_get_rate ( hw - > clk ) ;
2010-11-22 18:37:54 -08:00
}
2012-08-06 11:57:43 +05:30
static long tegra20_emc_clk_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
2010-11-22 18:37:54 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2012-02-06 17:09:15 -08:00
long emc_rate ;
long clk_rate ;
2010-11-22 18:37:54 -08:00
2012-02-06 17:09:15 -08:00
/*
* The slowest entry in the EMC clock table that is at least as
* fast as rate .
*/
emc_rate = tegra_emc_round_rate ( rate ) ;
if ( emc_rate < 0 )
2010-11-22 18:37:54 -08:00
return c - > max_rate ;
2012-02-06 17:09:15 -08:00
/*
* The fastest rate the PLL will generate that is at most the
* requested rate .
*/
2012-08-06 11:57:43 +05:30
clk_rate = tegra20_periph_clk_round_rate ( hw , emc_rate , NULL ) ;
2012-02-06 17:09:15 -08:00
/*
* If this fails , and emc_rate > clk_rate , it ' s because the maximum
* rate in the EMC tables is larger than the maximum rate of the EMC
* clock . The EMC clock ' s max rate is the rate it was running when the
* kernel booted . Such a mismatch is probably due to using the wrong
* BCT , i . e . using a Tegra20 BCT with an EMC table written for Tegra25 .
*/
WARN_ONCE ( emc_rate ! = clk_rate ,
" emc_rate %ld != clk_rate %ld " ,
emc_rate , clk_rate ) ;
2010-11-22 18:37:54 -08:00
2012-02-06 17:09:15 -08:00
return emc_rate ;
2010-11-22 18:37:54 -08:00
}
2012-08-06 11:57:43 +05:30
static int tegra20_emc_clk_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
2010-11-22 18:37:54 -08:00
{
int ret ;
2012-08-06 11:57:43 +05:30
2010-11-22 18:37:54 -08:00
/*
* The Tegra2 memory controller has an interlock with the clock
* block that allows memory shadowed registers to be updated ,
* and then transfer them to the main registers at the same
* time as the clock update without glitches .
*/
ret = tegra_emc_set_rate ( rate ) ;
if ( ret < 0 )
return ret ;
2012-08-06 11:57:43 +05:30
ret = tegra20_periph_clk_set_rate ( hw , rate , parent_rate ) ;
2010-11-22 18:37:54 -08:00
udelay ( 1 ) ;
return ret ;
}
2012-08-06 11:57:40 +05:30
struct clk_ops tegra_emc_clk_ops = {
2012-08-06 11:57:43 +05:30
. init = tegra20_emc_clk_init ,
. is_enabled = tegra20_periph_clk_is_enabled ,
. enable = tegra20_periph_clk_enable ,
. disable = tegra20_periph_clk_disable ,
. set_parent = tegra20_periph_clk_set_parent ,
. get_parent = tegra20_periph_clk_get_parent ,
. set_rate = tegra20_emc_clk_set_rate ,
. round_rate = tegra20_emc_clk_round_rate ,
. recalc_rate = tegra20_periph_clk_recalc_rate ,
2010-11-22 18:37:54 -08:00
} ;
2010-01-28 16:40:29 -08:00
/* Clock doubler ops */
2012-08-06 11:57:43 +05:30
static int tegra20_clk_double_is_enabled ( struct clk_hw * hw )
2010-01-28 16:40:29 -08:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-01-28 16:40:29 -08:00
c - > state = ON ;
2011-02-21 16:44:07 -08:00
if ( ! c - > u . periph . clk_num )
2012-08-06 11:57:43 +05:30
goto out ;
2011-02-21 16:44:07 -08:00
2010-01-28 16:40:29 -08:00
if ( ! ( clk_readl ( CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG ( c ) ) &
PERIPH_CLK_TO_ENB_BIT ( c ) ) )
c - > state = OFF ;
2012-08-06 11:57:43 +05:30
out :
return c - > state ;
2010-01-28 16:40:29 -08:00
} ;
2012-08-06 11:57:43 +05:30
static unsigned long tegra20_clk_double_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
2010-06-07 20:49:46 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
u64 rate = prate ;
2010-06-07 20:49:46 -07:00
c - > mul = 2 ;
c - > div = 1 ;
2012-08-06 11:57:43 +05:30
rate * = c - > mul ;
rate + = c - > div - 1 ; /* round up */
do_div ( rate , c - > div ) ;
return rate ;
}
static long tegra20_clk_double_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
unsigned long output_rate = * prate ;
do_div ( output_rate , 2 ) ;
return output_rate ;
}
static int tegra20_clk_double_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
if ( rate ! = 2 * parent_rate )
return - EINVAL ;
2010-06-07 20:49:46 -07:00
return 0 ;
}
2012-08-06 11:57:40 +05:30
struct clk_ops tegra_clk_double_ops = {
2012-08-06 11:57:43 +05:30
. is_enabled = tegra20_clk_double_is_enabled ,
. enable = tegra20_periph_clk_enable ,
. disable = tegra20_periph_clk_disable ,
. set_rate = tegra20_clk_double_set_rate ,
. recalc_rate = tegra20_clk_double_recalc_rate ,
. round_rate = tegra20_clk_double_round_rate ,
2010-06-07 20:49:46 -07:00
} ;
2010-10-04 11:49:26 -07:00
/* Audio sync clock ops */
2012-08-06 11:57:43 +05:30
static int tegra20_audio_sync_clk_is_enabled ( struct clk_hw * hw )
2010-06-07 20:49:46 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-06-07 20:49:46 -07:00
u32 val = clk_readl ( c - > reg ) ;
2012-08-06 11:57:43 +05:30
2010-06-07 20:49:46 -07:00
c - > state = ( val & ( 1 < < 4 ) ) ? OFF : ON ;
2012-08-06 11:57:43 +05:30
return c - > state ;
2010-06-07 20:49:46 -07:00
}
2012-08-06 11:57:43 +05:30
static int tegra20_audio_sync_clk_enable ( struct clk_hw * hw )
2010-06-07 20:49:46 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-06-07 20:49:46 -07:00
clk_writel ( 0 , c - > reg ) ;
return 0 ;
}
2012-08-06 11:57:43 +05:30
static void tegra20_audio_sync_clk_disable ( struct clk_hw * hw )
2010-06-07 20:49:46 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-06-07 20:49:46 -07:00
clk_writel ( 1 , c - > reg ) ;
}
2012-08-06 11:57:43 +05:30
static u8 tegra20_audio_sync_clk_get_parent ( struct clk_hw * hw )
2010-06-07 20:49:46 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
u32 val = clk_readl ( c - > reg ) ;
int source ;
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
source = val & 0xf ;
return source ;
}
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
static int tegra20_audio_sync_clk_set_parent ( struct clk_hw * hw , u8 index )
{
struct clk_tegra * c = to_clk_tegra ( hw ) ;
u32 val ;
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
val = clk_readl ( c - > reg ) ;
val & = ~ 0xf ;
val | = index ;
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
clk_writel ( val , c - > reg ) ;
2010-06-07 20:49:46 -07:00
2012-08-06 11:57:43 +05:30
return 0 ;
2010-06-07 20:49:46 -07:00
}
2012-08-06 11:57:40 +05:30
struct clk_ops tegra_audio_sync_clk_ops = {
2012-08-06 11:57:43 +05:30
. is_enabled = tegra20_audio_sync_clk_is_enabled ,
. enable = tegra20_audio_sync_clk_enable ,
. disable = tegra20_audio_sync_clk_disable ,
. set_parent = tegra20_audio_sync_clk_set_parent ,
. get_parent = tegra20_audio_sync_clk_get_parent ,
2010-01-28 16:40:29 -08:00
} ;
2010-10-04 11:49:26 -07:00
/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */
2012-08-06 11:57:43 +05:30
static int tegra20_cdev_clk_is_enabled ( struct clk_hw * hw )
2010-10-04 11:49:26 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2010-10-04 11:49:26 -07:00
/* We could un-tristate the cdev1 or cdev2 pingroup here; this is
* currently done in the pinmux code . */
c - > state = ON ;
2011-02-21 16:44:07 -08:00
BUG_ON ( ! c - > u . periph . clk_num ) ;
2010-10-04 11:49:26 -07:00
if ( ! ( clk_readl ( CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG ( c ) ) &
PERIPH_CLK_TO_ENB_BIT ( c ) ) )
c - > state = OFF ;
2012-08-06 11:57:43 +05:30
return c - > state ;
2010-10-04 11:49:26 -07:00
}
2012-08-06 11:57:43 +05:30
static int tegra20_cdev_clk_enable ( struct clk_hw * hw )
2010-10-04 11:49:26 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2011-02-21 16:44:07 -08:00
BUG_ON ( ! c - > u . periph . clk_num ) ;
2010-10-04 11:49:26 -07:00
clk_writel ( PERIPH_CLK_TO_ENB_BIT ( c ) ,
CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG ( c ) ) ;
return 0 ;
}
2012-08-06 11:57:43 +05:30
static void tegra20_cdev_clk_disable ( struct clk_hw * hw )
2010-10-04 11:49:26 -07:00
{
2012-08-06 11:57:43 +05:30
struct clk_tegra * c = to_clk_tegra ( hw ) ;
2011-02-21 16:44:07 -08:00
BUG_ON ( ! c - > u . periph . clk_num ) ;
2010-10-04 11:49:26 -07:00
clk_writel ( PERIPH_CLK_TO_ENB_BIT ( c ) ,
CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG ( c ) ) ;
}
2012-08-06 11:57:43 +05:30
static unsigned long tegra20_cdev_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
2011-02-12 16:14:03 -08:00
{
2012-08-06 11:57:43 +05:30
return to_clk_tegra ( hw ) - > fixed_rate ;
2011-02-12 16:14:03 -08:00
}
2012-08-06 11:57:43 +05:30
struct clk_ops tegra_cdev_clk_ops = {
. is_enabled = tegra20_cdev_clk_is_enabled ,
. enable = tegra20_cdev_clk_enable ,
. disable = tegra20_cdev_clk_disable ,
. recalc_rate = tegra20_cdev_recalc_rate ,
2011-02-12 16:14:03 -08:00
} ;
2012-08-16 17:31:48 +08:00
/* Tegra20 CPU clock and reset control functions */
static void tegra20_wait_cpu_in_reset ( u32 cpu )
{
unsigned int reg ;
do {
reg = readl ( reg_clk_base +
TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET ) ;
cpu_relax ( ) ;
} while ( ! ( reg & ( 1 < < cpu ) ) ) ; /* check CPU been reset or not */
return ;
}
static void tegra20_put_cpu_in_reset ( u32 cpu )
{
writel ( CPU_RESET ( cpu ) ,
reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET ) ;
dmb ( ) ;
}
static void tegra20_cpu_out_of_reset ( u32 cpu )
{
writel ( CPU_RESET ( cpu ) ,
reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR ) ;
wmb ( ) ;
}
static void tegra20_enable_cpu_clock ( u32 cpu )
{
unsigned int reg ;
reg = readl ( reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX ) ;
writel ( reg & ~ CPU_CLOCK ( cpu ) ,
reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX ) ;
barrier ( ) ;
reg = readl ( reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX ) ;
}
static void tegra20_disable_cpu_clock ( u32 cpu )
{
unsigned int reg ;
reg = readl ( reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX ) ;
writel ( reg | CPU_CLOCK ( cpu ) ,
reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX ) ;
}
static struct tegra_cpu_car_ops tegra20_cpu_car_ops = {
. wait_for_reset = tegra20_wait_cpu_in_reset ,
. put_in_reset = tegra20_put_cpu_in_reset ,
. out_of_reset = tegra20_cpu_out_of_reset ,
. enable_clock = tegra20_enable_cpu_clock ,
. disable_clock = tegra20_disable_cpu_clock ,
} ;
void __init tegra20_cpu_car_ops_init ( void )
{
tegra_cpu_car_ops = & tegra20_cpu_car_ops ;
}