diff options
-rw-r--r-- | MAINTAINERS | 3 | ||||
-rw-r--r-- | drivers/mmc/host/Kconfig | 8 | ||||
-rw-r--r-- | drivers/mmc/host/at91_mci.c | 114 | ||||
-rw-r--r-- | drivers/mmc/host/ricoh_mmc.c | 162 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 13 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 1 |
6 files changed, 231 insertions, 70 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 5740aa216e11..c40f0ae96552 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2682,7 +2682,6 @@ MOTOROLA IMX MMC/SD HOST CONTROLLER INTERFACE DRIVER P: Pavel Pisa M: ppisa@pikron.com L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) -W: http://mmc.drzeus.cx/wiki/Controllers/Freescale/SDHC S: Maintained MOUSE AND MISC DEVICES [GENERAL] @@ -3716,7 +3715,6 @@ SECURE DIGITAL HOST CONTROLLER INTERFACE DRIVER P: Pierre Ossman M: drzeus-sdhci@drzeus.cx L: sdhci-devel@list.drzeus.cx -W: http://mmc.drzeus.cx/wiki/Linux/Drivers/sdhci S: Maintained SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS @@ -4286,7 +4284,6 @@ W83L51xD SD/MMC CARD INTERFACE DRIVER P: Pierre Ossman M: drzeus-wbsd@drzeus.cx L: linux-kernel@vger.kernel.org -W: http://projects.drzeus.cx/wbsd S: Maintained WATCHDOG DEVICE DRIVERS diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 5fef6783c716..3b3cd0e74715 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -25,8 +25,8 @@ config MMC_PXA If unsure, say N. config MMC_SDHCI - tristate "Secure Digital Host Controller Interface support (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL + tristate "Secure Digital Host Controller Interface support" + depends on PCI help This select the generic Secure Digital Host Controller Interface. It is used by manufacturers such as Texas Instruments(R), Ricoh(R) @@ -118,8 +118,8 @@ config MMC_TIFM_SD module will be called tifm_sd. config MMC_SPI - tristate "MMC/SD over SPI (EXPERIMENTAL)" - depends on MMC && SPI_MASTER && !HIGHMEM && EXPERIMENTAL + tristate "MMC/SD over SPI" + depends on MMC && SPI_MASTER && !HIGHMEM select CRC7 select CRC_ITU_T help diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index b1edcefdd4f9..21acecc9fe3a 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -70,10 +70,11 @@ #include <asm/io.h> #include <asm/irq.h> +#include <asm/gpio.h> + #include <asm/mach/mmc.h> #include <asm/arch/board.h> #include <asm/arch/cpu.h> -#include <asm/arch/gpio.h> #include <asm/arch/at91_mci.h> #define DRIVER_NAME "at91_mci" @@ -659,11 +660,11 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->board->vcc_pin) { switch (ios->power_mode) { case MMC_POWER_OFF: - at91_set_gpio_value(host->board->vcc_pin, 0); + gpio_set_value(host->board->vcc_pin, 0); break; case MMC_POWER_UP: case MMC_POWER_ON: - at91_set_gpio_value(host->board->vcc_pin, 1); + gpio_set_value(host->board->vcc_pin, 1); break; } } @@ -768,7 +769,7 @@ static irqreturn_t at91_mci_irq(int irq, void *devid) static irqreturn_t at91_mmc_det_irq(int irq, void *_host) { struct at91mci_host *host = _host; - int present = !at91_get_gpio_value(irq); + int present = !gpio_get_value(irq_to_gpio(irq)); /* * we expect this irq on both insert and remove, @@ -793,7 +794,7 @@ static int at91_mci_get_ro(struct mmc_host *mmc) struct at91mci_host *host = mmc_priv(mmc); if (host->board->wp_pin) { - read_only = at91_get_gpio_value(host->board->wp_pin); + read_only = gpio_get_value(host->board->wp_pin); printk(KERN_WARNING "%s: card is %s\n", mmc_hostname(mmc), (read_only ? "read-only" : "read-write") ); } @@ -820,8 +821,6 @@ static int __init at91_mci_probe(struct platform_device *pdev) struct resource *res; int ret; - pr_debug("Probe MCI devices\n"); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENXIO; @@ -831,9 +830,9 @@ static int __init at91_mci_probe(struct platform_device *pdev) mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev); if (!mmc) { - pr_debug("Failed to allocate mmc host\n"); - release_mem_region(res->start, res->end - res->start + 1); - return -ENOMEM; + ret = -ENOMEM; + dev_dbg(&pdev->dev, "couldn't allocate mmc host\n"); + goto fail6; } mmc->ops = &at91_mci_ops; @@ -853,19 +852,44 @@ static int __init at91_mci_probe(struct platform_device *pdev) if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) mmc->caps |= MMC_CAP_4_BIT_DATA; else - printk("AT91 MMC: 4 wire bus mode not supported" + dev_warn(&pdev->dev, "4 wire bus mode not supported" " - using 1 wire\n"); } /* + * Reserve GPIOs ... board init code makes sure these pins are set + * up as GPIOs with the right direction (input, except for vcc) + */ + if (host->board->det_pin) { + ret = gpio_request(host->board->det_pin, "mmc_detect"); + if (ret < 0) { + dev_dbg(&pdev->dev, "couldn't claim card detect pin\n"); + goto fail5; + } + } + if (host->board->wp_pin) { + ret = gpio_request(host->board->wp_pin, "mmc_wp"); + if (ret < 0) { + dev_dbg(&pdev->dev, "couldn't claim wp sense pin\n"); + goto fail4; + } + } + if (host->board->vcc_pin) { + ret = gpio_request(host->board->vcc_pin, "mmc_vcc"); + if (ret < 0) { + dev_dbg(&pdev->dev, "couldn't claim vcc switch pin\n"); + goto fail3; + } + } + + /* * Get Clock */ host->mci_clk = clk_get(&pdev->dev, "mci_clk"); if (IS_ERR(host->mci_clk)) { - printk(KERN_ERR "AT91 MMC: no clock defined.\n"); - mmc_free_host(mmc); - release_mem_region(res->start, res->end - res->start + 1); - return -ENODEV; + ret = -ENODEV; + dev_dbg(&pdev->dev, "no mci_clk?\n"); + goto fail2; } /* @@ -873,10 +897,8 @@ static int __init at91_mci_probe(struct platform_device *pdev) */ host->baseaddr = ioremap(res->start, res->end - res->start + 1); if (!host->baseaddr) { - clk_put(host->mci_clk); - mmc_free_host(mmc); - release_mem_region(res->start, res->end - res->start + 1); - return -ENOMEM; + ret = -ENOMEM; + goto fail1; } /* @@ -890,15 +912,11 @@ static int __init at91_mci_probe(struct platform_device *pdev) * Allocate the MCI interrupt */ host->irq = platform_get_irq(pdev, 0); - ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host); + ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, + mmc_hostname(mmc), host); if (ret) { - printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n"); - clk_disable(host->mci_clk); - clk_put(host->mci_clk); - mmc_free_host(mmc); - iounmap(host->baseaddr); - release_mem_region(res->start, res->end - res->start + 1); - return ret; + dev_dbg(&pdev->dev, "request MCI interrupt failed\n"); + goto fail0; } platform_set_drvdata(pdev, mmc); @@ -907,8 +925,7 @@ static int __init at91_mci_probe(struct platform_device *pdev) * Add host to MMC layer */ if (host->board->det_pin) { - host->present = !at91_get_gpio_value(host->board->det_pin); - device_init_wakeup(&pdev->dev, 1); + host->present = !gpio_get_value(host->board->det_pin); } else host->present = -1; @@ -919,15 +936,38 @@ static int __init at91_mci_probe(struct platform_device *pdev) * monitor card insertion/removal if we can */ if (host->board->det_pin) { - ret = request_irq(host->board->det_pin, at91_mmc_det_irq, - 0, DRIVER_NAME, host); + ret = request_irq(gpio_to_irq(host->board->det_pin), + at91_mmc_det_irq, 0, mmc_hostname(mmc), host); if (ret) - printk(KERN_ERR "AT91 MMC: Couldn't allocate MMC detect irq\n"); + dev_warn(&pdev->dev, "request MMC detect irq failed\n"); + else + device_init_wakeup(&pdev->dev, 1); } pr_debug("Added MCI driver\n"); return 0; + +fail0: + clk_disable(host->mci_clk); + iounmap(host->baseaddr); +fail1: + clk_put(host->mci_clk); +fail2: + if (host->board->vcc_pin) + gpio_free(host->board->vcc_pin); +fail3: + if (host->board->wp_pin) + gpio_free(host->board->wp_pin); +fail4: + if (host->board->det_pin) + gpio_free(host->board->det_pin); +fail5: + mmc_free_host(mmc); +fail6: + release_mem_region(res->start, res->end - res->start + 1); + dev_err(&pdev->dev, "probe failed, err %d\n", ret); + return ret; } /* @@ -945,9 +985,10 @@ static int __exit at91_mci_remove(struct platform_device *pdev) host = mmc_priv(mmc); if (host->board->det_pin) { + if (device_can_wakeup(&pdev->dev)) + free_irq(gpio_to_irq(host->board->det_pin), host); device_init_wakeup(&pdev->dev, 0); - free_irq(host->board->det_pin, host); - cancel_delayed_work(&host->mmc->detect); + gpio_free(host->board->det_pin); } at91_mci_disable(host); @@ -957,6 +998,11 @@ static int __exit at91_mci_remove(struct platform_device *pdev) clk_disable(host->mci_clk); /* Disable the peripheral clock */ clk_put(host->mci_clk); + if (host->board->vcc_pin) + gpio_free(host->board->vcc_pin); + if (host->board->wp_pin) + gpio_free(host->board->wp_pin); + iounmap(host->baseaddr); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, res->end - res->start + 1); diff --git a/drivers/mmc/host/ricoh_mmc.c b/drivers/mmc/host/ricoh_mmc.c index 1e8704533bc5..a16d7609e4ee 100644 --- a/drivers/mmc/host/ricoh_mmc.c +++ b/drivers/mmc/host/ricoh_mmc.c @@ -41,10 +41,91 @@ static const struct pci_device_id pci_ids[] __devinitdata = { MODULE_DEVICE_TABLE(pci, pci_ids); +static int ricoh_mmc_disable(struct pci_dev *fw_dev) +{ + u8 write_enable; + u8 write_target; + u8 disable; + + if (fw_dev->device == PCI_DEVICE_ID_RICOH_RL5C476) { + /* via RL5C476 */ + + pci_read_config_byte(fw_dev, 0xB7, &disable); + if (disable & 0x02) { + printk(KERN_INFO DRIVER_NAME + ": Controller already disabled. " \ + "Nothing to do.\n"); + return -ENODEV; + } + + pci_read_config_byte(fw_dev, 0x8E, &write_enable); + pci_write_config_byte(fw_dev, 0x8E, 0xAA); + pci_read_config_byte(fw_dev, 0x8D, &write_target); + pci_write_config_byte(fw_dev, 0x8D, 0xB7); + pci_write_config_byte(fw_dev, 0xB7, disable | 0x02); + pci_write_config_byte(fw_dev, 0x8E, write_enable); + pci_write_config_byte(fw_dev, 0x8D, write_target); + } else { + /* via R5C832 */ + + pci_read_config_byte(fw_dev, 0xCB, &disable); + if (disable & 0x02) { + printk(KERN_INFO DRIVER_NAME + ": Controller already disabled. " \ + "Nothing to do.\n"); + return -ENODEV; + } + + pci_read_config_byte(fw_dev, 0xCA, &write_enable); + pci_write_config_byte(fw_dev, 0xCA, 0x57); + pci_write_config_byte(fw_dev, 0xCB, disable | 0x02); + pci_write_config_byte(fw_dev, 0xCA, write_enable); + } + + printk(KERN_INFO DRIVER_NAME + ": Controller is now disabled.\n"); + + return 0; +} + +static int ricoh_mmc_enable(struct pci_dev *fw_dev) +{ + u8 write_enable; + u8 write_target; + u8 disable; + + if (fw_dev->device == PCI_DEVICE_ID_RICOH_RL5C476) { + /* via RL5C476 */ + + pci_read_config_byte(fw_dev, 0x8E, &write_enable); + pci_write_config_byte(fw_dev, 0x8E, 0xAA); + pci_read_config_byte(fw_dev, 0x8D, &write_target); + pci_write_config_byte(fw_dev, 0x8D, 0xB7); + pci_read_config_byte(fw_dev, 0xB7, &disable); + pci_write_config_byte(fw_dev, 0xB7, disable & ~0x02); + pci_write_config_byte(fw_dev, 0x8E, write_enable); + pci_write_config_byte(fw_dev, 0x8D, write_target); + } else { + /* via R5C832 */ + + pci_read_config_byte(fw_dev, 0xCA, &write_enable); + pci_read_config_byte(fw_dev, 0xCB, &disable); + pci_write_config_byte(fw_dev, 0xCA, 0x57); + pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02); + pci_write_config_byte(fw_dev, 0xCA, write_enable); + } + + printk(KERN_INFO DRIVER_NAME + ": Controller is now re-enabled.\n"); + + return 0; +} + static int __devinit ricoh_mmc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { u8 rev; + u8 ctrlfound = 0; struct pci_dev *fw_dev = NULL; @@ -58,34 +139,38 @@ static int __devinit ricoh_mmc_probe(struct pci_dev *pdev, pci_name(pdev), (int)pdev->vendor, (int)pdev->device, (int)rev); - while ((fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) { + while ((fw_dev = + pci_get_device(PCI_VENDOR_ID_RICOH, + PCI_DEVICE_ID_RICOH_RL5C476, fw_dev))) { if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) && pdev->bus == fw_dev->bus) { - u8 write_enable; - u8 disable; - - pci_read_config_byte(fw_dev, 0xCB, &disable); - if (disable & 0x02) { - printk(KERN_INFO DRIVER_NAME - ": Controller already disabled. Nothing to do.\n"); + if (ricoh_mmc_disable(fw_dev) != 0) return -ENODEV; - } - - pci_read_config_byte(fw_dev, 0xCA, &write_enable); - pci_write_config_byte(fw_dev, 0xCA, 0x57); - pci_write_config_byte(fw_dev, 0xCB, disable | 0x02); - pci_write_config_byte(fw_dev, 0xCA, write_enable); pci_set_drvdata(pdev, fw_dev); - printk(KERN_INFO DRIVER_NAME - ": Controller is now disabled.\n"); - + ++ctrlfound; break; } } - if (pci_get_drvdata(pdev) == NULL) { + fw_dev = NULL; + + while (!ctrlfound && + (fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, + PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) { + if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) && + pdev->bus == fw_dev->bus) { + if (ricoh_mmc_disable(fw_dev) != 0) + return -ENODEV; + + pci_set_drvdata(pdev, fw_dev); + + ++ctrlfound; + } + } + + if (!ctrlfound) { printk(KERN_WARNING DRIVER_NAME ": Main firewire function not found. Cannot disable controller.\n"); return -ENODEV; @@ -96,30 +181,51 @@ static int __devinit ricoh_mmc_probe(struct pci_dev *pdev, static void __devexit ricoh_mmc_remove(struct pci_dev *pdev) { - u8 write_enable; - u8 disable; struct pci_dev *fw_dev = NULL; fw_dev = pci_get_drvdata(pdev); BUG_ON(fw_dev == NULL); - pci_read_config_byte(fw_dev, 0xCA, &write_enable); - pci_read_config_byte(fw_dev, 0xCB, &disable); - pci_write_config_byte(fw_dev, 0xCA, 0x57); - pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02); - pci_write_config_byte(fw_dev, 0xCA, write_enable); - - printk(KERN_INFO DRIVER_NAME - ": Controller is now re-enabled.\n"); + ricoh_mmc_enable(fw_dev); pci_set_drvdata(pdev, NULL); } +static int ricoh_mmc_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct pci_dev *fw_dev = NULL; + + fw_dev = pci_get_drvdata(pdev); + BUG_ON(fw_dev == NULL); + + printk(KERN_INFO DRIVER_NAME ": Suspending.\n"); + + ricoh_mmc_enable(fw_dev); + + return 0; +} + +static int ricoh_mmc_resume(struct pci_dev *pdev) +{ + struct pci_dev *fw_dev = NULL; + + fw_dev = pci_get_drvdata(pdev); + BUG_ON(fw_dev == NULL); + + printk(KERN_INFO DRIVER_NAME ": Resuming.\n"); + + ricoh_mmc_disable(fw_dev); + + return 0; +} + static struct pci_driver ricoh_mmc_driver = { .name = DRIVER_NAME, .id_table = pci_ids, .probe = ricoh_mmc_probe, .remove = __devexit_p(ricoh_mmc_remove), + .suspend = ricoh_mmc_suspend, + .resume = ricoh_mmc_resume, }; /*****************************************************************************\ diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 785bbdcf4a58..4b673aa2dc3c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -30,6 +30,10 @@ static unsigned int debug_quirks = 0; +/* For multi controllers in one platform case */ +static u16 chip_index = 0; +static spinlock_t index_lock; + /* * Different quirks to handle when the hardware deviates from a strict * interpretation of the SDHCI specification. @@ -1320,7 +1324,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq); - snprintf(host->slot_descr, 20, "sdhci:slot%d", slot); + snprintf(host->slot_descr, 20, "sdhc%d:slot%d", chip->index, slot); ret = pci_request_region(pdev, host->bar, host->slot_descr); if (ret) @@ -1585,6 +1589,11 @@ static int __devinit sdhci_probe(struct pci_dev *pdev, chip->num_slots = slots; pci_set_drvdata(pdev, chip); + /* Add for multi controller case */ + spin_lock(&index_lock); + chip->index = chip_index++; + spin_unlock(&index_lock); + for (i = 0;i < slots;i++) { ret = sdhci_probe_slot(pdev, i); if (ret) { @@ -1645,6 +1654,8 @@ static int __init sdhci_drv_init(void) ": Secure Digital Host Controller Interface driver\n"); printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); + spin_lock_init(&index_lock); + return pci_register_driver(&sdhci_driver); } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index e4d77b038bfa..d5a38f1b755a 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -208,6 +208,7 @@ struct sdhci_chip { unsigned long quirks; + int index; /* Index for chip0, chip1 ...*/ int num_slots; /* Slots on controller */ struct sdhci_host *hosts[0]; /* Pointers to hosts */ }; |