Merge branch 'master' into devel and apply fixup from Stephen Rothwell:
[pandora-kernel.git] / drivers / mmc / host / sdhci-esdhc-imx.c
index a19967d..710b706 100644 (file)
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/mmc/host.h>
-#include <linux/mmc/sdhci-pltfm.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sdio.h>
 #include <mach/hardware.h>
 #include <mach/esdhc.h>
-#include "sdhci.h"
 #include "sdhci-pltfm.h"
 #include "sdhci-esdhc.h"
 
@@ -31,7 +29,7 @@
 #define SDHCI_VENDOR_SPEC              0xC0
 #define  SDHCI_VENDOR_SPEC_SDIO_QUIRK  0x00000002
 
-#define ESDHC_FLAG_GPIO_FOR_CD_WP      (1 << 0)
+#define ESDHC_FLAG_GPIO_FOR_CD         (1 << 0)
 /*
  * The CMDTYPE of the CMD register (offset 0xE) should be set to
  * "11" when the STOP CMD12 is issued on imx53 to abort one
@@ -67,14 +65,14 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
        u32 val = readl(host->ioaddr + reg);
 
        if (unlikely((reg == SDHCI_PRESENT_STATE)
-                       && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP))) {
+                       && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD))) {
                struct esdhc_platform_data *boarddata =
                                host->mmc->parent->platform_data;
 
                if (boarddata && gpio_is_valid(boarddata->cd_gpio)
                                && gpio_get_value(boarddata->cd_gpio))
                        /* no card, if a valid gpio says so... */
-                       val &= SDHCI_CARD_PRESENT;
+                       val &= ~SDHCI_CARD_PRESENT;
                else
                        /* ... in all other cases assume card is present */
                        val |= SDHCI_CARD_PRESENT;
@@ -89,7 +87,7 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
        struct pltfm_imx_data *imx_data = pltfm_host->priv;
 
        if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)
-                       && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP)))
+                       && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD)))
                /*
                 * these interrupts won't work with a custom card_detect gpio
                 * (only applied to mx25/35)
@@ -191,16 +189,6 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
        return clk_get_rate(pltfm_host->clk) / 256 / 16;
 }
 
-static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
-{
-       struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
-
-       if (boarddata && gpio_is_valid(boarddata->wp_gpio))
-               return gpio_get_value(boarddata->wp_gpio);
-       else
-               return -ENOSYS;
-}
-
 static struct sdhci_ops sdhci_esdhc_ops = {
        .read_l = esdhc_readl_le,
        .read_w = esdhc_readw_le,
@@ -212,6 +200,24 @@ static struct sdhci_ops sdhci_esdhc_ops = {
        .get_min_clock = esdhc_pltfm_get_min_clock,
 };
 
+static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
+       .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
+                       | SDHCI_QUIRK_BROKEN_CARD_DETECTION,
+       /* ADMA has issues. Might be fixable */
+       .ops = &sdhci_esdhc_ops,
+};
+
+static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
+{
+       struct esdhc_platform_data *boarddata =
+                       host->mmc->parent->platform_data;
+
+       if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+               return gpio_get_value(boarddata->wp_gpio);
+       else
+               return -ENOSYS;
+}
+
 static irqreturn_t cd_irq(int irq, void *data)
 {
        struct sdhci_host *sdhost = (struct sdhci_host *)data;
@@ -220,30 +226,35 @@ static irqreturn_t cd_irq(int irq, void *data)
        return IRQ_HANDLED;
 };
 
-static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata)
+static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 {
-       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
+       struct sdhci_pltfm_host *pltfm_host;
+       struct sdhci_host *host;
+       struct esdhc_platform_data *boarddata;
        struct clk *clk;
        int err;
        struct pltfm_imx_data *imx_data;
 
+       host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
+       if (IS_ERR(host))
+               return PTR_ERR(host);
+
+       pltfm_host = sdhci_priv(host);
+
+       imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
+       if (!imx_data)
+               return -ENOMEM;
+       pltfm_host->priv = imx_data;
+
        clk = clk_get(mmc_dev(host->mmc), NULL);
        if (IS_ERR(clk)) {
                dev_err(mmc_dev(host->mmc), "clk err\n");
-               return PTR_ERR(clk);
+               err = PTR_ERR(clk);
+               goto err_clk_get;
        }
        clk_enable(clk);
        pltfm_host->clk = clk;
 
-       imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
-       if (!imx_data) {
-               clk_disable(pltfm_host->clk);
-               clk_put(pltfm_host->clk);
-               return -ENOMEM;
-       }
-       pltfm_host->priv = imx_data;
-
        if (!cpu_is_mx25())
                host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
 
@@ -257,6 +268,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
        if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
                imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
 
+       boarddata = host->mmc->parent->platform_data;
        if (boarddata) {
                err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
                if (err) {
@@ -284,11 +296,15 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
                        goto no_card_detect_irq;
                }
 
-               imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD_WP;
+               imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD;
                /* Now we have a working card_detect again */
                host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
        }
 
+       err = sdhci_add_host(host);
+       if (err)
+               goto err_add_host;
+
        return 0;
 
  no_card_detect_irq:
@@ -297,14 +313,23 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
        boarddata->cd_gpio = err;
  not_supported:
        kfree(imx_data);
-       return 0;
+ err_add_host:
+       clk_disable(pltfm_host->clk);
+       clk_put(pltfm_host->clk);
+ err_clk_get:
+       sdhci_pltfm_free(pdev);
+       return err;
 }
 
-static void esdhc_pltfm_exit(struct sdhci_host *host)
+static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
 {
+       struct sdhci_host *host = platform_get_drvdata(pdev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
        struct pltfm_imx_data *imx_data = pltfm_host->priv;
+       int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+       sdhci_remove_host(host, dead);
 
        if (boarddata && gpio_is_valid(boarddata->wp_gpio))
                gpio_free(boarddata->wp_gpio);
@@ -319,13 +344,37 @@ static void esdhc_pltfm_exit(struct sdhci_host *host)
        clk_disable(pltfm_host->clk);
        clk_put(pltfm_host->clk);
        kfree(imx_data);
+
+       sdhci_pltfm_free(pdev);
+
+       return 0;
 }
 
-struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
-       .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
-                       | SDHCI_QUIRK_BROKEN_CARD_DETECTION,
-       /* ADMA has issues. Might be fixable */
-       .ops = &sdhci_esdhc_ops,
-       .init = esdhc_pltfm_init,
-       .exit = esdhc_pltfm_exit,
+static struct platform_driver sdhci_esdhc_imx_driver = {
+       .driver         = {
+               .name   = "sdhci-esdhc-imx",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = sdhci_esdhc_imx_probe,
+       .remove         = __devexit_p(sdhci_esdhc_imx_remove),
+#ifdef CONFIG_PM
+       .suspend        = sdhci_pltfm_suspend,
+       .resume         = sdhci_pltfm_resume,
+#endif
 };
+
+static int __init sdhci_esdhc_imx_init(void)
+{
+       return platform_driver_register(&sdhci_esdhc_imx_driver);
+}
+module_init(sdhci_esdhc_imx_init);
+
+static void __exit sdhci_esdhc_imx_exit(void)
+{
+       platform_driver_unregister(&sdhci_esdhc_imx_driver);
+}
+module_exit(sdhci_esdhc_imx_exit);
+
+MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_LICENSE("GPL v2");