Add support for powering up SD cards driven by regulators.
This makes the mmc_spi driver work also with the Motorola A910 phone.

Signed-off-by: Antonio Ospite <[email protected]>
---

Changes since v1:
  - Remove the ifdef CONFIG_REGULATOR as regulator_get() degenerates to 
    a stub as well when the regulator framework is disabled.
  - Release the regulator in mmc_spi_remove()

Thanks,
   Antonio

 drivers/mmc/host/mmc_spi.c |   63 +++++++++++++++++++++++++++++++++++--------
 1 files changed, 51 insertions(+), 12 deletions(-)

diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 0f3672d..62b3b02 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -31,6 +31,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/crc7.h>
 #include <linux/crc-itu-t.h>
+#include <linux/regulator/consumer.h>
 #include <linux/scatterlist.h>
 
 #include <linux/mmc/host.h>
@@ -150,11 +151,13 @@ struct mmc_spi_host {
         */
        void                    *ones;
        dma_addr_t              ones_dma;
+
+       struct regulator        *vcc;
 };
 
 static inline int mmc_spi_canpower(struct mmc_spi_host *host)
 {
-       return host->pdata && host->pdata->setpower;
+       return (host->pdata && host->pdata->setpower) || host->vcc;
 }
 
 /****************************************************************************/
@@ -1225,17 +1228,35 @@ static inline int mmc_spi_setpower(struct mmc_spi_host 
*host,
                                        unsigned char power_mode,
                                        unsigned int vdd)
 {
+       if (!mmc_spi_canpower(host))
+               return -ENOSYS;
+
        /* switch power on/off if possible, accounting for
         * max 250msec powerup time if needed.
         */
-       if (mmc_spi_canpower(host)) {
-               switch (power_mode) {
-               case MMC_POWER_OFF:
-               case MMC_POWER_UP:
+       switch (power_mode) {
+       case MMC_POWER_OFF:
+               if (host->vcc) {
+                       int ret = mmc_regulator_set_ocr(host->mmc,
+                                                       host->vcc, 0);
+                       if (ret)
+                               return ret;
+               } else {
+                       host->pdata->setpower(&host->spi->dev, vdd);
+               }
+               break;
+
+       case MMC_POWER_UP:
+               if (host->vcc) {
+                       int ret = mmc_regulator_set_ocr(host->mmc,
+                                                       host->vcc, vdd);
+                       if (ret)
+                               return ret;
+               } else {
                        host->pdata->setpower(&host->spi->dev, vdd);
-                       if (power_mode == MMC_POWER_UP)
-                               msleep(host->powerup_msecs);
                }
+               msleep(host->powerup_msecs);
+               break;
        }
 
        return 0;
@@ -1420,12 +1441,27 @@ static int mmc_spi_probe(struct spi_device *spi)
         * and power switching gpios.
         */
        host->pdata = mmc_spi_get_pdata(spi);
-       if (host->pdata)
-               mmc->ocr_avail = host->pdata->ocr_mask;
-       if (!mmc->ocr_avail) {
-               dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power\n");
-               mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+
+       host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc");
+       if (IS_ERR(host->vcc)) {
+               host->vcc = NULL;
+       } else {
+               host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
+               if (host->pdata && host->pdata->ocr_mask)
+                       dev_warn(mmc_dev(host->mmc),
+                               "ocr_mask/setpower will not be used\n");
        }
+
+       if (host->vcc == NULL) {
+               /* fall-back to platform data */
+               if (host->pdata)
+                       mmc->ocr_avail = host->pdata->ocr_mask;
+               if (!mmc->ocr_avail) {
+                       dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power\n");
+                       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+               }
+       }
+
        if (mmc_spi_canpower(host)) {
                host->powerup_msecs = host->pdata->powerup_msecs;
                if (!host->powerup_msecs || host->powerup_msecs > 250)
@@ -1523,6 +1559,9 @@ static int __devexit mmc_spi_remove(struct spi_device 
*spi)
                if (host->pdata && host->pdata->exit)
                        host->pdata->exit(&spi->dev, mmc);
 
+               if (host->vcc)
+                       regulator_put(host->vcc);
+
                mmc_remove_host(mmc);
 
                if (host->dma_dev) {
-- 
1.7.4.4


------------------------------------------------------------------------------
Fulfilling the Lean Software Promise
Lean software platforms are now widely adopted and the benefits have been 
demonstrated beyond question. Learn why your peers are replacing JEE 
containers with lightweight application servers - and what you can gain 
from the move. http://p.sf.net/sfu/vmware-sfemails
_______________________________________________
spi-devel-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

Reply via email to