diff options
| -rw-r--r-- | drivers/mmc/card/block.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/core/core.c | 49 | ||||
| -rw-r--r-- | drivers/mmc/core/host.h | 21 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc.c | 26 | ||||
| -rw-r--r-- | drivers/mmc/core/sd.c | 22 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio.c | 7 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio_irq.c | 10 | ||||
| -rw-r--r-- | drivers/mmc/host/atmel-mci.c | 3 | ||||
| -rw-r--r-- | drivers/mmc/host/dw_mmc.c | 144 | ||||
| -rw-r--r-- | drivers/mmc/host/of_mmc_spi.c | 4 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-of-esdhc.c | 32 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-pltfm.c | 10 | ||||
| -rw-r--r-- | drivers/mmc/host/sh_mmcif.c | 16 | ||||
| -rw-r--r-- | drivers/mmc/host/tmio_mmc.h | 7 | ||||
| -rw-r--r-- | drivers/mmc/host/tmio_mmc_dma.c | 12 | ||||
| -rw-r--r-- | drivers/mmc/host/tmio_mmc_pio.c | 6 | ||||
| -rw-r--r-- | include/linux/mmc/card.h | 4 | ||||
| -rw-r--r-- | include/linux/mmc/dw_mmc.h | 6 | ||||
| -rw-r--r-- | include/linux/mmc/host.h | 20 |
20 files changed, 269 insertions, 133 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 0cad48a284a8..c6a383d0244d 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c | |||
| @@ -1694,6 +1694,7 @@ static int mmc_add_disk(struct mmc_blk_data *md) | |||
| 1694 | 1694 | ||
| 1695 | md->power_ro_lock.show = power_ro_lock_show; | 1695 | md->power_ro_lock.show = power_ro_lock_show; |
| 1696 | md->power_ro_lock.store = power_ro_lock_store; | 1696 | md->power_ro_lock.store = power_ro_lock_store; |
| 1697 | sysfs_attr_init(&md->power_ro_lock.attr); | ||
| 1697 | md->power_ro_lock.attr.mode = mode; | 1698 | md->power_ro_lock.attr.mode = mode; |
| 1698 | md->power_ro_lock.attr.name = | 1699 | md->power_ro_lock.attr.name = |
| 1699 | "ro_lock_until_next_power_on"; | 1700 | "ro_lock_until_next_power_on"; |
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f545a3e6eb80..690255c7d4dc 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
| @@ -290,8 +290,11 @@ static void mmc_wait_for_req_done(struct mmc_host *host, | |||
| 290 | static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, | 290 | static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, |
| 291 | bool is_first_req) | 291 | bool is_first_req) |
| 292 | { | 292 | { |
| 293 | if (host->ops->pre_req) | 293 | if (host->ops->pre_req) { |
| 294 | mmc_host_clk_hold(host); | ||
| 294 | host->ops->pre_req(host, mrq, is_first_req); | 295 | host->ops->pre_req(host, mrq, is_first_req); |
| 296 | mmc_host_clk_release(host); | ||
| 297 | } | ||
| 295 | } | 298 | } |
| 296 | 299 | ||
| 297 | /** | 300 | /** |
| @@ -306,8 +309,11 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, | |||
| 306 | static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, | 309 | static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, |
| 307 | int err) | 310 | int err) |
| 308 | { | 311 | { |
| 309 | if (host->ops->post_req) | 312 | if (host->ops->post_req) { |
| 313 | mmc_host_clk_hold(host); | ||
| 310 | host->ops->post_req(host, mrq, err); | 314 | host->ops->post_req(host, mrq, err); |
| 315 | mmc_host_clk_release(host); | ||
| 316 | } | ||
| 311 | } | 317 | } |
| 312 | 318 | ||
| 313 | /** | 319 | /** |
| @@ -620,7 +626,9 @@ int mmc_host_enable(struct mmc_host *host) | |||
| 620 | int err; | 626 | int err; |
| 621 | 627 | ||
| 622 | host->en_dis_recurs = 1; | 628 | host->en_dis_recurs = 1; |
| 629 | mmc_host_clk_hold(host); | ||
| 623 | err = host->ops->enable(host); | 630 | err = host->ops->enable(host); |
| 631 | mmc_host_clk_release(host); | ||
| 624 | host->en_dis_recurs = 0; | 632 | host->en_dis_recurs = 0; |
| 625 | 633 | ||
| 626 | if (err) { | 634 | if (err) { |
| @@ -640,7 +648,9 @@ static int mmc_host_do_disable(struct mmc_host *host, int lazy) | |||
| 640 | int err; | 648 | int err; |
| 641 | 649 | ||
| 642 | host->en_dis_recurs = 1; | 650 | host->en_dis_recurs = 1; |
| 651 | mmc_host_clk_hold(host); | ||
| 643 | err = host->ops->disable(host, lazy); | 652 | err = host->ops->disable(host, lazy); |
| 653 | mmc_host_clk_release(host); | ||
| 644 | host->en_dis_recurs = 0; | 654 | host->en_dis_recurs = 0; |
| 645 | 655 | ||
| 646 | if (err < 0) { | 656 | if (err < 0) { |
| @@ -1121,6 +1131,10 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, | |||
| 1121 | * might not allow this operation | 1131 | * might not allow this operation |
| 1122 | */ | 1132 | */ |
| 1123 | voltage = regulator_get_voltage(supply); | 1133 | voltage = regulator_get_voltage(supply); |
| 1134 | |||
| 1135 | if (mmc->caps2 & MMC_CAP2_BROKEN_VOLTAGE) | ||
| 1136 | min_uV = max_uV = voltage; | ||
| 1137 | |||
| 1124 | if (voltage < 0) | 1138 | if (voltage < 0) |
| 1125 | result = voltage; | 1139 | result = voltage; |
| 1126 | else if (voltage < min_uV || voltage > max_uV) | 1140 | else if (voltage < min_uV || voltage > max_uV) |
| @@ -1203,8 +1217,11 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11 | |||
| 1203 | 1217 | ||
| 1204 | host->ios.signal_voltage = signal_voltage; | 1218 | host->ios.signal_voltage = signal_voltage; |
| 1205 | 1219 | ||
| 1206 | if (host->ops->start_signal_voltage_switch) | 1220 | if (host->ops->start_signal_voltage_switch) { |
| 1221 | mmc_host_clk_hold(host); | ||
| 1207 | err = host->ops->start_signal_voltage_switch(host, &host->ios); | 1222 | err = host->ops->start_signal_voltage_switch(host, &host->ios); |
| 1223 | mmc_host_clk_release(host); | ||
| 1224 | } | ||
| 1208 | 1225 | ||
| 1209 | return err; | 1226 | return err; |
| 1210 | } | 1227 | } |
| @@ -1239,6 +1256,7 @@ static void mmc_poweroff_notify(struct mmc_host *host) | |||
| 1239 | int err = 0; | 1256 | int err = 0; |
| 1240 | 1257 | ||
| 1241 | card = host->card; | 1258 | card = host->card; |
| 1259 | mmc_claim_host(host); | ||
| 1242 | 1260 | ||
| 1243 | /* | 1261 | /* |
| 1244 | * Send power notify command only if card | 1262 | * Send power notify command only if card |
| @@ -1269,6 +1287,7 @@ static void mmc_poweroff_notify(struct mmc_host *host) | |||
| 1269 | /* Set the card state to no notification after the poweroff */ | 1287 | /* Set the card state to no notification after the poweroff */ |
| 1270 | card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION; | 1288 | card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION; |
| 1271 | } | 1289 | } |
| 1290 | mmc_release_host(host); | ||
| 1272 | } | 1291 | } |
| 1273 | 1292 | ||
| 1274 | /* | 1293 | /* |
| @@ -1327,12 +1346,28 @@ static void mmc_power_up(struct mmc_host *host) | |||
| 1327 | 1346 | ||
| 1328 | void mmc_power_off(struct mmc_host *host) | 1347 | void mmc_power_off(struct mmc_host *host) |
| 1329 | { | 1348 | { |
| 1349 | int err = 0; | ||
| 1330 | mmc_host_clk_hold(host); | 1350 | mmc_host_clk_hold(host); |
| 1331 | 1351 | ||
| 1332 | host->ios.clock = 0; | 1352 | host->ios.clock = 0; |
| 1333 | host->ios.vdd = 0; | 1353 | host->ios.vdd = 0; |
| 1334 | 1354 | ||
| 1335 | mmc_poweroff_notify(host); | 1355 | /* |
| 1356 | * For eMMC 4.5 device send AWAKE command before | ||
| 1357 | * POWER_OFF_NOTIFY command, because in sleep state | ||
| 1358 | * eMMC 4.5 devices respond to only RESET and AWAKE cmd | ||
| 1359 | */ | ||
| 1360 | if (host->card && mmc_card_is_sleep(host->card) && | ||
| 1361 | host->bus_ops->resume) { | ||
| 1362 | err = host->bus_ops->resume(host); | ||
| 1363 | |||
| 1364 | if (!err) | ||
| 1365 | mmc_poweroff_notify(host); | ||
| 1366 | else | ||
| 1367 | pr_warning("%s: error %d during resume " | ||
| 1368 | "(continue with poweroff sequence)\n", | ||
| 1369 | mmc_hostname(host), err); | ||
| 1370 | } | ||
| 1336 | 1371 | ||
| 1337 | /* | 1372 | /* |
| 1338 | * Reset ocr mask to be the highest possible voltage supported for | 1373 | * Reset ocr mask to be the highest possible voltage supported for |
| @@ -2386,12 +2421,6 @@ int mmc_suspend_host(struct mmc_host *host) | |||
| 2386 | */ | 2421 | */ |
| 2387 | if (mmc_try_claim_host(host)) { | 2422 | if (mmc_try_claim_host(host)) { |
| 2388 | if (host->bus_ops->suspend) { | 2423 | if (host->bus_ops->suspend) { |
| 2389 | /* | ||
| 2390 | * For eMMC 4.5 device send notify command | ||
| 2391 | * before sleep, because in sleep state eMMC 4.5 | ||
| 2392 | * devices respond to only RESET and AWAKE cmd | ||
| 2393 | */ | ||
| 2394 | mmc_poweroff_notify(host); | ||
| 2395 | err = host->bus_ops->suspend(host); | 2424 | err = host->bus_ops->suspend(host); |
| 2396 | } | 2425 | } |
| 2397 | mmc_do_release_host(host); | 2426 | mmc_do_release_host(host); |
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index fb8a5cd2e4a1..08a7852ade44 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h | |||
| @@ -14,27 +14,6 @@ | |||
| 14 | 14 | ||
| 15 | int mmc_register_host_class(void); | 15 | int mmc_register_host_class(void); |
| 16 | void mmc_unregister_host_class(void); | 16 | void mmc_unregister_host_class(void); |
| 17 | |||
| 18 | #ifdef CONFIG_MMC_CLKGATE | ||
| 19 | void mmc_host_clk_hold(struct mmc_host *host); | ||
| 20 | void mmc_host_clk_release(struct mmc_host *host); | ||
| 21 | unsigned int mmc_host_clk_rate(struct mmc_host *host); | ||
| 22 | |||
| 23 | #else | ||
| 24 | static inline void mmc_host_clk_hold(struct mmc_host *host) | ||
| 25 | { | ||
| 26 | } | ||
| 27 | |||
| 28 | static inline void mmc_host_clk_release(struct mmc_host *host) | ||
| 29 | { | ||
| 30 | } | ||
| 31 | |||
| 32 | static inline unsigned int mmc_host_clk_rate(struct mmc_host *host) | ||
| 33 | { | ||
| 34 | return host->ios.clock; | ||
| 35 | } | ||
| 36 | #endif | ||
| 37 | |||
| 38 | void mmc_host_deeper_disable(struct work_struct *work); | 17 | void mmc_host_deeper_disable(struct work_struct *work); |
| 39 | 18 | ||
| 40 | #endif | 19 | #endif |
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 59b9ba52e66a..a48066344fa8 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c | |||
| @@ -376,7 +376,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | card->ext_csd.raw_hc_erase_gap_size = | 378 | card->ext_csd.raw_hc_erase_gap_size = |
| 379 | ext_csd[EXT_CSD_PARTITION_ATTRIBUTE]; | 379 | ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; |
| 380 | card->ext_csd.raw_sec_trim_mult = | 380 | card->ext_csd.raw_sec_trim_mult = |
| 381 | ext_csd[EXT_CSD_SEC_TRIM_MULT]; | 381 | ext_csd[EXT_CSD_SEC_TRIM_MULT]; |
| 382 | card->ext_csd.raw_sec_erase_mult = | 382 | card->ext_csd.raw_sec_erase_mult = |
| @@ -551,7 +551,7 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) | |||
| 551 | goto out; | 551 | goto out; |
| 552 | 552 | ||
| 553 | /* only compare read only fields */ | 553 | /* only compare read only fields */ |
| 554 | err = (!(card->ext_csd.raw_partition_support == | 554 | err = !((card->ext_csd.raw_partition_support == |
| 555 | bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) && | 555 | bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) && |
| 556 | (card->ext_csd.raw_erased_mem_count == | 556 | (card->ext_csd.raw_erased_mem_count == |
| 557 | bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) && | 557 | bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) && |
| @@ -1006,7 +1006,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 1006 | err = mmc_select_hs200(card); | 1006 | err = mmc_select_hs200(card); |
| 1007 | else if (host->caps & MMC_CAP_MMC_HIGHSPEED) | 1007 | else if (host->caps & MMC_CAP_MMC_HIGHSPEED) |
| 1008 | err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | 1008 | err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, |
| 1009 | EXT_CSD_HS_TIMING, 1, 0); | 1009 | EXT_CSD_HS_TIMING, 1, |
| 1010 | card->ext_csd.generic_cmd6_time); | ||
| 1010 | 1011 | ||
| 1011 | if (err && err != -EBADMSG) | 1012 | if (err && err != -EBADMSG) |
| 1012 | goto free_card; | 1013 | goto free_card; |
| @@ -1116,7 +1117,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 1116 | * Activate wide bus and DDR (if supported). | 1117 | * Activate wide bus and DDR (if supported). |
| 1117 | */ | 1118 | */ |
| 1118 | if (!mmc_card_hs200(card) && | 1119 | if (!mmc_card_hs200(card) && |
| 1119 | (card->csd.mmca_vsn >= CSD_SPEC_VER_3) && | 1120 | (card->csd.mmca_vsn >= CSD_SPEC_VER_4) && |
| 1120 | (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) { | 1121 | (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) { |
| 1121 | static unsigned ext_csd_bits[][2] = { | 1122 | static unsigned ext_csd_bits[][2] = { |
| 1122 | { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 }, | 1123 | { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 }, |
| @@ -1315,11 +1316,13 @@ static int mmc_suspend(struct mmc_host *host) | |||
| 1315 | BUG_ON(!host->card); | 1316 | BUG_ON(!host->card); |
| 1316 | 1317 | ||
| 1317 | mmc_claim_host(host); | 1318 | mmc_claim_host(host); |
| 1318 | if (mmc_card_can_sleep(host)) | 1319 | if (mmc_card_can_sleep(host)) { |
| 1319 | err = mmc_card_sleep(host); | 1320 | err = mmc_card_sleep(host); |
| 1320 | else if (!mmc_host_is_spi(host)) | 1321 | if (!err) |
| 1322 | mmc_card_set_sleep(host->card); | ||
| 1323 | } else if (!mmc_host_is_spi(host)) | ||
| 1321 | mmc_deselect_cards(host); | 1324 | mmc_deselect_cards(host); |
| 1322 | host->card->state &= ~MMC_STATE_HIGHSPEED; | 1325 | host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200); |
| 1323 | mmc_release_host(host); | 1326 | mmc_release_host(host); |
| 1324 | 1327 | ||
| 1325 | return err; | 1328 | return err; |
| @@ -1339,7 +1342,11 @@ static int mmc_resume(struct mmc_host *host) | |||
| 1339 | BUG_ON(!host->card); | 1342 | BUG_ON(!host->card); |
| 1340 | 1343 | ||
| 1341 | mmc_claim_host(host); | 1344 | mmc_claim_host(host); |
| 1342 | err = mmc_init_card(host, host->ocr, host->card); | 1345 | if (mmc_card_is_sleep(host->card)) { |
| 1346 | err = mmc_card_awake(host); | ||
| 1347 | mmc_card_clr_sleep(host->card); | ||
| 1348 | } else | ||
| 1349 | err = mmc_init_card(host, host->ocr, host->card); | ||
| 1343 | mmc_release_host(host); | 1350 | mmc_release_host(host); |
| 1344 | 1351 | ||
| 1345 | return err; | 1352 | return err; |
| @@ -1349,7 +1356,8 @@ static int mmc_power_restore(struct mmc_host *host) | |||
| 1349 | { | 1356 | { |
| 1350 | int ret; | 1357 | int ret; |
| 1351 | 1358 | ||
| 1352 | host->card->state &= ~MMC_STATE_HIGHSPEED; | 1359 | host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200); |
| 1360 | mmc_card_clr_sleep(host->card); | ||
| 1353 | mmc_claim_host(host); | 1361 | mmc_claim_host(host); |
| 1354 | ret = mmc_init_card(host, host->ocr, host->card); | 1362 | ret = mmc_init_card(host, host->ocr, host->card); |
| 1355 | mmc_release_host(host); | 1363 | mmc_release_host(host); |
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index c63ad03c29c7..5017f9354ce2 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c | |||
| @@ -451,9 +451,11 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status) | |||
| 451 | * information and let the hardware specific code | 451 | * information and let the hardware specific code |
| 452 | * return what is possible given the options | 452 | * return what is possible given the options |
| 453 | */ | 453 | */ |
| 454 | mmc_host_clk_hold(card->host); | ||
| 454 | drive_strength = card->host->ops->select_drive_strength( | 455 | drive_strength = card->host->ops->select_drive_strength( |
| 455 | card->sw_caps.uhs_max_dtr, | 456 | card->sw_caps.uhs_max_dtr, |
| 456 | host_drv_type, card_drv_type); | 457 | host_drv_type, card_drv_type); |
| 458 | mmc_host_clk_release(card->host); | ||
| 457 | 459 | ||
| 458 | err = mmc_sd_switch(card, 1, 2, drive_strength, status); | 460 | err = mmc_sd_switch(card, 1, 2, drive_strength, status); |
| 459 | if (err) | 461 | if (err) |
| @@ -660,9 +662,12 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) | |||
| 660 | goto out; | 662 | goto out; |
| 661 | 663 | ||
| 662 | /* SPI mode doesn't define CMD19 */ | 664 | /* SPI mode doesn't define CMD19 */ |
| 663 | if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) | 665 | if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) { |
| 666 | mmc_host_clk_hold(card->host); | ||
| 664 | err = card->host->ops->execute_tuning(card->host, | 667 | err = card->host->ops->execute_tuning(card->host, |
| 665 | MMC_SEND_TUNING_BLOCK); | 668 | MMC_SEND_TUNING_BLOCK); |
| 669 | mmc_host_clk_release(card->host); | ||
| 670 | } | ||
| 666 | 671 | ||
| 667 | out: | 672 | out: |
| 668 | kfree(status); | 673 | kfree(status); |
| @@ -850,8 +855,11 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, | |||
| 850 | if (!reinit) { | 855 | if (!reinit) { |
| 851 | int ro = -1; | 856 | int ro = -1; |
| 852 | 857 | ||
| 853 | if (host->ops->get_ro) | 858 | if (host->ops->get_ro) { |
| 859 | mmc_host_clk_hold(card->host); | ||
| 854 | ro = host->ops->get_ro(host); | 860 | ro = host->ops->get_ro(host); |
| 861 | mmc_host_clk_release(card->host); | ||
| 862 | } | ||
| 855 | 863 | ||
| 856 | if (ro < 0) { | 864 | if (ro < 0) { |
| 857 | pr_warning("%s: host does not " | 865 | pr_warning("%s: host does not " |
| @@ -967,8 +975,11 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, | |||
| 967 | * Since initialization is now complete, enable preset | 975 | * Since initialization is now complete, enable preset |
| 968 | * value registers for UHS-I cards. | 976 | * value registers for UHS-I cards. |
| 969 | */ | 977 | */ |
| 970 | if (host->ops->enable_preset_value) | 978 | if (host->ops->enable_preset_value) { |
| 979 | mmc_host_clk_hold(card->host); | ||
| 971 | host->ops->enable_preset_value(host, true); | 980 | host->ops->enable_preset_value(host, true); |
| 981 | mmc_host_clk_release(card->host); | ||
| 982 | } | ||
| 972 | } else { | 983 | } else { |
| 973 | /* | 984 | /* |
| 974 | * Attempt to change to high-speed (if supported) | 985 | * Attempt to change to high-speed (if supported) |
| @@ -1151,8 +1162,11 @@ int mmc_attach_sd(struct mmc_host *host) | |||
| 1151 | return err; | 1162 | return err; |
| 1152 | 1163 | ||
| 1153 | /* Disable preset value enable if already set since last time */ | 1164 | /* Disable preset value enable if already set since last time */ |
| 1154 | if (host->ops->enable_preset_value) | 1165 | if (host->ops->enable_preset_value) { |
| 1166 | mmc_host_clk_hold(host); | ||
| 1155 | host->ops->enable_preset_value(host, false); | 1167 | host->ops->enable_preset_value(host, false); |
| 1168 | mmc_host_clk_release(host); | ||
| 1169 | } | ||
| 1156 | 1170 | ||
| 1157 | err = mmc_send_app_op_cond(host, 0, &ocr); | 1171 | err = mmc_send_app_op_cond(host, 0, &ocr); |
| 1158 | if (err) | 1172 | if (err) |
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index bd7bacc950dc..12cde6ee17f5 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c | |||
| @@ -98,10 +98,11 @@ fail: | |||
| 98 | return ret; | 98 | return ret; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | static int sdio_read_cccr(struct mmc_card *card) | 101 | static int sdio_read_cccr(struct mmc_card *card, u32 ocr) |
| 102 | { | 102 | { |
| 103 | int ret; | 103 | int ret; |
| 104 | int cccr_vsn; | 104 | int cccr_vsn; |
| 105 | int uhs = ocr & R4_18V_PRESENT; | ||
| 105 | unsigned char data; | 106 | unsigned char data; |
| 106 | unsigned char speed; | 107 | unsigned char speed; |
| 107 | 108 | ||
| @@ -149,7 +150,7 @@ static int sdio_read_cccr(struct mmc_card *card) | |||
| 149 | card->scr.sda_spec3 = 0; | 150 | card->scr.sda_spec3 = 0; |
| 150 | card->sw_caps.sd3_bus_mode = 0; | 151 | card->sw_caps.sd3_bus_mode = 0; |
| 151 | card->sw_caps.sd3_drv_type = 0; | 152 | card->sw_caps.sd3_drv_type = 0; |
| 152 | if (cccr_vsn >= SDIO_CCCR_REV_3_00) { | 153 | if (cccr_vsn >= SDIO_CCCR_REV_3_00 && uhs) { |
| 153 | card->scr.sda_spec3 = 1; | 154 | card->scr.sda_spec3 = 1; |
| 154 | ret = mmc_io_rw_direct(card, 0, 0, | 155 | ret = mmc_io_rw_direct(card, 0, 0, |
| 155 | SDIO_CCCR_UHS, 0, &data); | 156 | SDIO_CCCR_UHS, 0, &data); |
| @@ -712,7 +713,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, | |||
| 712 | /* | 713 | /* |
| 713 | * Read the common registers. | 714 | * Read the common registers. |
| 714 | */ | 715 | */ |
| 715 | err = sdio_read_cccr(card); | 716 | err = sdio_read_cccr(card, ocr); |
| 716 | if (err) | 717 | if (err) |
| 717 | goto remove; | 718 | goto remove; |
| 718 | 719 | ||
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 68f81b9ee0fb..f573e7f9f740 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c | |||
| @@ -146,15 +146,21 @@ static int sdio_irq_thread(void *_host) | |||
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | set_current_state(TASK_INTERRUPTIBLE); | 148 | set_current_state(TASK_INTERRUPTIBLE); |
| 149 | if (host->caps & MMC_CAP_SDIO_IRQ) | 149 | if (host->caps & MMC_CAP_SDIO_IRQ) { |
| 150 | mmc_host_clk_hold(host); | ||
| 150 | host->ops->enable_sdio_irq(host, 1); | 151 | host->ops->enable_sdio_irq(host, 1); |
| 152 | mmc_host_clk_release(host); | ||
| 153 | } | ||
| 151 | if (!kthread_should_stop()) | 154 | if (!kthread_should_stop()) |
| 152 | schedule_timeout(period); | 155 | schedule_timeout(period); |
| 153 | set_current_state(TASK_RUNNING); | 156 | set_current_state(TASK_RUNNING); |
| 154 | } while (!kthread_should_stop()); | 157 | } while (!kthread_should_stop()); |
| 155 | 158 | ||
| 156 | if (host->caps & MMC_CAP_SDIO_IRQ) | 159 | if (host->caps & MMC_CAP_SDIO_IRQ) { |
| 160 | mmc_host_clk_hold(host); | ||
| 157 | host->ops->enable_sdio_irq(host, 0); | 161 | host->ops->enable_sdio_irq(host, 0); |
| 162 | mmc_host_clk_release(host); | ||
| 163 | } | ||
| 158 | 164 | ||
| 159 | pr_debug("%s: IRQ thread exiting with code %d\n", | 165 | pr_debug("%s: IRQ thread exiting with code %d\n", |
| 160 | mmc_hostname(host), ret); | 166 | mmc_hostname(host), ret); |
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index fcfe1eb5acc8..6985cdb0bb26 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c | |||
| @@ -969,11 +969,14 @@ static void atmci_start_request(struct atmel_mci *host, | |||
| 969 | host->data_status = 0; | 969 | host->data_status = 0; |
| 970 | 970 | ||
| 971 | if (host->need_reset) { | 971 | if (host->need_reset) { |
| 972 | iflags = atmci_readl(host, ATMCI_IMR); | ||
| 973 | iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB); | ||
| 972 | atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); | 974 | atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); |
| 973 | atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); | 975 | atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); |
| 974 | atmci_writel(host, ATMCI_MR, host->mode_reg); | 976 | atmci_writel(host, ATMCI_MR, host->mode_reg); |
| 975 | if (host->caps.has_cfg_reg) | 977 | if (host->caps.has_cfg_reg) |
| 976 | atmci_writel(host, ATMCI_CFG, host->cfg_reg); | 978 | atmci_writel(host, ATMCI_CFG, host->cfg_reg); |
| 979 | atmci_writel(host, ATMCI_IER, iflags); | ||
| 977 | host->need_reset = false; | 980 | host->need_reset = false; |
| 978 | } | 981 | } |
| 979 | atmci_writel(host, ATMCI_SDCR, slot->sdc_reg); | 982 | atmci_writel(host, ATMCI_SDCR, slot->sdc_reg); |
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 0e342793ff14..8bec1c36b159 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c | |||
| @@ -22,7 +22,6 @@ | |||
| 22 | #include <linux/ioport.h> | 22 | #include <linux/ioport.h> |
| 23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
| 24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 25 | #include <linux/scatterlist.h> | ||
| 26 | #include <linux/seq_file.h> | 25 | #include <linux/seq_file.h> |
| 27 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
| 28 | #include <linux/stat.h> | 27 | #include <linux/stat.h> |
| @@ -502,8 +501,14 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) | |||
| 502 | host->dir_status = DW_MCI_SEND_STATUS; | 501 | host->dir_status = DW_MCI_SEND_STATUS; |
| 503 | 502 | ||
| 504 | if (dw_mci_submit_data_dma(host, data)) { | 503 | if (dw_mci_submit_data_dma(host, data)) { |
| 504 | int flags = SG_MITER_ATOMIC; | ||
| 505 | if (host->data->flags & MMC_DATA_READ) | ||
| 506 | flags |= SG_MITER_TO_SG; | ||
| 507 | else | ||
| 508 | flags |= SG_MITER_FROM_SG; | ||
| 509 | |||
| 510 | sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); | ||
| 505 | host->sg = data->sg; | 511 | host->sg = data->sg; |
| 506 | host->pio_offset = 0; | ||
| 507 | host->part_buf_start = 0; | 512 | host->part_buf_start = 0; |
| 508 | host->part_buf_count = 0; | 513 | host->part_buf_count = 0; |
| 509 | 514 | ||
| @@ -972,6 +977,7 @@ static void dw_mci_tasklet_func(unsigned long priv) | |||
| 972 | * generates a block interrupt, hence setting | 977 | * generates a block interrupt, hence setting |
| 973 | * the scatter-gather pointer to NULL. | 978 | * the scatter-gather pointer to NULL. |
| 974 | */ | 979 | */ |
| 980 | sg_miter_stop(&host->sg_miter); | ||
| 975 | host->sg = NULL; | 981 | host->sg = NULL; |
| 976 | ctrl = mci_readl(host, CTRL); | 982 | ctrl = mci_readl(host, CTRL); |
| 977 | ctrl |= SDMMC_CTRL_FIFO_RESET; | 983 | ctrl |= SDMMC_CTRL_FIFO_RESET; |
| @@ -1311,54 +1317,44 @@ static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) | |||
| 1311 | 1317 | ||
| 1312 | static void dw_mci_read_data_pio(struct dw_mci *host) | 1318 | static void dw_mci_read_data_pio(struct dw_mci *host) |
| 1313 | { | 1319 | { |
| 1314 | struct scatterlist *sg = host->sg; | 1320 | struct sg_mapping_iter *sg_miter = &host->sg_miter; |
| 1315 | void *buf = sg_virt(sg); | 1321 | void *buf; |
| 1316 | unsigned int offset = host->pio_offset; | 1322 | unsigned int offset; |
| 1317 | struct mmc_data *data = host->data; | 1323 | struct mmc_data *data = host->data; |
| 1318 | int shift = host->data_shift; | 1324 | int shift = host->data_shift; |
| 1319 | u32 status; | 1325 | u32 status; |
| 1320 | unsigned int nbytes = 0, len; | 1326 | unsigned int nbytes = 0, len; |
| 1327 | unsigned int remain, fcnt; | ||
| 1321 | 1328 | ||
| 1322 | do { | 1329 | do { |
| 1323 | len = host->part_buf_count + | 1330 | if (!sg_miter_next(sg_miter)) |
| 1324 | (SDMMC_GET_FCNT(mci_readl(host, STATUS)) << shift); | 1331 | goto done; |
| 1325 | if (offset + len <= sg->length) { | 1332 | |
| 1333 | host->sg = sg_miter->__sg; | ||
| 1334 | buf = sg_miter->addr; | ||
| 1335 | remain = sg_miter->length; | ||
| 1336 | offset = 0; | ||
| 1337 | |||
| 1338 | do { | ||
| 1339 | fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS)) | ||
| 1340 | << shift) + host->part_buf_count; | ||
| 1341 | len = min(remain, fcnt); | ||
| 1342 | if (!len) | ||
| 1343 | break; | ||
| 1326 | dw_mci_pull_data(host, (void *)(buf + offset), len); | 1344 | dw_mci_pull_data(host, (void *)(buf + offset), len); |
| 1327 | |||
| 1328 | offset += len; | 1345 | offset += len; |
| 1329 | nbytes += len; | 1346 | nbytes += len; |
| 1330 | 1347 | remain -= len; | |
| 1331 | if (offset == sg->length) { | 1348 | } while (remain); |
| 1332 | flush_dcache_page(sg_page(sg)); | 1349 | sg_miter->consumed = offset; |
| 1333 | host->sg = sg = sg_next(sg); | ||
| 1334 | if (!sg) | ||
| 1335 | goto done; | ||
| 1336 | |||
| 1337 | offset = 0; | ||
| 1338 | buf = sg_virt(sg); | ||
| 1339 | } | ||
| 1340 | } else { | ||
| 1341 | unsigned int remaining = sg->length - offset; | ||
| 1342 | dw_mci_pull_data(host, (void *)(buf + offset), | ||
| 1343 | remaining); | ||
| 1344 | nbytes += remaining; | ||
| 1345 | |||
| 1346 | flush_dcache_page(sg_page(sg)); | ||
| 1347 | host->sg = sg = sg_next(sg); | ||
| 1348 | if (!sg) | ||
| 1349 | goto done; | ||
| 1350 | |||
| 1351 | offset = len - remaining; | ||
| 1352 | buf = sg_virt(sg); | ||
| 1353 | dw_mci_pull_data(host, buf, offset); | ||
| 1354 | nbytes += offset; | ||
| 1355 | } | ||
| 1356 | 1350 | ||
| 1357 | status = mci_readl(host, MINTSTS); | 1351 | status = mci_readl(host, MINTSTS); |
| 1358 | mci_writel(host, RINTSTS, SDMMC_INT_RXDR); | 1352 | mci_writel(host, RINTSTS, SDMMC_INT_RXDR); |
| 1359 | if (status & DW_MCI_DATA_ERROR_FLAGS) { | 1353 | if (status & DW_MCI_DATA_ERROR_FLAGS) { |
| 1360 | host->data_status = status; | 1354 | host->data_status = status; |
| 1361 | data->bytes_xfered += nbytes; | 1355 | data->bytes_xfered += nbytes; |
| 1356 | sg_miter_stop(sg_miter); | ||
| 1357 | host->sg = NULL; | ||
| 1362 | smp_wmb(); | 1358 | smp_wmb(); |
| 1363 | 1359 | ||
| 1364 | set_bit(EVENT_DATA_ERROR, &host->pending_events); | 1360 | set_bit(EVENT_DATA_ERROR, &host->pending_events); |
| @@ -1367,65 +1363,66 @@ static void dw_mci_read_data_pio(struct dw_mci *host) | |||
| 1367 | return; | 1363 | return; |
| 1368 | } | 1364 | } |
| 1369 | } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/ | 1365 | } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/ |
| 1370 | host->pio_offset = offset; | ||
| 1371 | data->bytes_xfered += nbytes; | 1366 | data->bytes_xfered += nbytes; |
| 1367 | |||
| 1368 | if (!remain) { | ||
| 1369 | if (!sg_miter_next(sg_miter)) | ||
| 1370 | goto done; | ||
| 1371 | sg_miter->consumed = 0; | ||
| 1372 | } | ||
| 1373 | sg_miter_stop(sg_miter); | ||
| 1372 | return; | 1374 | return; |
| 1373 | 1375 | ||
| 1374 | done: | 1376 | done: |
| 1375 | data->bytes_xfered += nbytes; | 1377 | data->bytes_xfered += nbytes; |
| 1378 | sg_miter_stop(sg_miter); | ||
| 1379 | host->sg = NULL; | ||
| 1376 | smp_wmb(); | 1380 | smp_wmb(); |
| 1377 | set_bit(EVENT_XFER_COMPLETE, &host->pending_events); | 1381 | set_bit(EVENT_XFER_COMPLETE, &host->pending_events); |
| 1378 | } | 1382 | } |
| 1379 | 1383 | ||
| 1380 | static void dw_mci_write_data_pio(struct dw_mci *host) | 1384 | static void dw_mci_write_data_pio(struct dw_mci *host) |
| 1381 | { | 1385 | { |
| 1382 | struct scatterlist *sg = host->sg; | 1386 | struct sg_mapping_iter *sg_miter = &host->sg_miter; |
| 1383 | void *buf = sg_virt(sg); | 1387 | void *buf; |
| 1384 | unsigned int offset = host->pio_offset; | 1388 | unsigned int offset; |
| 1385 | struct mmc_data *data = host->data; | 1389 | struct mmc_data *data = host->data; |
| 1386 | int shift = host->data_shift; | 1390 | int shift = host->data_shift; |
| 1387 | u32 status; | 1391 | u32 status; |
| 1388 | unsigned int nbytes = 0, len; | 1392 | unsigned int nbytes = 0, len; |
| 1393 | unsigned int fifo_depth = host->fifo_depth; | ||
| 1394 | unsigned int remain, fcnt; | ||
| 1389 | 1395 | ||
| 1390 | do { | 1396 | do { |
| 1391 | len = ((host->fifo_depth - | 1397 | if (!sg_miter_next(sg_miter)) |
| 1392 | SDMMC_GET_FCNT(mci_readl(host, STATUS))) << shift) | 1398 | goto done; |
| 1393 | - host->part_buf_count; | 1399 | |
| 1394 | if (offset + len <= sg->length) { | 1400 | host->sg = sg_miter->__sg; |
| 1401 | buf = sg_miter->addr; | ||
| 1402 | remain = sg_miter->length; | ||
| 1403 | offset = 0; | ||
| 1404 | |||
| 1405 | do { | ||
| 1406 | fcnt = ((fifo_depth - | ||
| 1407 | SDMMC_GET_FCNT(mci_readl(host, STATUS))) | ||
| 1408 | << shift) - host->part_buf_count; | ||
| 1409 | len = min(remain, fcnt); | ||
| 1410 | if (!len) | ||
| 1411 | break; | ||
| 1395 | host->push_data(host, (void *)(buf + offset), len); | 1412 | host->push_data(host, (void *)(buf + offset), len); |
| 1396 | |||
| 1397 | offset += len; | 1413 | offset += len; |
| 1398 | nbytes += len; | 1414 | nbytes += len; |
| 1399 | if (offset == sg->length) { | 1415 | remain -= len; |
| 1400 | host->sg = sg = sg_next(sg); | 1416 | } while (remain); |
| 1401 | if (!sg) | 1417 | sg_miter->consumed = offset; |
| 1402 | goto done; | ||
| 1403 | |||
| 1404 | offset = 0; | ||
| 1405 | buf = sg_virt(sg); | ||
| 1406 | } | ||
| 1407 | } else { | ||
| 1408 | unsigned int remaining = sg->length - offset; | ||
| 1409 | |||
| 1410 | host->push_data(host, (void *)(buf + offset), | ||
| 1411 | remaining); | ||
| 1412 | nbytes += remaining; | ||
| 1413 | |||
| 1414 | host->sg = sg = sg_next(sg); | ||
| 1415 | if (!sg) | ||
| 1416 | goto done; | ||
| 1417 | |||
| 1418 | offset = len - remaining; | ||
| 1419 | buf = sg_virt(sg); | ||
| 1420 | host->push_data(host, (void *)buf, offset); | ||
| 1421 | nbytes += offset; | ||
| 1422 | } | ||
| 1423 | 1418 | ||
| 1424 | status = mci_readl(host, MINTSTS); | 1419 | status = mci_readl(host, MINTSTS); |
| 1425 | mci_writel(host, RINTSTS, SDMMC_INT_TXDR); | 1420 | mci_writel(host, RINTSTS, SDMMC_INT_TXDR); |
| 1426 | if (status & DW_MCI_DATA_ERROR_FLAGS) { | 1421 | if (status & DW_MCI_DATA_ERROR_FLAGS) { |
| 1427 | host->data_status = status; | 1422 | host->data_status = status; |
| 1428 | data->bytes_xfered += nbytes; | 1423 | data->bytes_xfered += nbytes; |
| 1424 | sg_miter_stop(sg_miter); | ||
| 1425 | host->sg = NULL; | ||
| 1429 | 1426 | ||
| 1430 | smp_wmb(); | 1427 | smp_wmb(); |
| 1431 | 1428 | ||
| @@ -1435,12 +1432,20 @@ static void dw_mci_write_data_pio(struct dw_mci *host) | |||
| 1435 | return; | 1432 | return; |
| 1436 | } | 1433 | } |
| 1437 | } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ | 1434 | } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ |
| 1438 | host->pio_offset = offset; | ||
| 1439 | data->bytes_xfered += nbytes; | 1435 | data->bytes_xfered += nbytes; |
| 1436 | |||
| 1437 | if (!remain) { | ||
| 1438 | if (!sg_miter_next(sg_miter)) | ||
| 1439 | goto done; | ||
| 1440 | sg_miter->consumed = 0; | ||
| 1441 | } | ||
| 1442 | sg_miter_stop(sg_miter); | ||
| 1440 | return; | 1443 | return; |
| 1441 | 1444 | ||
| 1442 | done: | 1445 | done: |
| 1443 | data->bytes_xfered += nbytes; | 1446 | data->bytes_xfered += nbytes; |
| 1447 | sg_miter_stop(sg_miter); | ||
| 1448 | host->sg = NULL; | ||
| 1444 | smp_wmb(); | 1449 | smp_wmb(); |
| 1445 | set_bit(EVENT_XFER_COMPLETE, &host->pending_events); | 1450 | set_bit(EVENT_XFER_COMPLETE, &host->pending_events); |
| 1446 | } | 1451 | } |
| @@ -1643,6 +1648,7 @@ static void dw_mci_work_routine_card(struct work_struct *work) | |||
| 1643 | * block interrupt, hence setting the | 1648 | * block interrupt, hence setting the |
| 1644 | * scatter-gather pointer to NULL. | 1649 | * scatter-gather pointer to NULL. |
| 1645 | */ | 1650 | */ |
| 1651 | sg_miter_stop(&host->sg_miter); | ||
| 1646 | host->sg = NULL; | 1652 | host->sg = NULL; |
| 1647 | 1653 | ||
| 1648 | ctrl = mci_readl(host, CTRL); | 1654 | ctrl = mci_readl(host, CTRL); |
diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c index ab66f2454dc4..1534b582c419 100644 --- a/drivers/mmc/host/of_mmc_spi.c +++ b/drivers/mmc/host/of_mmc_spi.c | |||
| @@ -113,8 +113,8 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi) | |||
| 113 | const int j = i * 2; | 113 | const int j = i * 2; |
| 114 | u32 mask; | 114 | u32 mask; |
| 115 | 115 | ||
| 116 | mask = mmc_vddrange_to_ocrmask(voltage_ranges[j], | 116 | mask = mmc_vddrange_to_ocrmask(be32_to_cpu(voltage_ranges[j]), |
| 117 | voltage_ranges[j + 1]); | 117 | be32_to_cpu(voltage_ranges[j + 1])); |
| 118 | if (!mask) { | 118 | if (!mask) { |
| 119 | ret = -EINVAL; | 119 | ret = -EINVAL; |
| 120 | dev_err(dev, "OF: voltage-range #%d is invalid\n", i); | 120 | dev_err(dev, "OF: voltage-range #%d is invalid\n", i); |
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index ff4adc018041..5d876ff86f37 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c | |||
| @@ -38,6 +38,23 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg) | |||
| 38 | int base = reg & ~0x3; | 38 | int base = reg & ~0x3; |
| 39 | int shift = (reg & 0x3) * 8; | 39 | int shift = (reg & 0x3) * 8; |
| 40 | u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff; | 40 | u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff; |
| 41 | |||
| 42 | /* | ||
| 43 | * "DMA select" locates at offset 0x28 in SD specification, but on | ||
| 44 | * P5020 or P3041, it locates at 0x29. | ||
| 45 | */ | ||
| 46 | if (reg == SDHCI_HOST_CONTROL) { | ||
| 47 | u32 dma_bits; | ||
| 48 | |||
| 49 | dma_bits = in_be32(host->ioaddr + reg); | ||
| 50 | /* DMA select is 22,23 bits in Protocol Control Register */ | ||
| 51 | dma_bits = (dma_bits >> 5) & SDHCI_CTRL_DMA_MASK; | ||
| 52 | |||
| 53 | /* fixup the result */ | ||
| 54 | ret &= ~SDHCI_CTRL_DMA_MASK; | ||
| 55 | ret |= dma_bits; | ||
| 56 | } | ||
| 57 | |||
| 41 | return ret; | 58 | return ret; |
| 42 | } | 59 | } |
| 43 | 60 | ||
| @@ -56,6 +73,21 @@ static void esdhc_writew(struct sdhci_host *host, u16 val, int reg) | |||
| 56 | 73 | ||
| 57 | static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg) | 74 | static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg) |
| 58 | { | 75 | { |
| 76 | /* | ||
| 77 | * "DMA select" location is offset 0x28 in SD specification, but on | ||
| 78 | * P5020 or P3041, it's located at 0x29. | ||
| 79 | */ | ||
| 80 | if (reg == SDHCI_HOST_CONTROL) { | ||
| 81 | u32 dma_bits; | ||
| 82 | |||
| 83 | /* DMA select is 22,23 bits in Protocol Control Register */ | ||
| 84 | dma_bits = (val & SDHCI_CTRL_DMA_MASK) << 5; | ||
| 85 | clrsetbits_be32(host->ioaddr + reg , SDHCI_CTRL_DMA_MASK << 5, | ||
| 86 | dma_bits); | ||
| 87 | val &= ~SDHCI_CTRL_DMA_MASK; | ||
| 88 | val |= in_be32(host->ioaddr + reg) & SDHCI_CTRL_DMA_MASK; | ||
| 89 | } | ||
| 90 | |||
| 59 | /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */ | 91 | /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */ |
| 60 | if (reg == SDHCI_HOST_CONTROL) | 92 | if (reg == SDHCI_HOST_CONTROL) |
| 61 | val &= ~ESDHC_HOST_CONTROL_RES; | 93 | val &= ~ESDHC_HOST_CONTROL_RES; |
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 7165e6a09274..6ebdc4010e7c 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c | |||
| @@ -250,7 +250,7 @@ static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) | |||
| 250 | 250 | ||
| 251 | static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot) | 251 | static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot) |
| 252 | { | 252 | { |
| 253 | slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD; | 253 | slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE; |
| 254 | return 0; | 254 | return 0; |
| 255 | } | 255 | } |
| 256 | 256 | ||
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 03970bcb3495..c5c2a48bdd94 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * sdhci-pltfm.c Support for SDHCI platform devices | 2 | * sdhci-pltfm.c Support for SDHCI platform devices |
| 3 | * Copyright (c) 2009 Intel Corporation | 3 | * Copyright (c) 2009 Intel Corporation |
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2007 Freescale Semiconductor, Inc. | 5 | * Copyright (c) 2007, 2011 Freescale Semiconductor, Inc. |
| 6 | * Copyright (c) 2009 MontaVista Software, Inc. | 6 | * Copyright (c) 2009 MontaVista Software, Inc. |
| 7 | * | 7 | * |
| 8 | * Authors: Xiaobo Xie <X.Xie@freescale.com> | 8 | * Authors: Xiaobo Xie <X.Xie@freescale.com> |
| @@ -71,6 +71,14 @@ void sdhci_get_of_property(struct platform_device *pdev) | |||
| 71 | if (sdhci_of_wp_inverted(np)) | 71 | if (sdhci_of_wp_inverted(np)) |
| 72 | host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; | 72 | host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; |
| 73 | 73 | ||
| 74 | if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc")) | ||
| 75 | host->quirks |= SDHCI_QUIRK_BROKEN_DMA; | ||
| 76 | |||
| 77 | if (of_device_is_compatible(np, "fsl,p2020-esdhc") || | ||
| 78 | of_device_is_compatible(np, "fsl,p1010-esdhc") || | ||
| 79 | of_device_is_compatible(np, "fsl,mpc8536-esdhc")) | ||
| 80 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; | ||
| 81 | |||
| 74 | clk = of_get_property(np, "clock-frequency", &size); | 82 | clk = of_get_property(np, "clock-frequency", &size); |
| 75 | if (clk && size == sizeof(*clk) && *clk) | 83 | if (clk && size == sizeof(*clk) && *clk) |
| 76 | pltfm_host->clock = be32_to_cpup(clk); | 84 | pltfm_host->clock = be32_to_cpup(clk); |
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index f5d8b53be333..352d4797865b 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c | |||
| @@ -1327,7 +1327,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) | |||
| 1327 | if (ret < 0) | 1327 | if (ret < 0) |
| 1328 | goto clean_up2; | 1328 | goto clean_up2; |
| 1329 | 1329 | ||
| 1330 | mmc_add_host(mmc); | 1330 | INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work); |
| 1331 | 1331 | ||
| 1332 | sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); | 1332 | sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); |
| 1333 | 1333 | ||
| @@ -1338,22 +1338,24 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) | |||
| 1338 | } | 1338 | } |
| 1339 | ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host); | 1339 | ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host); |
| 1340 | if (ret) { | 1340 | if (ret) { |
| 1341 | free_irq(irq[0], host); | ||
| 1342 | dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n"); | 1341 | dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n"); |
| 1343 | goto clean_up3; | 1342 | goto clean_up4; |
| 1344 | } | 1343 | } |
| 1345 | 1344 | ||
| 1346 | INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work); | 1345 | ret = mmc_add_host(mmc); |
| 1347 | 1346 | if (ret < 0) | |
| 1348 | mmc_detect_change(host->mmc, 0); | 1347 | goto clean_up5; |
| 1349 | 1348 | ||
| 1350 | dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION); | 1349 | dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION); |
| 1351 | dev_dbg(&pdev->dev, "chip ver H'%04x\n", | 1350 | dev_dbg(&pdev->dev, "chip ver H'%04x\n", |
| 1352 | sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); | 1351 | sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); |
| 1353 | return ret; | 1352 | return ret; |
| 1354 | 1353 | ||
| 1354 | clean_up5: | ||
| 1355 | free_irq(irq[1], host); | ||
| 1356 | clean_up4: | ||
| 1357 | free_irq(irq[0], host); | ||
| 1355 | clean_up3: | 1358 | clean_up3: |
| 1356 | mmc_remove_host(mmc); | ||
| 1357 | pm_runtime_suspend(&pdev->dev); | 1359 | pm_runtime_suspend(&pdev->dev); |
| 1358 | clean_up2: | 1360 | clean_up2: |
| 1359 | pm_runtime_disable(&pdev->dev); | 1361 | pm_runtime_disable(&pdev->dev); |
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index a95e6d901726..f96c536d130a 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h | |||
| @@ -20,8 +20,8 @@ | |||
| 20 | #include <linux/mmc/tmio.h> | 20 | #include <linux/mmc/tmio.h> |
| 21 | #include <linux/mutex.h> | 21 | #include <linux/mutex.h> |
| 22 | #include <linux/pagemap.h> | 22 | #include <linux/pagemap.h> |
| 23 | #include <linux/spinlock.h> | ||
| 24 | #include <linux/scatterlist.h> | 23 | #include <linux/scatterlist.h> |
| 24 | #include <linux/spinlock.h> | ||
| 25 | 25 | ||
| 26 | /* Definitions for values the CTRL_SDIO_STATUS register can take. */ | 26 | /* Definitions for values the CTRL_SDIO_STATUS register can take. */ |
| 27 | #define TMIO_SDIO_STAT_IOIRQ 0x0001 | 27 | #define TMIO_SDIO_STAT_IOIRQ 0x0001 |
| @@ -120,6 +120,7 @@ void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data); | |||
| 120 | void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable); | 120 | void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable); |
| 121 | void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); | 121 | void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); |
| 122 | void tmio_mmc_release_dma(struct tmio_mmc_host *host); | 122 | void tmio_mmc_release_dma(struct tmio_mmc_host *host); |
| 123 | void tmio_mmc_abort_dma(struct tmio_mmc_host *host); | ||
| 123 | #else | 124 | #else |
| 124 | static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host, | 125 | static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host, |
| 125 | struct mmc_data *data) | 126 | struct mmc_data *data) |
| @@ -140,6 +141,10 @@ static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host, | |||
| 140 | static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host) | 141 | static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host) |
| 141 | { | 142 | { |
| 142 | } | 143 | } |
| 144 | |||
| 145 | static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host) | ||
| 146 | { | ||
| 147 | } | ||
| 143 | #endif | 148 | #endif |
| 144 | 149 | ||
| 145 | #ifdef CONFIG_PM | 150 | #ifdef CONFIG_PM |
diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c index 7a6e6cc8f8b8..8253ec12003e 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/tmio_mmc_dma.c | |||
| @@ -34,6 +34,18 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) | |||
| 34 | #endif | 34 | #endif |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | void tmio_mmc_abort_dma(struct tmio_mmc_host *host) | ||
| 38 | { | ||
| 39 | tmio_mmc_enable_dma(host, false); | ||
| 40 | |||
| 41 | if (host->chan_rx) | ||
| 42 | dmaengine_terminate_all(host->chan_rx); | ||
| 43 | if (host->chan_tx) | ||
| 44 | dmaengine_terminate_all(host->chan_tx); | ||
| 45 | |||
| 46 | tmio_mmc_enable_dma(host, true); | ||
| 47 | } | ||
| 48 | |||
| 37 | static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) | 49 | static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) |
| 38 | { | 50 | { |
| 39 | struct scatterlist *sg = host->sg_ptr, *sg_tmp; | 51 | struct scatterlist *sg = host->sg_ptr, *sg_tmp; |
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index abad01b37cfb..5f9ad74fbf80 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c | |||
| @@ -41,8 +41,8 @@ | |||
| 41 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
| 42 | #include <linux/pm_runtime.h> | 42 | #include <linux/pm_runtime.h> |
| 43 | #include <linux/scatterlist.h> | 43 | #include <linux/scatterlist.h> |
| 44 | #include <linux/workqueue.h> | ||
| 45 | #include <linux/spinlock.h> | 44 | #include <linux/spinlock.h> |
| 45 | #include <linux/workqueue.h> | ||
| 46 | 46 | ||
| 47 | #include "tmio_mmc.h" | 47 | #include "tmio_mmc.h" |
| 48 | 48 | ||
| @@ -246,6 +246,7 @@ static void tmio_mmc_reset_work(struct work_struct *work) | |||
| 246 | /* Ready for new calls */ | 246 | /* Ready for new calls */ |
| 247 | host->mrq = NULL; | 247 | host->mrq = NULL; |
| 248 | 248 | ||
| 249 | tmio_mmc_abort_dma(host); | ||
| 249 | mmc_request_done(host->mmc, mrq); | 250 | mmc_request_done(host->mmc, mrq); |
| 250 | } | 251 | } |
| 251 | 252 | ||
| @@ -272,6 +273,9 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host) | |||
| 272 | host->mrq = NULL; | 273 | host->mrq = NULL; |
| 273 | spin_unlock_irqrestore(&host->lock, flags); | 274 | spin_unlock_irqrestore(&host->lock, flags); |
| 274 | 275 | ||
| 276 | if (mrq->cmd->error || (mrq->data && mrq->data->error)) | ||
| 277 | tmio_mmc_abort_dma(host); | ||
| 278 | |||
| 275 | mmc_request_done(host->mmc, mrq); | 279 | mmc_request_done(host->mmc, mrq); |
| 276 | } | 280 | } |
| 277 | 281 | ||
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 9f22ba572de0..19a41d1737af 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h | |||
| @@ -217,6 +217,7 @@ struct mmc_card { | |||
| 217 | #define MMC_CARD_SDXC (1<<6) /* card is SDXC */ | 217 | #define MMC_CARD_SDXC (1<<6) /* card is SDXC */ |
| 218 | #define MMC_CARD_REMOVED (1<<7) /* card has been removed */ | 218 | #define MMC_CARD_REMOVED (1<<7) /* card has been removed */ |
| 219 | #define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */ | 219 | #define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */ |
| 220 | #define MMC_STATE_SLEEP (1<<9) /* card is in sleep state */ | ||
| 220 | unsigned int quirks; /* card quirks */ | 221 | unsigned int quirks; /* card quirks */ |
| 221 | #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ | 222 | #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ |
| 222 | #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */ | 223 | #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */ |
| @@ -382,6 +383,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) | |||
| 382 | #define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) | 383 | #define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) |
| 383 | #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) | 384 | #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) |
| 384 | #define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) | 385 | #define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) |
| 386 | #define mmc_card_is_sleep(c) ((c)->state & MMC_STATE_SLEEP) | ||
| 385 | 387 | ||
| 386 | #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) | 388 | #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) |
| 387 | #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) | 389 | #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) |
| @@ -393,7 +395,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) | |||
| 393 | #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED) | 395 | #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED) |
| 394 | #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) | 396 | #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) |
| 395 | #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) | 397 | #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) |
| 398 | #define mmc_card_set_sleep(c) ((c)->state |= MMC_STATE_SLEEP) | ||
| 396 | 399 | ||
| 400 | #define mmc_card_clr_sleep(c) ((c)->state &= ~MMC_STATE_SLEEP) | ||
| 397 | /* | 401 | /* |
| 398 | * Quirk add/remove for MMC products. | 402 | * Quirk add/remove for MMC products. |
| 399 | */ | 403 | */ |
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index e8779c6d1759..aae5d1f1bb39 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | #ifndef LINUX_MMC_DW_MMC_H | 14 | #ifndef LINUX_MMC_DW_MMC_H |
| 15 | #define LINUX_MMC_DW_MMC_H | 15 | #define LINUX_MMC_DW_MMC_H |
| 16 | 16 | ||
| 17 | #include <linux/scatterlist.h> | ||
| 18 | |||
| 17 | #define MAX_MCI_SLOTS 2 | 19 | #define MAX_MCI_SLOTS 2 |
| 18 | 20 | ||
| 19 | enum dw_mci_state { | 21 | enum dw_mci_state { |
| @@ -40,7 +42,7 @@ struct mmc_data; | |||
| 40 | * @lock: Spinlock protecting the queue and associated data. | 42 | * @lock: Spinlock protecting the queue and associated data. |
| 41 | * @regs: Pointer to MMIO registers. | 43 | * @regs: Pointer to MMIO registers. |
| 42 | * @sg: Scatterlist entry currently being processed by PIO code, if any. | 44 | * @sg: Scatterlist entry currently being processed by PIO code, if any. |
| 43 | * @pio_offset: Offset into the current scatterlist entry. | 45 | * @sg_miter: PIO mapping scatterlist iterator. |
| 44 | * @cur_slot: The slot which is currently using the controller. | 46 | * @cur_slot: The slot which is currently using the controller. |
| 45 | * @mrq: The request currently being processed on @cur_slot, | 47 | * @mrq: The request currently being processed on @cur_slot, |
| 46 | * or NULL if the controller is idle. | 48 | * or NULL if the controller is idle. |
| @@ -115,7 +117,7 @@ struct dw_mci { | |||
| 115 | void __iomem *regs; | 117 | void __iomem *regs; |
| 116 | 118 | ||
| 117 | struct scatterlist *sg; | 119 | struct scatterlist *sg; |
| 118 | unsigned int pio_offset; | 120 | struct sg_mapping_iter sg_miter; |
| 119 | 121 | ||
| 120 | struct dw_mci_slot *cur_slot; | 122 | struct dw_mci_slot *cur_slot; |
| 121 | struct mmc_request *mrq; | 123 | struct mmc_request *mrq; |
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 0beba1e5e1ed..ee2b0363c040 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h | |||
| @@ -257,6 +257,7 @@ struct mmc_host { | |||
| 257 | #define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */ | 257 | #define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */ |
| 258 | #define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \ | 258 | #define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \ |
| 259 | MMC_CAP2_HS200_1_2V_SDR) | 259 | MMC_CAP2_HS200_1_2V_SDR) |
| 260 | #define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */ | ||
| 260 | 261 | ||
| 261 | mmc_pm_flag_t pm_caps; /* supported pm features */ | 262 | mmc_pm_flag_t pm_caps; /* supported pm features */ |
| 262 | unsigned int power_notify_type; | 263 | unsigned int power_notify_type; |
| @@ -444,4 +445,23 @@ static inline int mmc_boot_partition_access(struct mmc_host *host) | |||
| 444 | return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC); | 445 | return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC); |
| 445 | } | 446 | } |
| 446 | 447 | ||
| 448 | #ifdef CONFIG_MMC_CLKGATE | ||
| 449 | void mmc_host_clk_hold(struct mmc_host *host); | ||
| 450 | void mmc_host_clk_release(struct mmc_host *host); | ||
| 451 | unsigned int mmc_host_clk_rate(struct mmc_host *host); | ||
| 452 | |||
| 453 | #else | ||
| 454 | static inline void mmc_host_clk_hold(struct mmc_host *host) | ||
| 455 | { | ||
| 456 | } | ||
| 457 | |||
| 458 | static inline void mmc_host_clk_release(struct mmc_host *host) | ||
| 459 | { | ||
| 460 | } | ||
| 461 | |||
| 462 | static inline unsigned int mmc_host_clk_rate(struct mmc_host *host) | ||
| 463 | { | ||
| 464 | return host->ios.clock; | ||
| 465 | } | ||
| 466 | #endif | ||
| 447 | #endif /* LINUX_MMC_HOST_H */ | 467 | #endif /* LINUX_MMC_HOST_H */ |
