diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-11 13:56:48 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-11 13:56:48 -0500 |
commit | aa7ed01f93ff7e149cad46f13f66b269d59c9bc0 (patch) | |
tree | ab46a44f3c83c75e1c81f211acd0d68ffe60dd7c /drivers/mmc/core/core.c | |
parent | 7796c11c728ad40ba4151d559a949c002deffb9a (diff) | |
parent | 017210d1c0dc2e2d3b142985cb31d90b98dc0f0f (diff) |
Merge tag 'mmc-v3.20-1' of git://git.linaro.org/people/ulf.hansson/mmc
Pull MMC updates from Ulf Hansson:
"MMC core:
- Support for MMC power sequences.
- SDIO function devicetree subnode parsing.
- Refactor the hardware reset routines and enable it for SD cards.
- Various code quality improvements, especially for slot-gpio.
MMC host:
- dw_mmc: Various fixes and cleanups.
- dw_mmc: Convert to mmc_send_tuning().
- moxart: Fix probe logic.
- sdhci: Various fixes and cleanups
- sdhci: Asynchronous request handling support.
- sdhci-pxav3: Various fixes and cleanups.
- sdhci-tegra: Fixes for T114, T124 and T132.
- rtsx: Various fixes and cleanups.
- rtsx: Support for SDIO.
- sdhi/tmio: Refactor and cleanup of header files.
- omap_hsmmc: Use slot-gpio and common MMC DT parser.
- Make all hosts to deal with errors from mmc_of_parse().
- sunxi: Various fixes and cleanups.
- sdhci: Support for Fujitsu SDHCI controller f_sdh30"
* tag 'mmc-v3.20-1' of git://git.linaro.org/people/ulf.hansson/mmc: (117 commits)
mmc: sdhci-s3c: solve problem with sleeping in atomic context
mmc: pwrseq: add driver for emmc hardware reset
mmc: moxart: fix probe logic
mmc: core: Invoke mmc_pwrseq_post_power_on() prior MMC_POWER_ON state
mmc: pwrseq_simple: Add optional reference clock support
mmc: pwrseq: Document optional clock for the simple power sequence
mmc: pwrseq_simple: Extend to support more pins
mmc: pwrseq: Document that simple sequence support more than one GPIO
mmc: Add hardware dependencies for sdhci-pxav3 and sdhci-pxav2
mmc: sdhci-pxav3: Modify clock settings for the SDR50 and DDR50 modes
mmc: sdhci-pxav3: Extend binding with SDIO3 conf reg for the Armada 38x
mmc: sdhci-pxav3: Fix Armada 38x controller's caps according to erratum ERR-7878951
mmc: sdhci-pxav3: Fix SDR50 and DDR50 capabilities for the Armada 38x flavor
mmc: sdhci: switch voltage before sdhci_set_ios in runtime resume
mmc: tegra: Write xfer_mode, CMD regs in together
mmc: Resolve BKOPS compatability issue
mmc: sdhci-pxav3: fix setting of pdata->clk_delay_cycles
mmc: dw_mmc: rockchip: remove incorrect __exit_p()
mmc: dw_mmc: exynos: remove incorrect __exit_p()
mmc: Fix menuconfig alignment of MMC_SDHCI_* options
...
Diffstat (limited to 'drivers/mmc/core/core.c')
-rw-r--r-- | drivers/mmc/core/core.c | 152 |
1 files changed, 90 insertions, 62 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9584bffa8b22..23f10f72e5f3 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "bus.h" | 40 | #include "bus.h" |
41 | #include "host.h" | 41 | #include "host.h" |
42 | #include "sdio_bus.h" | 42 | #include "sdio_bus.h" |
43 | #include "pwrseq.h" | ||
43 | 44 | ||
44 | #include "mmc_ops.h" | 45 | #include "mmc_ops.h" |
45 | #include "sd_ops.h" | 46 | #include "sd_ops.h" |
@@ -185,13 +186,14 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) | |||
185 | 186 | ||
186 | EXPORT_SYMBOL(mmc_request_done); | 187 | EXPORT_SYMBOL(mmc_request_done); |
187 | 188 | ||
188 | static void | 189 | static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) |
189 | mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) | ||
190 | { | 190 | { |
191 | #ifdef CONFIG_MMC_DEBUG | 191 | #ifdef CONFIG_MMC_DEBUG |
192 | unsigned int i, sz; | 192 | unsigned int i, sz; |
193 | struct scatterlist *sg; | 193 | struct scatterlist *sg; |
194 | #endif | 194 | #endif |
195 | if (mmc_card_removed(host->card)) | ||
196 | return -ENOMEDIUM; | ||
195 | 197 | ||
196 | if (mrq->sbc) { | 198 | if (mrq->sbc) { |
197 | pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n", | 199 | pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n", |
@@ -251,6 +253,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) | |||
251 | mmc_host_clk_hold(host); | 253 | mmc_host_clk_hold(host); |
252 | led_trigger_event(host->led, LED_FULL); | 254 | led_trigger_event(host->led, LED_FULL); |
253 | host->ops->request(host, mrq); | 255 | host->ops->request(host, mrq); |
256 | |||
257 | return 0; | ||
254 | } | 258 | } |
255 | 259 | ||
256 | /** | 260 | /** |
@@ -271,7 +275,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) | |||
271 | 275 | ||
272 | BUG_ON(!card); | 276 | BUG_ON(!card); |
273 | 277 | ||
274 | if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card)) | 278 | if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card)) |
275 | return; | 279 | return; |
276 | 280 | ||
277 | err = mmc_read_bkops_status(card); | 281 | err = mmc_read_bkops_status(card); |
@@ -345,29 +349,34 @@ static void mmc_wait_done(struct mmc_request *mrq) | |||
345 | */ | 349 | */ |
346 | static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq) | 350 | static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq) |
347 | { | 351 | { |
352 | int err; | ||
353 | |||
348 | mrq->done = mmc_wait_data_done; | 354 | mrq->done = mmc_wait_data_done; |
349 | mrq->host = host; | 355 | mrq->host = host; |
350 | if (mmc_card_removed(host->card)) { | 356 | |
351 | mrq->cmd->error = -ENOMEDIUM; | 357 | err = mmc_start_request(host, mrq); |
358 | if (err) { | ||
359 | mrq->cmd->error = err; | ||
352 | mmc_wait_data_done(mrq); | 360 | mmc_wait_data_done(mrq); |
353 | return -ENOMEDIUM; | ||
354 | } | 361 | } |
355 | mmc_start_request(host, mrq); | ||
356 | 362 | ||
357 | return 0; | 363 | return err; |
358 | } | 364 | } |
359 | 365 | ||
360 | static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) | 366 | static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) |
361 | { | 367 | { |
368 | int err; | ||
369 | |||
362 | init_completion(&mrq->completion); | 370 | init_completion(&mrq->completion); |
363 | mrq->done = mmc_wait_done; | 371 | mrq->done = mmc_wait_done; |
364 | if (mmc_card_removed(host->card)) { | 372 | |
365 | mrq->cmd->error = -ENOMEDIUM; | 373 | err = mmc_start_request(host, mrq); |
374 | if (err) { | ||
375 | mrq->cmd->error = err; | ||
366 | complete(&mrq->completion); | 376 | complete(&mrq->completion); |
367 | return -ENOMEDIUM; | ||
368 | } | 377 | } |
369 | mmc_start_request(host, mrq); | 378 | |
370 | return 0; | 379 | return err; |
371 | } | 380 | } |
372 | 381 | ||
373 | /* | 382 | /* |
@@ -1077,6 +1086,30 @@ void mmc_set_ungated(struct mmc_host *host) | |||
1077 | } | 1086 | } |
1078 | #endif | 1087 | #endif |
1079 | 1088 | ||
1089 | int mmc_execute_tuning(struct mmc_card *card) | ||
1090 | { | ||
1091 | struct mmc_host *host = card->host; | ||
1092 | u32 opcode; | ||
1093 | int err; | ||
1094 | |||
1095 | if (!host->ops->execute_tuning) | ||
1096 | return 0; | ||
1097 | |||
1098 | if (mmc_card_mmc(card)) | ||
1099 | opcode = MMC_SEND_TUNING_BLOCK_HS200; | ||
1100 | else | ||
1101 | opcode = MMC_SEND_TUNING_BLOCK; | ||
1102 | |||
1103 | mmc_host_clk_hold(host); | ||
1104 | err = host->ops->execute_tuning(host, opcode); | ||
1105 | mmc_host_clk_release(host); | ||
1106 | |||
1107 | if (err) | ||
1108 | pr_err("%s: tuning execution failed\n", mmc_hostname(host)); | ||
1109 | |||
1110 | return err; | ||
1111 | } | ||
1112 | |||
1080 | /* | 1113 | /* |
1081 | * Change the bus mode (open drain/push-pull) of a host. | 1114 | * Change the bus mode (open drain/push-pull) of a host. |
1082 | */ | 1115 | */ |
@@ -1232,6 +1265,34 @@ EXPORT_SYMBOL(mmc_of_parse_voltage); | |||
1232 | 1265 | ||
1233 | #endif /* CONFIG_OF */ | 1266 | #endif /* CONFIG_OF */ |
1234 | 1267 | ||
1268 | static int mmc_of_get_func_num(struct device_node *node) | ||
1269 | { | ||
1270 | u32 reg; | ||
1271 | int ret; | ||
1272 | |||
1273 | ret = of_property_read_u32(node, "reg", ®); | ||
1274 | if (ret < 0) | ||
1275 | return ret; | ||
1276 | |||
1277 | return reg; | ||
1278 | } | ||
1279 | |||
1280 | struct device_node *mmc_of_find_child_device(struct mmc_host *host, | ||
1281 | unsigned func_num) | ||
1282 | { | ||
1283 | struct device_node *node; | ||
1284 | |||
1285 | if (!host->parent || !host->parent->of_node) | ||
1286 | return NULL; | ||
1287 | |||
1288 | for_each_child_of_node(host->parent->of_node, node) { | ||
1289 | if (mmc_of_get_func_num(node) == func_num) | ||
1290 | return node; | ||
1291 | } | ||
1292 | |||
1293 | return NULL; | ||
1294 | } | ||
1295 | |||
1235 | #ifdef CONFIG_REGULATOR | 1296 | #ifdef CONFIG_REGULATOR |
1236 | 1297 | ||
1237 | /** | 1298 | /** |
@@ -1555,6 +1616,8 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) | |||
1555 | 1616 | ||
1556 | mmc_host_clk_hold(host); | 1617 | mmc_host_clk_hold(host); |
1557 | 1618 | ||
1619 | mmc_pwrseq_pre_power_on(host); | ||
1620 | |||
1558 | host->ios.vdd = fls(ocr) - 1; | 1621 | host->ios.vdd = fls(ocr) - 1; |
1559 | host->ios.power_mode = MMC_POWER_UP; | 1622 | host->ios.power_mode = MMC_POWER_UP; |
1560 | /* Set initial state and call mmc_set_ios */ | 1623 | /* Set initial state and call mmc_set_ios */ |
@@ -1574,6 +1637,8 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) | |||
1574 | */ | 1637 | */ |
1575 | mmc_delay(10); | 1638 | mmc_delay(10); |
1576 | 1639 | ||
1640 | mmc_pwrseq_post_power_on(host); | ||
1641 | |||
1577 | host->ios.clock = host->f_init; | 1642 | host->ios.clock = host->f_init; |
1578 | 1643 | ||
1579 | host->ios.power_mode = MMC_POWER_ON; | 1644 | host->ios.power_mode = MMC_POWER_ON; |
@@ -1595,6 +1660,8 @@ void mmc_power_off(struct mmc_host *host) | |||
1595 | 1660 | ||
1596 | mmc_host_clk_hold(host); | 1661 | mmc_host_clk_hold(host); |
1597 | 1662 | ||
1663 | mmc_pwrseq_power_off(host); | ||
1664 | |||
1598 | host->ios.clock = 0; | 1665 | host->ios.clock = 0; |
1599 | host->ios.vdd = 0; | 1666 | host->ios.vdd = 0; |
1600 | 1667 | ||
@@ -2245,67 +2312,28 @@ static void mmc_hw_reset_for_init(struct mmc_host *host) | |||
2245 | mmc_host_clk_release(host); | 2312 | mmc_host_clk_release(host); |
2246 | } | 2313 | } |
2247 | 2314 | ||
2248 | int mmc_can_reset(struct mmc_card *card) | 2315 | int mmc_hw_reset(struct mmc_host *host) |
2249 | { | ||
2250 | u8 rst_n_function; | ||
2251 | |||
2252 | if (!mmc_card_mmc(card)) | ||
2253 | return 0; | ||
2254 | rst_n_function = card->ext_csd.rst_n_function; | ||
2255 | if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED) | ||
2256 | return 0; | ||
2257 | return 1; | ||
2258 | } | ||
2259 | EXPORT_SYMBOL(mmc_can_reset); | ||
2260 | |||
2261 | static int mmc_do_hw_reset(struct mmc_host *host, int check) | ||
2262 | { | 2316 | { |
2263 | struct mmc_card *card = host->card; | 2317 | int ret; |
2264 | |||
2265 | if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) | ||
2266 | return -EOPNOTSUPP; | ||
2267 | 2318 | ||
2268 | if (!card) | 2319 | if (!host->card) |
2269 | return -EINVAL; | 2320 | return -EINVAL; |
2270 | 2321 | ||
2271 | if (!mmc_can_reset(card)) | 2322 | mmc_bus_get(host); |
2323 | if (!host->bus_ops || host->bus_dead || !host->bus_ops->reset) { | ||
2324 | mmc_bus_put(host); | ||
2272 | return -EOPNOTSUPP; | 2325 | return -EOPNOTSUPP; |
2273 | |||
2274 | mmc_host_clk_hold(host); | ||
2275 | mmc_set_clock(host, host->f_init); | ||
2276 | |||
2277 | host->ops->hw_reset(host); | ||
2278 | |||
2279 | /* If the reset has happened, then a status command will fail */ | ||
2280 | if (check) { | ||
2281 | u32 status; | ||
2282 | |||
2283 | if (!mmc_send_status(card, &status)) { | ||
2284 | mmc_host_clk_release(host); | ||
2285 | return -ENOSYS; | ||
2286 | } | ||
2287 | } | 2326 | } |
2288 | 2327 | ||
2289 | /* Set initial state and call mmc_set_ios */ | 2328 | ret = host->bus_ops->reset(host); |
2290 | mmc_set_initial_state(host); | 2329 | mmc_bus_put(host); |
2291 | 2330 | ||
2292 | mmc_host_clk_release(host); | 2331 | pr_warn("%s: tried to reset card\n", mmc_hostname(host)); |
2293 | 2332 | ||
2294 | return host->bus_ops->power_restore(host); | 2333 | return ret; |
2295 | } | ||
2296 | |||
2297 | int mmc_hw_reset(struct mmc_host *host) | ||
2298 | { | ||
2299 | return mmc_do_hw_reset(host, 0); | ||
2300 | } | 2334 | } |
2301 | EXPORT_SYMBOL(mmc_hw_reset); | 2335 | EXPORT_SYMBOL(mmc_hw_reset); |
2302 | 2336 | ||
2303 | int mmc_hw_reset_check(struct mmc_host *host) | ||
2304 | { | ||
2305 | return mmc_do_hw_reset(host, 1); | ||
2306 | } | ||
2307 | EXPORT_SYMBOL(mmc_hw_reset_check); | ||
2308 | |||
2309 | static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) | 2337 | static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) |
2310 | { | 2338 | { |
2311 | host->f_init = freq; | 2339 | host->f_init = freq; |