MMC: MMCI: use gpiolib for card detect/write protect
authorRussell King <rmk@dyn-67.arm.linux.org.uk>
Thu, 9 Jul 2009 14:16:07 +0000 (15:16 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 9 Jul 2009 14:16:07 +0000 (15:16 +0100)
Use gpiolib where available (and when valid GPIOs are provided) for
write protect/card detect status reporting.  We fall back to the old
'status' method where gpiolib support is not available.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h

index ac43f395eec0d116c2623bcddbb9b8d509e34379..5eb86a8c943bf4aa70ceb46babd67fcecf7058e9 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/amba/bus.h>
 #include <linux/clk.h>
 #include <linux/scatterlist.h>
+#include <linux/gpio.h>
 
 #include <asm/cacheflush.h>
 #include <asm/div64.h>
@@ -472,17 +473,41 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 }
 
+static int mmci_get_ro(struct mmc_host *mmc)
+{
+       struct mmci_host *host = mmc_priv(mmc);
+
+       if (host->gpio_wp == -ENOSYS)
+               return -ENOSYS;
+
+       return gpio_get_value(host->gpio_wp);
+}
+
+static int mmci_get_cd(struct mmc_host *mmc)
+{
+       struct mmci_host *host = mmc_priv(mmc);
+       unsigned int status;
+
+       if (host->gpio_cd == -ENOSYS)
+               status = host->plat->status(mmc_dev(host->mmc));
+       else
+               status = gpio_get_value(host->gpio_cd);
+
+       return !status;
+}
+
 static const struct mmc_host_ops mmci_ops = {
        .request        = mmci_request,
        .set_ios        = mmci_set_ios,
+       .get_ro         = mmci_get_ro,
+       .get_cd         = mmci_get_cd,
 };
 
 static void mmci_check_status(unsigned long data)
 {
        struct mmci_host *host = (struct mmci_host *)data;
-       unsigned int status;
+       unsigned int status = mmci_get_cd(host->mmc);
 
-       status = host->plat->status(mmc_dev(host->mmc));
        if (status ^ host->oldstat)
                mmc_detect_change(host->mmc, 0);
 
@@ -516,6 +541,9 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        host = mmc_priv(mmc);
        host->mmc = mmc;
 
+       host->gpio_wp = -ENOSYS;
+       host->gpio_cd = -ENOSYS;
+
        host->hw_designer = amba_manf(dev);
        host->hw_revision = amba_rev(dev);
        DBG(host, "designer ID = 0x%02x\n", host->hw_designer);
@@ -591,6 +619,25 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        writel(0, host->base + MMCIMASK1);
        writel(0xfff, host->base + MMCICLEAR);
 
+       if (gpio_is_valid(plat->gpio_cd)) {
+               ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)");
+               if (ret == 0)
+                       ret = gpio_direction_input(plat->gpio_cd);
+               if (ret == 0)
+                       host->gpio_cd = plat->gpio_cd;
+               else if (ret != -ENOSYS)
+                       goto err_gpio_cd;
+       }
+       if (gpio_is_valid(plat->gpio_wp)) {
+               ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)");
+               if (ret == 0)
+                       ret = gpio_direction_input(plat->gpio_wp);
+               if (ret == 0)
+                       host->gpio_wp = plat->gpio_wp;
+               else if (ret != -ENOSYS)
+                       goto err_gpio_wp;
+       }
+
        ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
        if (ret)
                goto unmap;
@@ -602,6 +649,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        writel(MCI_IRQENABLE, host->base + MMCIMASK0);
 
        amba_set_drvdata(dev, mmc);
+       host->oldstat = mmci_get_cd(host->mmc);
 
        mmc_add_host(mmc);
 
@@ -620,6 +668,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
  irq0_free:
        free_irq(dev->irq[0], host);
  unmap:
+       if (host->gpio_wp != -ENOSYS)
+               gpio_free(host->gpio_wp);
+ err_gpio_wp:
+       if (host->gpio_cd != -ENOSYS)
+               gpio_free(host->gpio_cd);
+ err_gpio_cd:
        iounmap(host->base);
  clk_disable:
        clk_disable(host->clk);
@@ -655,6 +709,11 @@ static int __devexit mmci_remove(struct amba_device *dev)
                free_irq(dev->irq[0], host);
                free_irq(dev->irq[1], host);
 
+               if (host->gpio_wp != -ENOSYS)
+                       gpio_free(host->gpio_wp);
+               if (host->gpio_cd != -ENOSYS)
+                       gpio_free(host->gpio_cd);
+
                iounmap(host->base);
                clk_disable(host->clk);
                clk_put(host->clk);
index 0441bac1c0eca66de761c353fb69370c74382ca0..839f264c9725d27e5c5f72d5b9502e99fc17fb3c 100644 (file)
@@ -151,6 +151,8 @@ struct mmci_host {
        struct mmc_data         *data;
        struct mmc_host         *mmc;
        struct clk              *clk;
+       int                     gpio_cd;
+       int                     gpio_wp;
 
        unsigned int            data_xfered;