summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-09 11:12:15 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-09 11:12:15 -0800
commit5b39dba5029108800b94a5f4f96e3a05417103ac (patch)
tree7d5c59fd124a776508b3e2a58efb093cd97b29ea
parent11eb3b0da3f8e4b9a6da6aba510471918239153d (diff)
parent882c49164d72c45f37d7fa1bb3de7c31cf1a5fab (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: mmc: extend ricoh_mmc to support Ricoh RL5c476 at91_mci: use generic GPIO calls sdhci: add num index for multi controllers case MAINTAINERS: remove non-existant URLs mmc: remove sdhci and mmc_spi experimental markers mmc: Handle suspend/resume in Ricoh MMC disabler
-rw-r--r--MAINTAINERS3
-rw-r--r--drivers/mmc/host/Kconfig8
-rw-r--r--drivers/mmc/host/at91_mci.c114
-rw-r--r--drivers/mmc/host/ricoh_mmc.c162
-rw-r--r--drivers/mmc/host/sdhci.c13
-rw-r--r--drivers/mmc/host/sdhci.h1
6 files changed, 231 insertions, 70 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 5740aa216e1..c40f0ae9655 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 5fef6783c71..3b3cd0e7471 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 b1edcefdd4f..21acecc9fe3 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 1e8704533bc..a16d7609e4e 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 785bbdcf4a5..4b673aa2dc3 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 e4d77b038bf..d5a38f1b755 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 */
};