Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: Move regulator handling closer to core

After discovering a problem in regulator reference counting I took Mark
Brown's advice to move the reference count into the MMC core by making the
regulator status a member of struct mmc_host.

I took this opportunity to also implement NULL versions of
the regulator functions so as to rid the driver code from
some ugly #ifdef CONFIG_REGULATOR clauses.

Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Cc: Liam Girdwood <lrg@slimlogic.co.uk>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Adrian Hunter <adrian.hunter@nokia.com>
Cc: Robert Jarzmik <robert.jarzmik@free.fr>
Cc: Sundar Iyer <sundar.iyer@stericsson.com>
Cc: Daniel Mack <daniel@caiaq.de>
Cc: Pierre Ossman <pierre@ossman.eu>
Cc: Matt Fleming <matt@console-pimps.org>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: Eric Miao <eric.y.miao@gmail.com>
Cc: Cliff Brake <cbrake@bec-systems.com>
Cc: Jarkko Lavinen <jarkko.lavinen@nokia.com>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Chris Ball <cjb@laptop.org>

authored by

Linus Walleij and committed by
Chris Ball
99fc5131 4d0b8611

+101 -37
+16 -10
drivers/mmc/core/core.c
··· 772 772 773 773 /** 774 774 * mmc_regulator_set_ocr - set regulator to match host->ios voltage 775 - * @vdd_bit: zero for power off, else a bit number (host->ios.vdd) 775 + * @mmc: the host to regulate 776 776 * @supply: regulator to use 777 + * @vdd_bit: zero for power off, else a bit number (host->ios.vdd) 777 778 * 778 779 * Returns zero on success, else negative errno. 779 780 * ··· 782 781 * a particular supply voltage. This would normally be called from the 783 782 * set_ios() method. 784 783 */ 785 - int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit) 784 + int mmc_regulator_set_ocr(struct mmc_host *mmc, 785 + struct regulator *supply, 786 + unsigned short vdd_bit) 786 787 { 787 788 int result = 0; 788 789 int min_uV, max_uV; 789 - int enabled; 790 - 791 - enabled = regulator_is_enabled(supply); 792 - if (enabled < 0) 793 - return enabled; 794 790 795 791 if (vdd_bit) { 796 792 int tmp; ··· 818 820 else 819 821 result = 0; 820 822 821 - if (result == 0 && !enabled) 823 + if (result == 0 && !mmc->regulator_enabled) { 822 824 result = regulator_enable(supply); 823 - } else if (enabled) { 825 + if (!result) 826 + mmc->regulator_enabled = true; 827 + } 828 + } else if (mmc->regulator_enabled) { 824 829 result = regulator_disable(supply); 830 + if (result == 0) 831 + mmc->regulator_enabled = false; 825 832 } 826 833 834 + if (result) 835 + dev_err(mmc_dev(mmc), 836 + "could not set regulator OCR (%d)\n", result); 827 837 return result; 828 838 } 829 839 EXPORT_SYMBOL(mmc_regulator_set_ocr); 830 840 831 - #endif 841 + #endif /* CONFIG_REGULATOR */ 832 842 833 843 /* 834 844 * Mask off any voltages we don't support and select
+18 -10
drivers/mmc/host/mmci.c
··· 523 523 struct mmci_host *host = mmc_priv(mmc); 524 524 u32 pwr = 0; 525 525 unsigned long flags; 526 + int ret; 526 527 527 528 switch (ios->power_mode) { 528 529 case MMC_POWER_OFF: 529 - if(host->vcc && 530 - regulator_is_enabled(host->vcc)) 531 - regulator_disable(host->vcc); 530 + if (host->vcc) 531 + ret = mmc_regulator_set_ocr(mmc, host->vcc, 0); 532 532 break; 533 533 case MMC_POWER_UP: 534 - #ifdef CONFIG_REGULATOR 535 - if (host->vcc) 536 - /* This implicitly enables the regulator */ 537 - mmc_regulator_set_ocr(host->vcc, ios->vdd); 538 - #endif 534 + if (host->vcc) { 535 + ret = mmc_regulator_set_ocr(mmc, host->vcc, ios->vdd); 536 + if (ret) { 537 + dev_err(mmc_dev(mmc), "unable to set OCR\n"); 538 + /* 539 + * The .set_ios() function in the mmc_host_ops 540 + * struct return void, and failing to set the 541 + * power should be rare so we print an error 542 + * and return here. 543 + */ 544 + return; 545 + } 546 + } 539 547 if (host->plat->vdd_handler) 540 548 pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd, 541 549 ios->power_mode); ··· 877 869 clk_disable(host->clk); 878 870 clk_put(host->clk); 879 871 880 - if (regulator_is_enabled(host->vcc)) 881 - regulator_disable(host->vcc); 872 + if (host->vcc) 873 + mmc_regulator_set_ocr(mmc, host->vcc, 0); 882 874 regulator_put(host->vcc); 883 875 884 876 mmc_free_host(mmc);
+13 -8
drivers/mmc/host/omap_hsmmc.c
··· 250 250 mmc_slot(host).before_set_reg(dev, slot, power_on, vdd); 251 251 252 252 if (power_on) 253 - ret = mmc_regulator_set_ocr(host->vcc, vdd); 253 + ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); 254 254 else 255 - ret = mmc_regulator_set_ocr(host->vcc, 0); 255 + ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0); 256 256 257 257 if (mmc_slot(host).after_set_reg) 258 258 mmc_slot(host).after_set_reg(dev, slot, power_on, vdd); ··· 291 291 * chips/cards need an interface voltage rail too. 292 292 */ 293 293 if (power_on) { 294 - ret = mmc_regulator_set_ocr(host->vcc, vdd); 294 + ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); 295 295 /* Enable interface voltage rail, if needed */ 296 296 if (ret == 0 && host->vcc_aux) { 297 297 ret = regulator_enable(host->vcc_aux); 298 298 if (ret < 0) 299 - ret = mmc_regulator_set_ocr(host->vcc, 0); 299 + ret = mmc_regulator_set_ocr(host->mmc, 300 + host->vcc, 0); 300 301 } 301 302 } else { 303 + /* Shut down the rail */ 302 304 if (host->vcc_aux) 303 305 ret = regulator_disable(host->vcc_aux); 304 - if (ret == 0) 305 - ret = mmc_regulator_set_ocr(host->vcc, 0); 306 + if (!ret) { 307 + /* Then proceed to shut down the local regulator */ 308 + ret = mmc_regulator_set_ocr(host->mmc, 309 + host->vcc, 0); 310 + } 306 311 } 307 312 308 313 if (mmc_slot(host).after_set_reg) ··· 348 343 if (cardsleep) { 349 344 /* VCC can be turned off if card is asleep */ 350 345 if (sleep) 351 - err = mmc_regulator_set_ocr(host->vcc, 0); 346 + err = mmc_regulator_set_ocr(host->mmc, host->vcc, 0); 352 347 else 353 - err = mmc_regulator_set_ocr(host->vcc, vdd); 348 + err = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); 354 349 } else 355 350 err = regulator_set_mode(host->vcc, mode); 356 351 if (err)
+33 -8
drivers/mmc/host/pxamci.c
··· 99 99 } 100 100 } 101 101 102 - static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd) 102 + static inline int pxamci_set_power(struct pxamci_host *host, 103 + unsigned char power_mode, 104 + unsigned int vdd) 103 105 { 104 106 int on; 105 107 106 - #ifdef CONFIG_REGULATOR 107 - if (host->vcc) 108 - mmc_regulator_set_ocr(host->vcc, vdd); 109 - #endif 108 + if (host->vcc) { 109 + int ret; 110 + 111 + if (power_mode == MMC_POWER_UP) { 112 + ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); 113 + if (ret) 114 + return ret; 115 + } else if (power_mode == MMC_POWER_OFF) { 116 + ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0); 117 + if (ret) 118 + return ret; 119 + } 120 + } 110 121 if (!host->vcc && host->pdata && 111 122 gpio_is_valid(host->pdata->gpio_power)) { 112 123 on = ((1 << vdd) & host->pdata->ocr_mask); ··· 126 115 } 127 116 if (!host->vcc && host->pdata && host->pdata->setpower) 128 117 host->pdata->setpower(mmc_dev(host->mmc), vdd); 118 + 119 + return 0; 129 120 } 130 121 131 122 static void pxamci_stop_clock(struct pxamci_host *host) ··· 503 490 } 504 491 505 492 if (host->power_mode != ios->power_mode) { 493 + int ret; 494 + 506 495 host->power_mode = ios->power_mode; 507 496 508 - pxamci_set_power(host, ios->vdd); 497 + ret = pxamci_set_power(host, ios->power_mode, ios->vdd); 498 + if (ret) { 499 + dev_err(mmc_dev(mmc), "unable to set power\n"); 500 + /* 501 + * The .set_ios() function in the mmc_host_ops 502 + * struct return void, and failing to set the 503 + * power should be rare so we print an error and 504 + * return here. 505 + */ 506 + return; 507 + } 509 508 510 509 if (ios->power_mode == MMC_POWER_ON) 511 510 host->cmdat |= CMDAT_INIT; ··· 528 503 else 529 504 host->cmdat &= ~CMDAT_SD_4DAT; 530 505 531 - pr_debug("PXAMCI: clkrt = %x cmdat = %x\n", 532 - host->clkrt, host->cmdat); 506 + dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n", 507 + host->clkrt, host->cmdat); 533 508 } 534 509 535 510 static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
+21 -1
include/linux/mmc/host.h
··· 212 212 struct led_trigger *led; /* activity led */ 213 213 #endif 214 214 215 + #ifdef CONFIG_REGULATOR 216 + bool regulator_enabled; /* regulator state */ 217 + #endif 218 + 215 219 struct dentry *debugfs_root; 216 220 217 221 unsigned long private[0] ____cacheline_aligned; ··· 254 250 255 251 struct regulator; 256 252 253 + #ifdef CONFIG_REGULATOR 257 254 int mmc_regulator_get_ocrmask(struct regulator *supply); 258 - int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit); 255 + int mmc_regulator_set_ocr(struct mmc_host *mmc, 256 + struct regulator *supply, 257 + unsigned short vdd_bit); 258 + #else 259 + static inline int mmc_regulator_get_ocrmask(struct regulator *supply) 260 + { 261 + return 0; 262 + } 263 + 264 + static inline int mmc_regulator_set_ocr(struct mmc_host *mmc, 265 + struct regulator *supply, 266 + unsigned short vdd_bit) 267 + { 268 + return 0; 269 + } 270 + #endif 259 271 260 272 int mmc_card_awake(struct mmc_host *host); 261 273 int mmc_card_sleep(struct mmc_host *host);