]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/mmc/host/mmci.c
Merge remote-tracking branch 'mmc-uh/next'
[karo-tx-linux.git] / drivers / mmc / host / mmci.c
index 7e853932393bf00a0131d1a93206fc0c57ea5daa..b3abb021afd68eca4ea42d152dc8d0127c87a5b5 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/device.h>
+#include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -23,6 +24,7 @@
 #include <linux/mmc/pm.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/amba/bus.h>
 #include <linux/clk.h>
 #include <linux/scatterlist.h>
@@ -1287,7 +1289,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                 * indicating signal direction for the signals in
                 * the SD/MMC bus and feedback-clock usage.
                 */
-               pwr |= host->plat->sigdir;
+               pwr |= host->pwr_reg_add;
 
                if (ios->bus_width == MMC_BUS_WIDTH_4)
                        pwr &= ~MCI_ST_DATA74DIREN;
@@ -1328,35 +1330,18 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        pm_runtime_put_autosuspend(mmc_dev(mmc));
 }
 
-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_cansleep(host->gpio_wp);
-}
-
 static int mmci_get_cd(struct mmc_host *mmc)
 {
        struct mmci_host *host = mmc_priv(mmc);
        struct mmci_platform_data *plat = host->plat;
-       unsigned int status;
+       unsigned int status = mmc_gpio_get_cd(mmc);
 
-       if (host->gpio_cd == -ENOSYS) {
+       if (status == -ENOSYS) {
                if (!plat->status)
                        return 1; /* Assume always present */
 
                status = plat->status(mmc_dev(host->mmc));
-       } else
-               status = !!gpio_get_value_cansleep(host->gpio_cd)
-                       ^ plat->cd_invert;
-
-       /*
-        * Use positive logic throughout - status is zero for no card,
-        * non-zero for card inserted.
-        */
+       }
        return status;
 }
 
@@ -1393,70 +1378,44 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
        return ret;
 }
 
-static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
-{
-       struct mmci_host *host = dev_id;
-
-       mmc_detect_change(host->mmc, msecs_to_jiffies(500));
-
-       return IRQ_HANDLED;
-}
-
 static struct mmc_host_ops mmci_ops = {
        .request        = mmci_request,
        .pre_req        = mmci_pre_request,
        .post_req       = mmci_post_request,
        .set_ios        = mmci_set_ios,
-       .get_ro         = mmci_get_ro,
+       .get_ro         = mmc_gpio_get_ro,
        .get_cd         = mmci_get_cd,
        .start_signal_voltage_switch = mmci_sig_volt_switch,
 };
 
-#ifdef CONFIG_OF
-static void mmci_dt_populate_generic_pdata(struct device_node *np,
-                                       struct mmci_platform_data *pdata)
+static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc)
 {
-       int bus_width = 0;
-
-       pdata->gpio_wp = of_get_named_gpio(np, "wp-gpios", 0);
-       pdata->gpio_cd = of_get_named_gpio(np, "cd-gpios", 0);
+       struct mmci_host *host = mmc_priv(mmc);
+       int ret = mmc_of_parse(mmc);
 
-       if (of_get_property(np, "cd-inverted", NULL))
-               pdata->cd_invert = true;
-       else
-               pdata->cd_invert = false;
+       if (ret)
+               return ret;
 
-       of_property_read_u32(np, "max-frequency", &pdata->f_max);
-       if (!pdata->f_max)
-               pr_warn("%s has no 'max-frequency' property\n", np->full_name);
+       if (of_get_property(np, "st,sig-dir-dat0", NULL))
+               host->pwr_reg_add |= MCI_ST_DATA0DIREN;
+       if (of_get_property(np, "st,sig-dir-dat2", NULL))
+               host->pwr_reg_add |= MCI_ST_DATA2DIREN;
+       if (of_get_property(np, "st,sig-dir-dat31", NULL))
+               host->pwr_reg_add |= MCI_ST_DATA31DIREN;
+       if (of_get_property(np, "st,sig-dir-dat74", NULL))
+               host->pwr_reg_add |= MCI_ST_DATA74DIREN;
+       if (of_get_property(np, "st,sig-dir-cmd", NULL))
+               host->pwr_reg_add |= MCI_ST_CMDDIREN;
+       if (of_get_property(np, "st,sig-pin-fbclk", NULL))
+               host->pwr_reg_add |= MCI_ST_FBCLKEN;
 
        if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL))
-               pdata->capabilities |= MMC_CAP_MMC_HIGHSPEED;
+               mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
        if (of_get_property(np, "mmc-cap-sd-highspeed", NULL))
-               pdata->capabilities |= MMC_CAP_SD_HIGHSPEED;
+               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
 
-       of_property_read_u32(np, "bus-width", &bus_width);
-       switch (bus_width) {
-       case 0 :
-               /* No bus-width supplied. */
-               break;
-       case 4 :
-               pdata->capabilities |= MMC_CAP_4_BIT_DATA;
-               break;
-       case 8 :
-               pdata->capabilities |= MMC_CAP_8_BIT_DATA;
-               break;
-       default :
-               pr_warn("%s: Unsupported bus width\n", np->full_name);
-       }
-}
-#else
-static void mmci_dt_populate_generic_pdata(struct device_node *np,
-                                       struct mmci_platform_data *pdata)
-{
-       return;
+       return 0;
 }
-#endif
 
 static int mmci_probe(struct amba_device *dev,
        const struct amba_id *id)
@@ -1480,26 +1439,17 @@ static int mmci_probe(struct amba_device *dev,
                        return -ENOMEM;
        }
 
-       if (np)
-               mmci_dt_populate_generic_pdata(np, plat);
+       mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
+       if (!mmc)
+               return -ENOMEM;
 
-       ret = amba_request_regions(dev, DRIVER_NAME);
+       ret = mmci_of_parse(np, mmc);
        if (ret)
-               goto out;
-
-       mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
-       if (!mmc) {
-               ret = -ENOMEM;
-               goto rel_regions;
-       }
+               goto host_free;
 
        host = mmc_priv(mmc);
        host->mmc = mmc;
 
-       host->gpio_wp = -ENOSYS;
-       host->gpio_cd = -ENOSYS;
-       host->gpio_cd_irq = -1;
-
        host->hw_designer = amba_manf(dev);
        host->hw_revision = amba_rev(dev);
        dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);
@@ -1531,10 +1481,11 @@ static int mmci_probe(struct amba_device *dev,
                dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n",
                        host->mclk);
        }
+
        host->phybase = dev->res.start;
-       host->base = ioremap(dev->res.start, resource_size(&dev->res));
-       if (!host->base) {
-               ret = -ENOMEM;
+       host->base = devm_ioremap_resource(&dev->dev, &dev->res);
+       if (IS_ERR(host->base)) {
+               ret = PTR_ERR(host->base);
                goto clk_disable;
        }
 
@@ -1548,15 +1499,13 @@ static int mmci_probe(struct amba_device *dev,
        else
                mmc->f_min = DIV_ROUND_UP(host->mclk, 512);
        /*
-        * If the platform data supplies a maximum operating
-        * frequency, this takes precedence. Else, we fall back
-        * to using the module parameter, which has a (low)
-        * default value in case it is not specified. Either
-        * value must not exceed the clock rate into the block,
-        * of course.
+        * If no maximum operating frequency is supplied, fall back to use
+        * the module parameter, which has a (low) default value in case it
+        * is not specified. Either value must not exceed the clock rate into
+        * the block, of course.
         */
-       if (plat->f_max)
-               mmc->f_max = min(host->mclk, plat->f_max);
+       if (mmc->f_max)
+               mmc->f_max = min(host->mclk, mmc->f_max);
        else
                mmc->f_max = min(host->mclk, fmax);
        dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
@@ -1568,8 +1517,15 @@ static int mmci_probe(struct amba_device *dev,
        else if (plat->ocr_mask)
                dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n");
 
-       mmc->caps = plat->capabilities;
-       mmc->caps2 = plat->capabilities2;
+       /* DT takes precedence over platform data. */
+       if (!np) {
+               if (!plat->cd_invert)
+                       mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
+               mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
+       }
+
+       /* We support these capabilities. */
+       mmc->caps |= MMC_CAP_CMD23;
 
        if (variant->busy_detect) {
                mmci_ops.card_busy = mmci_card_busy;
@@ -1581,7 +1537,7 @@ static int mmci_probe(struct amba_device *dev,
        mmc->ops = &mmci_ops;
 
        /* We support these PM capabilities. */
-       mmc->pm_caps = MMC_PM_KEEP_POWER;
+       mmc->pm_caps |= MMC_PM_KEEP_POWER;
 
        /*
         * We can do SGIO
@@ -1618,62 +1574,30 @@ static int mmci_probe(struct amba_device *dev,
        writel(0, host->base + MMCIMASK1);
        writel(0xfff, host->base + MMCICLEAR);
 
-       if (plat->gpio_cd == -EPROBE_DEFER) {
-               ret = -EPROBE_DEFER;
-               goto err_gpio_cd;
-       }
-       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;
-
-               /*
-                * A gpio pin that will detect cards when inserted and removed
-                * will most likely want to trigger on the edges if it is
-                * 0 when ejected and 1 when inserted (or mutatis mutandis
-                * for the inverted case) so we request triggers on both
-                * edges.
-                */
-               ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd),
-                               mmci_cd_irq,
-                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                               DRIVER_NAME " (cd)", host);
-               if (ret >= 0)
-                       host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd);
-       }
-       if (plat->gpio_wp == -EPROBE_DEFER) {
-               ret = -EPROBE_DEFER;
-               goto err_gpio_wp;
+       /* If DT, cd/wp gpios must be supplied through it. */
+       if (!np && gpio_is_valid(plat->gpio_cd)) {
+               ret = mmc_gpio_request_cd(mmc, plat->gpio_cd, 0);
+               if (ret)
+                       goto clk_disable;
        }
-       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;
+       if (!np && gpio_is_valid(plat->gpio_wp)) {
+               ret = mmc_gpio_request_ro(mmc, plat->gpio_wp);
+               if (ret)
+                       goto clk_disable;
        }
 
-       if ((host->plat->status || host->gpio_cd != -ENOSYS)
-           && host->gpio_cd_irq < 0)
-               mmc->caps |= MMC_CAP_NEEDS_POLL;
-
-       ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
+       ret = devm_request_irq(&dev->dev, dev->irq[0], mmci_irq, IRQF_SHARED,
+                       DRIVER_NAME " (cmd)", host);
        if (ret)
-               goto unmap;
+               goto clk_disable;
 
        if (!dev->irq[1])
                host->singleirq = true;
        else {
-               ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED,
-                                 DRIVER_NAME " (pio)", host);
+               ret = devm_request_irq(&dev->dev, dev->irq[1], mmci_pio_irq,
+                               IRQF_SHARED, DRIVER_NAME " (pio)", host);
                if (ret)
-                       goto irq0_free;
+                       goto clk_disable;
        }
 
        writel(MCI_IRQENABLE, host->base + MMCIMASK0);
@@ -1695,25 +1619,10 @@ static int mmci_probe(struct amba_device *dev,
 
        return 0;
 
- 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_irq >= 0)
-               free_irq(host->gpio_cd_irq, host);
-       if (host->gpio_cd != -ENOSYS)
-               gpio_free(host->gpio_cd);
- err_gpio_cd:
-       iounmap(host->base);
  clk_disable:
        clk_disable_unprepare(host->clk);
  host_free:
        mmc_free_host(mmc);
- rel_regions:
-       amba_release_regions(dev);
- out:
        return ret;
 }
 
@@ -1739,92 +1648,46 @@ static int mmci_remove(struct amba_device *dev)
                writel(0, host->base + MMCIDATACTRL);
 
                mmci_dma_release(host);
-               free_irq(dev->irq[0], host);
-               if (!host->singleirq)
-                       free_irq(dev->irq[1], host);
-
-               if (host->gpio_wp != -ENOSYS)
-                       gpio_free(host->gpio_wp);
-               if (host->gpio_cd_irq >= 0)
-                       free_irq(host->gpio_cd_irq, host);
-               if (host->gpio_cd != -ENOSYS)
-                       gpio_free(host->gpio_cd);
-
-               iounmap(host->base);
                clk_disable_unprepare(host->clk);
-
                mmc_free_host(mmc);
-
-               amba_release_regions(dev);
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_SUSPEND
-static int mmci_suspend(struct device *dev)
-{
-       struct amba_device *adev = to_amba_device(dev);
-       struct mmc_host *mmc = amba_get_drvdata(adev);
-
-       if (mmc) {
-               struct mmci_host *host = mmc_priv(mmc);
-               pm_runtime_get_sync(dev);
-               writel(0, host->base + MMCIMASK0);
        }
 
        return 0;
 }
 
-static int mmci_resume(struct device *dev)
-{
-       struct amba_device *adev = to_amba_device(dev);
-       struct mmc_host *mmc = amba_get_drvdata(adev);
-
-       if (mmc) {
-               struct mmci_host *host = mmc_priv(mmc);
-               writel(MCI_IRQENABLE, host->base + MMCIMASK0);
-               pm_runtime_put(dev);
-       }
-
-       return 0;
-}
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
 static void mmci_save(struct mmci_host *host)
 {
        unsigned long flags;
 
-       if (host->variant->pwrreg_nopower) {
-               spin_lock_irqsave(&host->lock, flags);
+       spin_lock_irqsave(&host->lock, flags);
 
-               writel(0, host->base + MMCIMASK0);
+       writel(0, host->base + MMCIMASK0);
+       if (host->variant->pwrreg_nopower) {
                writel(0, host->base + MMCIDATACTRL);
                writel(0, host->base + MMCIPOWER);
                writel(0, host->base + MMCICLOCK);
-               mmci_reg_delay(host);
-
-               spin_unlock_irqrestore(&host->lock, flags);
        }
+       mmci_reg_delay(host);
 
+       spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static void mmci_restore(struct mmci_host *host)
 {
        unsigned long flags;
 
-       if (host->variant->pwrreg_nopower) {
-               spin_lock_irqsave(&host->lock, flags);
+       spin_lock_irqsave(&host->lock, flags);
 
+       if (host->variant->pwrreg_nopower) {
                writel(host->clk_reg, host->base + MMCICLOCK);
                writel(host->datactrl_reg, host->base + MMCIDATACTRL);
                writel(host->pwr_reg, host->base + MMCIPOWER);
-               writel(MCI_IRQENABLE, host->base + MMCIMASK0);
-               mmci_reg_delay(host);
-
-               spin_unlock_irqrestore(&host->lock, flags);
        }
+       writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+       mmci_reg_delay(host);
+
+       spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static int mmci_runtime_suspend(struct device *dev)
@@ -1859,8 +1722,9 @@ static int mmci_runtime_resume(struct device *dev)
 #endif
 
 static const struct dev_pm_ops mmci_dev_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume)
-       SET_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_PM_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL)
 };
 
 static struct amba_id mmci_ids[] = {