>From e981cd75059c7059ea553dba97e6a39d56aac58f Mon Sep 17 00:00:00 2001
From: Chuanxiao Dong <[email protected]>
Date: Tue, 16 Nov 2010 16:27:42 +0800
Subject: [PATCH 3/3] mmc: implemented the real reset eMMC card in sdhci HC 
driver

Hardware reset need host controller to trigger a RST_n signal,
and driver needs to pull up/down the relavent GPIO to implement
this. Since GPIO need FW to add a name in SFI table, add two interface
in arch/x86/kernel/mrst.c to setup/release the needed GPIO.

Signed-off-by: Chuanxiao Dong <[email protected]>
---
 arch/x86/include/asm/mrst.h  |    3 ++
 arch/x86/kernel/mrst.c       |   59 ++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-pci.c |   43 ++++++++++++++++++++++++++++++
 include/linux/mmc/sdhci.h    |    2 +
 4 files changed, 107 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h
index 3f4687d..7e6ec39 100644
--- a/arch/x86/include/asm/mrst.h
+++ b/arch/x86/include/asm/mrst.h
@@ -69,4 +69,7 @@ extern void mrst_early_printk(const char *fmt, ...);
 
 extern void intel_scu_devices_create(void);
 extern void intel_scu_devices_destroy(void);
+
+extern int emmc_rst_gpio_setup(int);
+extern void emmc_rst_gpio_release(int);
 #endif /* _ASM_X86_MRST_H */
diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c
index dce79e2..58a43b3 100644
--- a/arch/x86/kernel/mrst.c
+++ b/arch/x86/kernel/mrst.c
@@ -1645,4 +1645,63 @@ static int __init setup_hsu_dma_enable_flag(char *p)
 }
 early_param("hsu_dma", setup_hsu_dma_enable_flag);
 
+#define PCI_DEVID_MFL_EMMC0    0x0823
+#define PCI_DEVID_MFL_EMMC1    0x0824
 
+int emmc_rst_gpio_setup(int device)
+{
+       int gpio;
+       int ret;
+       if (device == PCI_DEVID_MFL_EMMC0)
+               gpio = get_gpio_by_name("emmc0_rst");
+       else if (device == PCI_DEVID_MFL_EMMC1)
+               gpio = get_gpio_by_name("emmc1_rst");
+       else
+               return -ENODEV;
+
+       /* if the gpio number is -1, return
+        * -ENODEV indicates no gpio is avalible
+        * for hardware reset
+        * */
+       if (gpio == -1)
+               return -ENODEV;
+
+       /* request reset pin for eMMC */
+       ret = gpio_request(gpio, "eMMC_rst_pin");
+       if (ret < 0) {
+               pr_err("gpio %d request failed\n", gpio);
+               return -1;
+       }
+       /* set to be output and to be low state */
+       ret = gpio_direction_output(gpio, 0);
+       if (ret < 0) {
+               pr_err("gpio %d direction output failed\n", gpio);
+               goto gpio_output_failed;
+       }
+       return gpio;
+
+gpio_output_failed:
+       gpio_free(gpio);
+       return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(emmc_rst_gpio_setup);
+
+void emmc_rst_gpio_release(int device)
+{
+       int gpio;
+       if (device == PCI_DEVID_MFL_EMMC0)
+               gpio = get_gpio_by_name("emmc0_rst");
+       else if (device == PCI_DEVID_MFL_EMMC1)
+               gpio = get_gpio_by_name("emmc1_rst");
+       else
+               return;
+
+       if (gpio == -1)
+               return;
+
+       /* set to be output and to be low state */
+       gpio_direction_output(gpio, 0);
+       /* free reset gpio pin */
+       gpio_free(gpio);
+}
+EXPORT_SYMBOL_GPL(emmc_rst_gpio_release);
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 7bdbd9c..5fd2347 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -18,6 +18,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/device.h>
+#include <linux/gpio.h>
 
 #include <linux/mmc/host.h>
 
@@ -25,6 +26,10 @@
 #include <asm/io.h>
 #include <asm/intel_scu_ipc.h>
 
+#if defined(CONFIG_X86_MRST)
+#include <asm/mrst.h>
+#endif
+
 #include "sdhci.h"
 
 #define DRIVER_VERSION "June 21, 2010"
@@ -633,8 +638,32 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
        return 0;
 }
 
+/*
+ * HW reset eMMC4.4 card callback
+ * In this function, driver need to trigger RST_n signal
+ * as eMMC4.4 standard says.
+ * 0: reset emmc successfully
+ * -ENODEV: reset emmc failed, no gpio pin to to the reset
+ */
+static int sdhci_pci_reset_emmc(struct sdhci_host *host)
+{
+       /* trigger a RST_n signal */
+       if (host->rst_pin == -ENODEV)
+               return -ENODEV;
+
+#if CONFIG_GPIOLIB
+       __gpio_set_value(host->rst_pin, 1);
+       udelay(300);
+       __gpio_set_value(host->rst_pin, 0);
+       return 0;
+#else
+       return -ENODEV;
+#endif
+}
+
 static struct sdhci_ops sdhci_pci_ops = {
        .enable_dma     = sdhci_pci_enable_dma,
+       .reset_emmc = sdhci_pci_reset_emmc,
 };
 
 /*****************************************************************************\
@@ -783,6 +812,12 @@ static struct sdhci_pci_slot * __devinit 
sdhci_pci_probe_slot(
        slot->host = host;
        slot->pci_bar = bar;
 
+       /* disable reset eMMC card pin first
+        * If platform is MFLD, will enable
+        * reset pin later. If not, just reserve
+        * for other platform to enable it.
+        * */
+       host->rst_pin = -ENODEV;
        host->hw_name = "PCI";
        host->ops = &sdhci_pci_ops;
        host->quirks = chip->quirks;
@@ -817,6 +852,10 @@ static struct sdhci_pci_slot * __devinit 
sdhci_pci_probe_slot(
        if (ret)
                goto remove;
 
+#if defined(CONFIG_X86_MRST)
+       host->rst_pin = emmc_rst_gpio_setup(pdev->device);
+#endif
+
        return slot;
 
 remove:
@@ -845,6 +884,10 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot 
*slot)
        if (scratch == (u32)-1)
                dead = 1;
 
+#if defined(CONFIG_X86_MRST)
+       emmc_rst_gpio_release(slot->chip->pdev->device);
+#endif
+
        sdhci_remove_host(slot->host, dead);
 
        if (slot->chip->fixes && slot->chip->fixes->remove_slot)
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index dc712bb..ec646dc 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -96,6 +96,8 @@ struct sdhci_host {
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
 
+       int rst_pin;
+
        const struct sdhci_ops *ops;    /* Low level hw interface */
 
        struct regulator *vmmc; /* Power regulator */
-- 
1.6.6.1

_______________________________________________
MeeGo-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to