diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index f1f9c6d36bd2..165aa9c748f6 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -390,6 +390,20 @@ void __init tegra_init_clock(void) tegra2_init_clocks(); } +/* + * The SDMMC controllers have extra bits in the clock source register that + * adjust the delay between the clock and data to compenstate for delays + * on the PCB. + */ +void tegra_sdmmc_tap_delay(struct clk *c, int delay) +{ + unsigned long flags; + + spin_lock_irqsave(&c->spinlock, flags); + tegra2_sdmmc_tap_delay(c, delay); + spin_unlock_irqrestore(&c->spinlock, flags); +} + #ifdef CONFIG_DEBUG_FS static int __clk_lock_all_spinlocks(void) diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h index ebe6ea8b0575..688316abc64e 100644 --- a/arch/arm/mach-tegra/clock.h +++ b/arch/arm/mach-tegra/clock.h @@ -155,5 +155,6 @@ int clk_reparent(struct clk *c, struct clk *parent); void tegra_clk_init_from_table(struct tegra_clk_init_table *table); unsigned long clk_get_rate_locked(struct clk *c); int clk_set_rate_locked(struct clk *c, unsigned long rate); +void tegra2_sdmmc_tap_delay(struct clk *c, int delay); #endif diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h index fa7f9ca1fdbd..c8baf8f80d23 100644 --- a/arch/arm/mach-tegra/include/mach/clk.h +++ b/arch/arm/mach-tegra/include/mach/clk.h @@ -26,4 +26,6 @@ void tegra_periph_reset_deassert(struct clk *c); void tegra_periph_reset_assert(struct clk *c); unsigned long clk_get_rate_all_locked(struct clk *c); +void tegra_sdmmc_tap_delay(struct clk *c, int delay); + #endif diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index 7f7068714049..b85d2c75fb3c 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -74,6 +74,10 @@ #define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF #define PERIPH_CLK_SOURCE_DIV_SHIFT 0 +#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) + #define PLL_BASE 0x0 #define PLL_BASE_BYPASS (1<<31) #define PLL_BASE_ENABLE (1<<30) @@ -1052,6 +1056,21 @@ static struct clk_ops tegra_periph_clk_ops = { .reset = &tegra2_periph_clk_reset, }; +/* The SDMMC controllers have extra bits in the clock source register that + * adjust the delay between the clock and data to compenstate for delays + * on the PCB. */ +void tegra2_sdmmc_tap_delay(struct clk *c, int delay) +{ + u32 reg; + + delay = clamp(delay, 0, 15); + reg = clk_readl(c->reg); + reg &= ~SDMMC_CLK_INT_FB_DLY_MASK; + reg |= SDMMC_CLK_INT_FB_SEL; + reg |= delay << SDMMC_CLK_INT_FB_DLY_SHIFT; + clk_writel(reg, c->reg); +} + /* External memory controller clock ops */ static void tegra2_emc_clk_init(struct clk *c) {