[PATCH PM-0 v2] ARM: OMAP3: HSMMC: Ensure HSMMC is fully reset on boot

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This ensures that each HSMMC block is reset so it will not interfere
with retention or OFF-mode.

Signed-off-by: Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx>
---
 arch/arm/mach-omap2/hsmmc.c |   73 ++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 72 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 7334d86..00fe354 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -15,7 +15,9 @@
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/clk.h>
 #include <linux/i2c/twl4030.h>
+
 #include <mach/hardware.h>
 #include <mach/mmc.h>
 #include <mach/board.h>
@@ -46,6 +48,74 @@
 #define OMAP2_CONTROL_PBIAS_PWRDNZ	(1 << 1)
 #define OMAP2_CONTROL_PBIAS_SCTRL	(1 << 2)
 
+#define MMCHS1				(L4_34XX_BASE + 0x9C000)
+#define MMCHS2				(L4_34XX_BASE + 0xB4000)
+#define MMCHS3				(L4_34XX_BASE + 0xAD000)
+#define MAX_MMC				3
+#define MMCHS_SYSCONFIG			0x0010
+#define MMCHS_SYSCONFIG_SWRESET		(1 << 1)
+#define MMCHS_SYSSTATUS			0x0014
+#define MMCHS_SYSSTATUS_RESETDONE	(1 << 0)
+
+static struct platform_device dummy_pdev = {
+	.dev = {
+		.bus = &platform_bus_type,
+	},
+};
+
+/**
+ * hsmmc_reset() - Full reset of each HS-MMC controller
+ *
+ * Ensure that each MMC controller is fully reset.  Controllers
+ * left in an unknown state (by bootloaer) may prevent retention
+ * or OFF-mode.
+ *
+ * In order for reset to work, interface, functional and debounce
+ * clocks must be enabled.  The debounce clock comes from func_32k_clk
+ * and is not under SW controle, so we only enable i- and f-clocks.
+ **/
+static void __init hsmmc_reset(void)
+{
+	u32 i, base[MAX_MMC] = {MMCHS1, MMCHS2, MMCHS3};
+
+	for (i = 0; i < MAX_MMC; i++) {
+		u32 v;
+		struct clk *iclk, *fclk;
+		struct device *dev = &dummy_pdev.dev;
+
+		dummy_pdev.id = i + 1;
+		iclk = clk_get(dev, "mmchs_ick");
+		if (iclk && clk_enable(iclk))
+			iclk = NULL;
+		
+		fclk = clk_get(dev, "mmchs_fck");
+		if (fclk && clk_enable(fclk))
+			fclk = NULL;
+
+		if (!iclk || !fclk) {
+			printk(KERN_WARNING 
+			       "%s: Unable to enable clocks for MMC%d, "
+			       "cannot reset.\n",  __func__, i);
+			break;
+		}
+
+		omap_writel(MMCHS_SYSCONFIG_SWRESET, base[i] + MMCHS_SYSCONFIG);
+		v = omap_readl(base[i] + MMCHS_SYSSTATUS);
+		while (!(omap_readl(base[i] + MMCHS_SYSSTATUS) &
+			 MMCHS_SYSSTATUS_RESETDONE))
+			cpu_relax();
+
+		if (fclk) {
+			clk_disable(fclk);
+			clk_put(fclk);
+		}
+		if (iclk) {
+			clk_disable(iclk);
+			clk_put(iclk);
+		}
+	}
+}
+
 static int hsmmc_card_detect(int irq)
 {
 	return twl4030_get_gpio_datain(irq - TWL4030_GPIO_IRQ_BASE);
@@ -282,6 +352,7 @@ static struct omap_mmc_platform_data hsmmc_data = {
 
 void __init hsmmc_init(void)
 {
+	hsmmc_reset();
 	omap2_init_mmc(&hsmmc_data);
 }
 
@@ -289,7 +360,7 @@ void __init hsmmc_init(void)
 
 void __init hsmmc_init(void)
 {
-
+	hsmmc_reset();
 }
 
 #endif
-- 
1.6.0

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux