]> git.karo-electronics.de Git - linux-beck.git/commitdiff
ARM: tegra: clock: Add function to set SDMMC tap delay
authorColin Cross <ccross@android.com>
Sun, 13 Feb 2011 02:24:32 +0000 (18:24 -0800)
committerColin Cross <ccross@android.com>
Mon, 21 Feb 2011 08:16:47 +0000 (00:16 -0800)
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.  The values need to
be set from the clock code so the clock can be locked
during the read-modify-write on the clock source register.

Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Colin Cross <ccross@android.com>
arch/arm/mach-tegra/clock.c
arch/arm/mach-tegra/clock.h
arch/arm/mach-tegra/include/mach/clk.h
arch/arm/mach-tegra/tegra2_clocks.c

index f1f9c6d36bd2f60488906976682901d5b9cc0a2a..165aa9c748f6bb419cd0a8d84d50a8970346d1b2 100644 (file)
@@ -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)
index ebe6ea8b0575599fc9b2cf73b32a4aab1ade3c18..688316abc64e6a272fa59e33ae4bc1f7e79549f2 100644 (file)
@@ -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
index fa7f9ca1fdbd8972ae4dfc99a59db0ca62917a47..c8baf8f80d234aeaa7ae3377b1b1edd09c229506 100644 (file)
@@ -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
index 7f70687140492f6d4773ddc25e0f22d4699d3a70..b85d2c75fb3cdc99841b37af411447cb73fce612 100644 (file)
 #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)
 {