diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-pci.c')
-rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 181 |
1 files changed, 91 insertions, 90 deletions
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 6878a94626bc..7165e6a09274 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -23,8 +23,8 @@ #include <linux/scatterlist.h> #include <linux/io.h> #include <linux/gpio.h> -#include <linux/sfi.h> #include <linux/pm_runtime.h> +#include <linux/mmc/sdhci-pci-data.h> #include "sdhci.h" @@ -61,6 +61,7 @@ struct sdhci_pci_fixes { struct sdhci_pci_slot { struct sdhci_pci_chip *chip; struct sdhci_host *host; + struct sdhci_pci_data *data; int pci_bar; int rst_n_gpio; @@ -171,32 +172,9 @@ static int mrst_hc_probe(struct sdhci_pci_chip *chip) return 0; } -/* Medfield eMMC hardware reset GPIOs */ -static int mfd_emmc0_rst_gpio = -EINVAL; -static int mfd_emmc1_rst_gpio = -EINVAL; - -static int mfd_emmc_gpio_parse(struct sfi_table_header *table) -{ - struct sfi_table_simple *sb = (struct sfi_table_simple *)table; - struct sfi_gpio_table_entry *entry; - int i, num; - - num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry); - entry = (struct sfi_gpio_table_entry *)sb->pentry; - - for (i = 0; i < num; i++, entry++) { - if (!strncmp(entry->pin_name, "emmc0_rst", SFI_NAME_LEN)) - mfd_emmc0_rst_gpio = entry->pin_no; - else if (!strncmp(entry->pin_name, "emmc1_rst", SFI_NAME_LEN)) - mfd_emmc1_rst_gpio = entry->pin_no; - } - - return 0; -} - #ifdef CONFIG_PM_RUNTIME -static irqreturn_t mfd_sd_cd(int irq, void *dev_id) +static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id) { struct sdhci_pci_slot *slot = dev_id; struct sdhci_host *host = slot->host; @@ -205,15 +183,16 @@ static irqreturn_t mfd_sd_cd(int irq, void *dev_id) return IRQ_HANDLED; } -#define MFLD_SD_CD_PIN 69 - -static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot) +static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) { - int err, irq, gpio = MFLD_SD_CD_PIN; + int err, irq, gpio = slot->cd_gpio; slot->cd_gpio = -EINVAL; slot->cd_irq = -EINVAL; + if (!gpio_is_valid(gpio)) + return; + err = gpio_request(gpio, "sd_cd"); if (err < 0) goto out; @@ -226,72 +205,53 @@ static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot) if (irq < 0) goto out_free; - err = request_irq(irq, mfd_sd_cd, IRQF_TRIGGER_RISING | + err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "sd_cd", slot); if (err) goto out_free; slot->cd_gpio = gpio; slot->cd_irq = irq; - slot->host->quirks2 |= SDHCI_QUIRK2_OWN_CARD_DETECTION; - return 0; + return; out_free: gpio_free(gpio); out: dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n"); - return 0; } -static void mfd_sd_remove_slot(struct sdhci_pci_slot *slot, int dead) +static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) { if (slot->cd_irq >= 0) free_irq(slot->cd_irq, slot); - gpio_free(slot->cd_gpio); + if (gpio_is_valid(slot->cd_gpio)) + gpio_free(slot->cd_gpio); } #else -#define mfd_sd_probe_slot NULL -#define mfd_sd_remove_slot NULL +static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) +{ +} + +static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) +{ +} #endif static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) { - const char *name = NULL; - int gpio = -EINVAL; - - sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, mfd_emmc_gpio_parse); - - switch (slot->chip->pdev->device) { - case PCI_DEVICE_ID_INTEL_MFD_EMMC0: - gpio = mfd_emmc0_rst_gpio; - name = "eMMC0_reset"; - break; - case PCI_DEVICE_ID_INTEL_MFD_EMMC1: - gpio = mfd_emmc1_rst_gpio; - name = "eMMC1_reset"; - break; - } - - if (!gpio_request(gpio, name)) { - gpio_direction_output(gpio, 1); - slot->rst_n_gpio = gpio; - slot->host->mmc->caps |= MMC_CAP_HW_RESET; - } - slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; - slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC; - return 0; } -static void mfd_emmc_remove_slot(struct sdhci_pci_slot *slot, int dead) +static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot) { - gpio_free(slot->rst_n_gpio); + slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD; + return 0; } static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { @@ -307,20 +267,18 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = { static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .allow_runtime_pm = true, - .probe_slot = mfd_sd_probe_slot, - .remove_slot = mfd_sd_remove_slot, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .allow_runtime_pm = true, + .probe_slot = mfd_sdio_probe_slot, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .allow_runtime_pm = true, .probe_slot = mfd_emmc_probe_slot, - .remove_slot = mfd_emmc_remove_slot, }; /* O2Micro extra registers */ @@ -1012,11 +970,8 @@ static int sdhci_pci_suspend(struct device *dev) ret = sdhci_suspend_host(slot->host); - if (ret) { - for (i--; i >= 0; i--) - sdhci_resume_host(chip->slots[i]->host); - return ret; - } + if (ret) + goto err_pci_suspend; slot_pm_flags = slot->host->mmc->pm_flags; if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ) @@ -1027,11 +982,8 @@ static int sdhci_pci_suspend(struct device *dev) if (chip->fixes && chip->fixes->suspend) { ret = chip->fixes->suspend(chip); - if (ret) { - for (i = chip->num_slots - 1; i >= 0; i--) - sdhci_resume_host(chip->slots[i]->host); - return ret; - } + if (ret) + goto err_pci_suspend; } pci_save_state(pdev); @@ -1048,6 +1000,11 @@ static int sdhci_pci_suspend(struct device *dev) } return 0; + +err_pci_suspend: + while (--i >= 0) + sdhci_resume_host(chip->slots[i]->host); + return ret; } static int sdhci_pci_resume(struct device *dev) @@ -1113,23 +1070,22 @@ static int sdhci_pci_runtime_suspend(struct device *dev) ret = sdhci_runtime_suspend_host(slot->host); - if (ret) { - for (i--; i >= 0; i--) - sdhci_runtime_resume_host(chip->slots[i]->host); - return ret; - } + if (ret) + goto err_pci_runtime_suspend; } if (chip->fixes && chip->fixes->suspend) { ret = chip->fixes->suspend(chip); - if (ret) { - for (i = chip->num_slots - 1; i >= 0; i--) - sdhci_runtime_resume_host(chip->slots[i]->host); - return ret; - } + if (ret) + goto err_pci_runtime_suspend; } return 0; + +err_pci_runtime_suspend: + while (--i >= 0) + sdhci_runtime_resume_host(chip->slots[i]->host); + return ret; } static int sdhci_pci_runtime_resume(struct device *dev) @@ -1190,11 +1146,12 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = { \*****************************************************************************/ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( - struct pci_dev *pdev, struct sdhci_pci_chip *chip, int bar) + struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, + int slotno) { struct sdhci_pci_slot *slot; struct sdhci_host *host; - int ret; + int ret, bar = first_bar + slotno; if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar); @@ -1228,6 +1185,23 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( slot->host = host; slot->pci_bar = bar; slot->rst_n_gpio = -EINVAL; + slot->cd_gpio = -EINVAL; + + /* Retrieve platform data if there is any */ + if (*sdhci_pci_get_data) + slot->data = sdhci_pci_get_data(pdev, slotno); + + if (slot->data) { + if (slot->data->setup) { + ret = slot->data->setup(slot->data); + if (ret) { + dev_err(&pdev->dev, "platform setup failed\n"); + goto free; + } + } + slot->rst_n_gpio = slot->data->rst_n_gpio; + slot->cd_gpio = slot->data->cd_gpio; + } host->hw_name = "PCI"; host->ops = &sdhci_pci_ops; @@ -1238,7 +1212,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc)); if (ret) { dev_err(&pdev->dev, "cannot request region\n"); - goto free; + goto cleanup; } host->ioaddr = pci_ioremap_bar(pdev, bar); @@ -1254,15 +1228,30 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( goto unmap; } + if (gpio_is_valid(slot->rst_n_gpio)) { + if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) { + gpio_direction_output(slot->rst_n_gpio, 1); + slot->host->mmc->caps |= MMC_CAP_HW_RESET; + } else { + dev_warn(&pdev->dev, "failed to request rst_n_gpio\n"); + slot->rst_n_gpio = -EINVAL; + } + } + host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; ret = sdhci_add_host(host); if (ret) goto remove; + sdhci_pci_add_own_cd(slot); + return slot; remove: + if (gpio_is_valid(slot->rst_n_gpio)) + gpio_free(slot->rst_n_gpio); + if (chip->fixes && chip->fixes->remove_slot) chip->fixes->remove_slot(slot, 0); @@ -1272,6 +1261,10 @@ unmap: release: pci_release_region(pdev, bar); +cleanup: + if (slot->data && slot->data->cleanup) + slot->data->cleanup(slot->data); + free: sdhci_free_host(host); @@ -1283,6 +1276,8 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) int dead; u32 scratch; + sdhci_pci_remove_own_cd(slot); + dead = 0; scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32)-1) @@ -1290,9 +1285,15 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) sdhci_remove_host(slot->host, dead); + if (gpio_is_valid(slot->rst_n_gpio)) + gpio_free(slot->rst_n_gpio); + if (slot->chip->fixes && slot->chip->fixes->remove_slot) slot->chip->fixes->remove_slot(slot, dead); + if (slot->data && slot->data->cleanup) + slot->data->cleanup(slot->data); + pci_release_region(slot->chip->pdev, slot->pci_bar); sdhci_free_host(slot->host); @@ -1379,7 +1380,7 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, slots = chip->num_slots; /* Quirk may have changed this */ for (i = 0; i < slots; i++) { - slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i); + slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); if (IS_ERR(slot)) { for (i--; i >= 0; i--) sdhci_pci_remove_slot(chip->slots[i]); |