Hi Arjan,
   This patch is the version 3 of the serial hardware reset feature patches
   but only the 3rd one. Patch1 and patch2 I will submit to linux-mmc.

   patch1: implemented reset eMMC card ops for MFLD eMMC HC.

   changelog:
   In this patch, fixed the comment from Alan, thanks Alan.
   Add a new callback in sdhci_ops.

   I am not much clear where is the exactly place for me to add document for
   this new callback, so I just add some comment in the head file.

   Alan, I have fixed all of your comment. Could you please help to review
   the fix and point it out if I have done something wrong? Thanks.

Regards
Chuanxiao


>From 9a3c615c0adafa74033f3f7ecef90e0afcfb0f04 Mon Sep 17 00:00:00 2001
From: Chuanxiao Dong <[email protected]>
Date: Wed, 17 Nov 2010 18:20:19 +0800
Subject: [PATCH] mmc: implemented reset eMMC card ops for MFLD eMMC HC

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.

Add a new callback in sdhci_ops for sdhci core layer using. This
callback will be used to help implement eMMC4.4 hardware reset feature.

Signed-off-by: Chuanxiao Dong <[email protected]>
---
 arch/x86/include/asm/mrst.h  |    4 ++
 arch/x86/kernel/mrst.c       |   77 ++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-pci.c |   95 +++++++++++++++++++++++++++++++++++++++++-
 drivers/mmc/host/sdhci.h     |   14 ++++++
 4 files changed, 188 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h
index 3f4687d..52e17a8 100644
--- a/arch/x86/include/asm/mrst.h
+++ b/arch/x86/include/asm/mrst.h
@@ -69,4 +69,8 @@ extern void mrst_early_printk(const char *fmt, ...);
 
 extern void intel_scu_devices_create(void);
 extern void intel_scu_devices_destroy(void);
+
+extern int mfld_emmc_rstgpio_setup(struct pci_dev *pdev);
+extern void mfld_emmc_rstgpio_release(int gpio);
+extern int mfld_emmc_rstgpio_trigger(int gpio);
 #endif /* _ASM_X86_MRST_H */
diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c
index dce79e2..3a0dc39 100644
--- a/arch/x86/kernel/mrst.c
+++ b/arch/x86/kernel/mrst.c
@@ -34,6 +34,7 @@
 #include <linux/i2c/tc35894xbg.h>
 #include <linux/bh1770glc.h>
 #include <linux/leds-lp5523.h>
+#include <linux/pci.h>
 
 #include <asm/setup.h>
 #include <asm/mpspec_def.h>
@@ -1645,4 +1646,80 @@ 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
 
+/*
+ * Help eMMC host controller to get the correct
+ * GPIO lines.
+ * return value:
+ * successful: return the correct GPIO line number;
+ * fail: return -ENODEV for no valid GPIO line,
+ * or other failure value returned by gpio routine.
+ */
+int mfld_emmc_rstgpio_setup(struct pci_dev *pdev)
+{
+       int gpio;
+       int ret;
+
+       if (pdev->device == PCI_DEVID_MFL_EMMC0)
+               gpio = get_gpio_by_name("emmc0_rst");
+       else if (pdev->device == PCI_DEVID_MFL_EMMC1)
+               gpio = get_gpio_by_name("emmc1_rst");
+       else
+               return -ENODEV;
+
+       /* if the gpio number is less than 0, return
+        * -ENODEV indicates no gpio is avalible
+        * for hardware reset
+        * */
+       if (gpio < 0)
+               return -ENODEV;
+
+       /* request reset pin for eMMC */
+       ret = gpio_request(gpio, "eMMC_rst_pin");
+       if (ret < 0) {
+               dev_err(&pdev->dev, "gpio %d request failed\n", gpio);
+               return ret;
+       }
+       /* set to be output and to be low state */
+       ret = gpio_direction_output(gpio, 0);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "gpio %d direction output failed\n", gpio);
+               goto gpio_output_failed;
+       }
+       return gpio;
+
+gpio_output_failed:
+       gpio_free(gpio);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(mfld_emmc_rstgpio_setup);
+
+void mfld_emmc_rstgpio_release(int gpio)
+{
+       if (gpio < 0)
+               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(mfld_emmc_rstgpio_release);
+
+/*
+ * Trigger RST_n signale to reset eMMC card
+ * 0: successfully reset the eMMC card.
+ * -ENODEV: no valid GPIO line to be used.
+ */
+int mfld_emmc_rstgpio_trigger(int gpio)
+{
+       if (gpio < 0)
+               return -ENODEV;
+
+       __gpio_set_value(gpio, 1);
+       udelay(300);
+       __gpio_set_value(gpio, 0);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mfld_emmc_rstgpio_trigger);
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 7bdbd9c..6697e4e 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -66,6 +66,8 @@ struct sdhci_pci_slot {
        struct sdhci_host       *host;
 
        int                     pci_bar;
+
+       void *private; /* slot private things */
 };
 
 struct sdhci_pci_chip {
@@ -183,6 +185,65 @@ static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
                          SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
 };
 
+/*
+ * Let MFLD eMMC host controller request/release the reset
+ * GPIO lines.
+ */
+static int mfld_emmc_gpio_get_put(struct sdhci_pci_slot *slot, int get)
+{
+       struct sdhci_pci_chip *chip = slot->chip;
+       if (!chip)
+               return -ENODEV;
+#if defined(CONFIG_X86_MRST)
+       if (get) {
+               /* use private data as reset GPIO number */
+               return mfld_emmc_rstgpio_setup(chip->pdev);
+       } else {
+               int gpio;
+               if (slot->private == NULL)
+                       return 0;
+               else
+                       gpio = *(int *)slot->private;
+
+               mfld_emmc_rstgpio_release(gpio);
+               return 0;
+       }
+#endif
+       return -ENODEV;
+}
+
+/*
+ * Let MFLD eMMC host controller request GPIO which is
+ * used to reset eMMC card. The GPIO number should be get
+ * from SFI table.
+ */
+static int mfld_emmc_probe_slot(struct sdhci_pci_slot *slot)
+{
+       slot->private = kzalloc(sizeof(int), GFP_KERNEL);
+       if (!slot->private)
+               return -ENOMEM;
+
+       *(int *)slot->private = mfld_emmc_gpio_get_put(slot, 1);
+       return 0;
+}
+
+/*
+ * Let MFLD eMMC host controller release GPIO which is
+ * used to reset eMMC card.
+ */
+static void mfld_emmc_remove_slot(struct sdhci_pci_slot *slot, int dead)
+{
+       mfld_emmc_gpio_get_put(slot, 0);
+       kfree(slot->private);
+}
+
+static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = {
+       .quirks         = SDHCI_QUIRK_MFD_EMMC_SDIO_RESTRICTION |
+                         SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+       .probe_slot             = mfld_emmc_probe_slot,
+       .remove_slot    = mfld_emmc_remove_slot,
+};
+
 static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc_sdio = {
        .quirks         = SDHCI_QUIRK_MFD_EMMC_SDIO_RESTRICTION |
                          SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
@@ -582,7 +643,7 @@ static const struct pci_device_id pci_ids[] __devinitdata = 
{
                .device         = PCI_DEVICE_ID_INTEL_MFD_EMMC0,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
-               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
        },
 
        {
@@ -590,7 +651,7 @@ static const struct pci_device_id pci_ids[] __devinitdata = 
{
                .device         = PCI_DEVICE_ID_INTEL_MFD_EMMC1,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
-               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
        },
 
        {       /* Generic SD host controller */
@@ -633,8 +694,38 @@ 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)
+{
+       struct sdhci_pci_slot *slot = sdhci_priv(host);
+       int gpio;
+       int ret = -ENODEV;
+       if (slot->private == NULL)
+               return ret;
+       /*
+        * private stored the GPIO line number
+        */
+       gpio = *(int *)slot->private;
+       if (gpio < 0)
+               return ret;
+#if defined(CONFIG_X86_MRST)
+       /*
+        * trigger a RST_n signal
+        */
+       ret = mfld_emmc_rstgpio_trigger(gpio);
+#endif
+       return ret;
+}
+
 static struct sdhci_ops sdhci_pci_ops = {
        .enable_dma     = sdhci_pci_enable_dma,
+       .reset_emmc = sdhci_pci_reset_emmc,
 };
 
 /*****************************************************************************\
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 74b72f7..216fe66 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -20,6 +20,10 @@
 
 #include <linux/mmc/sdhci.h>
 
+#if defined(CONFIG_X86_MRST)
+#include <asm/mrst.h>
+#endif
+
 /*
  * Controller registers
  */
@@ -216,6 +220,16 @@ struct sdhci_ops {
        void (*platform_send_init_74_clocks)(struct sdhci_host *host,
                                             u8 power_mode);
        unsigned int    (*get_ro)(struct sdhci_host *host);
+
+       /*
+        * eMMC card reset callback.
+        * This callback can be used by sdhci layer to support eMMC4.4
+        * hardware reset feature.
+        * return value:
+        * 0: successfully reset eMMC card.
+        * -ENODEV: no valid GPIO lines to reset eMMC card.
+        */
+       int             (*reset_emmc)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-- 
1.6.6.1

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

Reply via email to