diff mbox

[RESEND,4/4] mmc_spi.c: add support for the regulator framework

Message ID 1303388873-15467-5-git-send-email-ospite@studenti.unina.it (mailing list archive)
State New, archived
Headers show

Commit Message

Antonio Ospite April 21, 2011, 12:27 p.m. UTC
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 <ospite@studenti.unina.it>
---
 drivers/mmc/host/mmc_spi.c |   61 +++++++++++++++++++++++++++++++++++--------
 1 files changed, 49 insertions(+), 12 deletions(-)

Comments

Mark Brown April 21, 2011, 12:40 p.m. UTC | #1
On Thu, Apr 21, 2011 at 02:27:53PM +0200, Antonio Ospite wrote:

> +#ifdef CONFIG_REGULATOR
> +	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");
>  	}
> +#endif

Why is this code conditional?  The regulator API will stub itself out
(by returning a null pointer, which plays well with your use of null) if
it's disabled.  I'm also not seeing any corresponding code to release
the regulator.
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Antonio Ospite April 21, 2011, 12:49 p.m. UTC | #2
On Thu, 21 Apr 2011 13:40:41 +0100
Mark Brown <broonie@opensource.wolfsonmicro.com> wrote:

> On Thu, Apr 21, 2011 at 02:27:53PM +0200, Antonio Ospite wrote:
> 
> > +#ifdef CONFIG_REGULATOR
> > +	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");
> >  	}
> > +#endif
> 
> Why is this code conditional?  The regulator API will stub itself out
> (by returning a null pointer, which plays well with your use of null) if
> it's disabled.  I'm also not seeing any corresponding code to release
> the regulator.
>

Actually I saw this done conditionally in pxamci.c and thought it was
really needed. About the call to regulator_put() if was there but got
lost when squashing the commits into the final patch and I was still
reading that part in my mind even if it was not there anymore.
The importance of reviewers with fresh eyes.

I'll resubmit this forth patch with the needed changes.

Thanks,
   Antonio
Daniel Ribeiro April 26, 2011, 9:21 p.m. UTC | #3
Em Qui, 2011-04-21 às 14:49 +0200, Antonio Ospite escreveu:
> On Thu, 21 Apr 2011 13:40:41 +0100
> Mark Brown <broonie@opensource.wolfsonmicro.com> wrote:
> 
> > On Thu, Apr 21, 2011 at 02:27:53PM +0200, Antonio Ospite wrote:
> > 
> > > +#ifdef CONFIG_REGULATOR
> > > +	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");
> > >  	}
> > > +#endif
> > 
> > Why is this code conditional?  The regulator API will stub itself out
> > (by returning a null pointer, which plays well with your use of null) if
> > it's disabled.  I'm also not seeing any corresponding code to release
> > the regulator.
> >
> 
> Actually I saw this done conditionally in pxamci.c and thought it was
> really needed. About the call to regulator_put() if was there but got
> lost when squashing the commits into the final patch and I was still
> reading that part in my mind even if it was not there anymore.
> The importance of reviewers with fresh eyes.
> 
> I'll resubmit this forth patch with the needed changes.

Hi,

The #ifdefs on pxamci were needed because at the time it was written
IS_ERR(regulator_get()) would return _false_ if CONFIG_REGULATOR is not
defined, breaking compatibility with the older ocr_mask/setpower.

I don't know if the regulator api changed it's old behaviour, see
http://www.mail-archive.com/openezx-devel@lists.openezx.org/msg01954.html
diff mbox

Patch

diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 0f3672d..acc2ec8 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,28 @@  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;
+#ifdef CONFIG_REGULATOR
+	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");
 	}
+#endif
+	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)