>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
