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

mmc: sdhci: fix vmmc handling

Presently the vmmc regulator is enabled when the host
controller is added and disabled when it is removed.
However, the vmmc regulator should be under the control
of the upper layers via ->set_ios(). Make it so.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Chris Ball <cjb@laptop.org>

authored by

Adrian Hunter and committed by
Chris Ball
ceb6143b 17e9ff55

+21 -22
+21 -22
drivers/mmc/host/sdhci.c
··· 1170 1170 host->clock = clock; 1171 1171 } 1172 1172 1173 - static void sdhci_set_power(struct sdhci_host *host, unsigned short power) 1173 + static int sdhci_set_power(struct sdhci_host *host, unsigned short power) 1174 1174 { 1175 1175 u8 pwr = 0; 1176 1176 ··· 1193 1193 } 1194 1194 1195 1195 if (host->pwr == pwr) 1196 - return; 1196 + return -1; 1197 1197 1198 1198 host->pwr = pwr; 1199 1199 1200 1200 if (pwr == 0) { 1201 1201 sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); 1202 - return; 1202 + return 0; 1203 1203 } 1204 1204 1205 1205 /* ··· 1226 1226 */ 1227 1227 if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) 1228 1228 mdelay(10); 1229 + 1230 + return power; 1229 1231 } 1230 1232 1231 1233 /*****************************************************************************\ ··· 1309 1307 static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) 1310 1308 { 1311 1309 unsigned long flags; 1310 + int vdd_bit = -1; 1312 1311 u8 ctrl; 1313 1312 1314 1313 spin_lock_irqsave(&host->lock, flags); 1315 1314 1316 - if (host->flags & SDHCI_DEVICE_DEAD) 1317 - goto out; 1315 + if (host->flags & SDHCI_DEVICE_DEAD) { 1316 + spin_unlock_irqrestore(&host->lock, flags); 1317 + if (host->vmmc && ios->power_mode == MMC_POWER_OFF) 1318 + mmc_regulator_set_ocr(host->mmc, host->vmmc, 0); 1319 + return; 1320 + } 1318 1321 1319 1322 /* 1320 1323 * Reset the chip on each power off. ··· 1333 1326 sdhci_set_clock(host, ios->clock); 1334 1327 1335 1328 if (ios->power_mode == MMC_POWER_OFF) 1336 - sdhci_set_power(host, -1); 1329 + vdd_bit = sdhci_set_power(host, -1); 1337 1330 else 1338 - sdhci_set_power(host, ios->vdd); 1331 + vdd_bit = sdhci_set_power(host, ios->vdd); 1332 + 1333 + if (host->vmmc && vdd_bit != -1) { 1334 + spin_unlock_irqrestore(&host->lock, flags); 1335 + mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit); 1336 + spin_lock_irqsave(&host->lock, flags); 1337 + } 1339 1338 1340 1339 if (host->ops->platform_send_init_74_clocks) 1341 1340 host->ops->platform_send_init_74_clocks(host, ios->power_mode); ··· 1466 1453 if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) 1467 1454 sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); 1468 1455 1469 - out: 1470 1456 mmiowb(); 1471 1457 spin_unlock_irqrestore(&host->lock, flags); 1472 1458 } ··· 2369 2357 2370 2358 free_irq(host->irq, host); 2371 2359 2372 - if (host->vmmc) 2373 - ret = regulator_disable(host->vmmc); 2374 - 2375 2360 return ret; 2376 2361 } 2377 2362 ··· 2377 2368 int sdhci_resume_host(struct sdhci_host *host) 2378 2369 { 2379 2370 int ret; 2380 - 2381 - if (host->vmmc) { 2382 - int ret = regulator_enable(host->vmmc); 2383 - if (ret) 2384 - return ret; 2385 - } 2386 2371 2387 2372 if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { 2388 2373 if (host->ops->enable_dma) ··· 2939 2936 if (IS_ERR(host->vmmc)) { 2940 2937 pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); 2941 2938 host->vmmc = NULL; 2942 - } else { 2943 - regulator_enable(host->vmmc); 2944 2939 } 2945 2940 2946 2941 sdhci_init(host, 0); ··· 3027 3026 tasklet_kill(&host->card_tasklet); 3028 3027 tasklet_kill(&host->finish_tasklet); 3029 3028 3030 - if (host->vmmc) { 3031 - regulator_disable(host->vmmc); 3029 + if (host->vmmc) 3032 3030 regulator_put(host->vmmc); 3033 - } 3034 3031 3035 3032 kfree(host->adma_desc); 3036 3033 kfree(host->align_buffer);