diff options
Diffstat (limited to 'drivers/mmc/core/core.c')
-rw-r--r-- | drivers/mmc/core/core.c | 179 |
1 files changed, 116 insertions, 63 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 09eee6df0653..8f86d702e46e 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -58,6 +58,7 @@ int mmc_assume_removable; | |||
58 | #else | 58 | #else |
59 | int mmc_assume_removable = 1; | 59 | int mmc_assume_removable = 1; |
60 | #endif | 60 | #endif |
61 | EXPORT_SYMBOL(mmc_assume_removable); | ||
61 | module_param_named(removable, mmc_assume_removable, bool, 0644); | 62 | module_param_named(removable, mmc_assume_removable, bool, 0644); |
62 | MODULE_PARM_DESC( | 63 | MODULE_PARM_DESC( |
63 | removable, | 64 | removable, |
@@ -650,14 +651,24 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode) | |||
650 | } | 651 | } |
651 | 652 | ||
652 | /* | 653 | /* |
653 | * Change data bus width of a host. | 654 | * Change data bus width and DDR mode of a host. |
654 | */ | 655 | */ |
655 | void mmc_set_bus_width(struct mmc_host *host, unsigned int width) | 656 | void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width, |
657 | unsigned int ddr) | ||
656 | { | 658 | { |
657 | host->ios.bus_width = width; | 659 | host->ios.bus_width = width; |
660 | host->ios.ddr = ddr; | ||
658 | mmc_set_ios(host); | 661 | mmc_set_ios(host); |
659 | } | 662 | } |
660 | 663 | ||
664 | /* | ||
665 | * Change data bus width of a host. | ||
666 | */ | ||
667 | void mmc_set_bus_width(struct mmc_host *host, unsigned int width) | ||
668 | { | ||
669 | mmc_set_bus_width_ddr(host, width, MMC_SDR_MODE); | ||
670 | } | ||
671 | |||
661 | /** | 672 | /** |
662 | * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number | 673 | * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number |
663 | * @vdd: voltage (mV) | 674 | * @vdd: voltage (mV) |
@@ -771,8 +782,9 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask); | |||
771 | 782 | ||
772 | /** | 783 | /** |
773 | * mmc_regulator_set_ocr - set regulator to match host->ios voltage | 784 | * mmc_regulator_set_ocr - set regulator to match host->ios voltage |
774 | * @vdd_bit: zero for power off, else a bit number (host->ios.vdd) | 785 | * @mmc: the host to regulate |
775 | * @supply: regulator to use | 786 | * @supply: regulator to use |
787 | * @vdd_bit: zero for power off, else a bit number (host->ios.vdd) | ||
776 | * | 788 | * |
777 | * Returns zero on success, else negative errno. | 789 | * Returns zero on success, else negative errno. |
778 | * | 790 | * |
@@ -780,15 +792,12 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask); | |||
780 | * a particular supply voltage. This would normally be called from the | 792 | * a particular supply voltage. This would normally be called from the |
781 | * set_ios() method. | 793 | * set_ios() method. |
782 | */ | 794 | */ |
783 | int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit) | 795 | int mmc_regulator_set_ocr(struct mmc_host *mmc, |
796 | struct regulator *supply, | ||
797 | unsigned short vdd_bit) | ||
784 | { | 798 | { |
785 | int result = 0; | 799 | int result = 0; |
786 | int min_uV, max_uV; | 800 | int min_uV, max_uV; |
787 | int enabled; | ||
788 | |||
789 | enabled = regulator_is_enabled(supply); | ||
790 | if (enabled < 0) | ||
791 | return enabled; | ||
792 | 801 | ||
793 | if (vdd_bit) { | 802 | if (vdd_bit) { |
794 | int tmp; | 803 | int tmp; |
@@ -819,17 +828,25 @@ int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit) | |||
819 | else | 828 | else |
820 | result = 0; | 829 | result = 0; |
821 | 830 | ||
822 | if (result == 0 && !enabled) | 831 | if (result == 0 && !mmc->regulator_enabled) { |
823 | result = regulator_enable(supply); | 832 | result = regulator_enable(supply); |
824 | } else if (enabled) { | 833 | if (!result) |
834 | mmc->regulator_enabled = true; | ||
835 | } | ||
836 | } else if (mmc->regulator_enabled) { | ||
825 | result = regulator_disable(supply); | 837 | result = regulator_disable(supply); |
838 | if (result == 0) | ||
839 | mmc->regulator_enabled = false; | ||
826 | } | 840 | } |
827 | 841 | ||
842 | if (result) | ||
843 | dev_err(mmc_dev(mmc), | ||
844 | "could not set regulator OCR (%d)\n", result); | ||
828 | return result; | 845 | return result; |
829 | } | 846 | } |
830 | EXPORT_SYMBOL(mmc_regulator_set_ocr); | 847 | EXPORT_SYMBOL(mmc_regulator_set_ocr); |
831 | 848 | ||
832 | #endif | 849 | #endif /* CONFIG_REGULATOR */ |
833 | 850 | ||
834 | /* | 851 | /* |
835 | * Mask off any voltages we don't support and select | 852 | * Mask off any voltages we don't support and select |
@@ -907,12 +924,7 @@ static void mmc_power_up(struct mmc_host *host) | |||
907 | */ | 924 | */ |
908 | mmc_delay(10); | 925 | mmc_delay(10); |
909 | 926 | ||
910 | if (host->f_min > 400000) { | 927 | host->ios.clock = host->f_init; |
911 | pr_warning("%s: Minimum clock frequency too high for " | ||
912 | "identification mode\n", mmc_hostname(host)); | ||
913 | host->ios.clock = host->f_min; | ||
914 | } else | ||
915 | host->ios.clock = 400000; | ||
916 | 928 | ||
917 | host->ios.power_mode = MMC_POWER_ON; | 929 | host->ios.power_mode = MMC_POWER_ON; |
918 | mmc_set_ios(host); | 930 | mmc_set_ios(host); |
@@ -1397,6 +1409,21 @@ int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, | |||
1397 | } | 1409 | } |
1398 | EXPORT_SYMBOL(mmc_erase_group_aligned); | 1410 | EXPORT_SYMBOL(mmc_erase_group_aligned); |
1399 | 1411 | ||
1412 | int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) | ||
1413 | { | ||
1414 | struct mmc_command cmd; | ||
1415 | |||
1416 | if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card)) | ||
1417 | return 0; | ||
1418 | |||
1419 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
1420 | cmd.opcode = MMC_SET_BLOCKLEN; | ||
1421 | cmd.arg = blocklen; | ||
1422 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; | ||
1423 | return mmc_wait_for_cmd(card->host, &cmd, 5); | ||
1424 | } | ||
1425 | EXPORT_SYMBOL(mmc_set_blocklen); | ||
1426 | |||
1400 | void mmc_rescan(struct work_struct *work) | 1427 | void mmc_rescan(struct work_struct *work) |
1401 | { | 1428 | { |
1402 | struct mmc_host *host = | 1429 | struct mmc_host *host = |
@@ -1404,6 +1431,8 @@ void mmc_rescan(struct work_struct *work) | |||
1404 | u32 ocr; | 1431 | u32 ocr; |
1405 | int err; | 1432 | int err; |
1406 | unsigned long flags; | 1433 | unsigned long flags; |
1434 | int i; | ||
1435 | const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; | ||
1407 | 1436 | ||
1408 | spin_lock_irqsave(&host->lock, flags); | 1437 | spin_lock_irqsave(&host->lock, flags); |
1409 | 1438 | ||
@@ -1443,55 +1472,71 @@ void mmc_rescan(struct work_struct *work) | |||
1443 | if (host->ops->get_cd && host->ops->get_cd(host) == 0) | 1472 | if (host->ops->get_cd && host->ops->get_cd(host) == 0) |
1444 | goto out; | 1473 | goto out; |
1445 | 1474 | ||
1446 | mmc_claim_host(host); | 1475 | for (i = 0; i < ARRAY_SIZE(freqs); i++) { |
1476 | mmc_claim_host(host); | ||
1447 | 1477 | ||
1448 | mmc_power_up(host); | 1478 | if (freqs[i] >= host->f_min) |
1449 | sdio_reset(host); | 1479 | host->f_init = freqs[i]; |
1450 | mmc_go_idle(host); | 1480 | else if (!i || freqs[i-1] > host->f_min) |
1481 | host->f_init = host->f_min; | ||
1482 | else { | ||
1483 | mmc_release_host(host); | ||
1484 | goto out; | ||
1485 | } | ||
1486 | #ifdef CONFIG_MMC_DEBUG | ||
1487 | pr_info("%s: %s: trying to init card at %u Hz\n", | ||
1488 | mmc_hostname(host), __func__, host->f_init); | ||
1489 | #endif | ||
1490 | mmc_power_up(host); | ||
1491 | sdio_reset(host); | ||
1492 | mmc_go_idle(host); | ||
1451 | 1493 | ||
1452 | mmc_send_if_cond(host, host->ocr_avail); | 1494 | mmc_send_if_cond(host, host->ocr_avail); |
1453 | 1495 | ||
1454 | /* | 1496 | /* |
1455 | * First we search for SDIO... | 1497 | * First we search for SDIO... |
1456 | */ | 1498 | */ |
1457 | err = mmc_send_io_op_cond(host, 0, &ocr); | 1499 | err = mmc_send_io_op_cond(host, 0, &ocr); |
1458 | if (!err) { | 1500 | if (!err) { |
1459 | if (mmc_attach_sdio(host, ocr)) { | 1501 | if (mmc_attach_sdio(host, ocr)) { |
1460 | mmc_claim_host(host); | 1502 | mmc_claim_host(host); |
1461 | /* try SDMEM (but not MMC) even if SDIO is broken */ | 1503 | /* |
1462 | if (mmc_send_app_op_cond(host, 0, &ocr)) | 1504 | * Try SDMEM (but not MMC) even if SDIO |
1463 | goto out_fail; | 1505 | * is broken. |
1506 | */ | ||
1507 | if (mmc_send_app_op_cond(host, 0, &ocr)) | ||
1508 | goto out_fail; | ||
1509 | |||
1510 | if (mmc_attach_sd(host, ocr)) | ||
1511 | mmc_power_off(host); | ||
1512 | } | ||
1513 | goto out; | ||
1514 | } | ||
1464 | 1515 | ||
1516 | /* | ||
1517 | * ...then normal SD... | ||
1518 | */ | ||
1519 | err = mmc_send_app_op_cond(host, 0, &ocr); | ||
1520 | if (!err) { | ||
1465 | if (mmc_attach_sd(host, ocr)) | 1521 | if (mmc_attach_sd(host, ocr)) |
1466 | mmc_power_off(host); | 1522 | mmc_power_off(host); |
1523 | goto out; | ||
1467 | } | 1524 | } |
1468 | goto out; | ||
1469 | } | ||
1470 | 1525 | ||
1471 | /* | 1526 | /* |
1472 | * ...then normal SD... | 1527 | * ...and finally MMC. |
1473 | */ | 1528 | */ |
1474 | err = mmc_send_app_op_cond(host, 0, &ocr); | 1529 | err = mmc_send_op_cond(host, 0, &ocr); |
1475 | if (!err) { | 1530 | if (!err) { |
1476 | if (mmc_attach_sd(host, ocr)) | 1531 | if (mmc_attach_mmc(host, ocr)) |
1477 | mmc_power_off(host); | 1532 | mmc_power_off(host); |
1478 | goto out; | 1533 | goto out; |
1479 | } | 1534 | } |
1480 | |||
1481 | /* | ||
1482 | * ...and finally MMC. | ||
1483 | */ | ||
1484 | err = mmc_send_op_cond(host, 0, &ocr); | ||
1485 | if (!err) { | ||
1486 | if (mmc_attach_mmc(host, ocr)) | ||
1487 | mmc_power_off(host); | ||
1488 | goto out; | ||
1489 | } | ||
1490 | 1535 | ||
1491 | out_fail: | 1536 | out_fail: |
1492 | mmc_release_host(host); | 1537 | mmc_release_host(host); |
1493 | mmc_power_off(host); | 1538 | mmc_power_off(host); |
1494 | 1539 | } | |
1495 | out: | 1540 | out: |
1496 | if (host->caps & MMC_CAP_NEEDS_POLL) | 1541 | if (host->caps & MMC_CAP_NEEDS_POLL) |
1497 | mmc_schedule_delayed_work(&host->detect, HZ); | 1542 | mmc_schedule_delayed_work(&host->detect, HZ); |
@@ -1538,37 +1583,45 @@ void mmc_stop_host(struct mmc_host *host) | |||
1538 | mmc_power_off(host); | 1583 | mmc_power_off(host); |
1539 | } | 1584 | } |
1540 | 1585 | ||
1541 | void mmc_power_save_host(struct mmc_host *host) | 1586 | int mmc_power_save_host(struct mmc_host *host) |
1542 | { | 1587 | { |
1588 | int ret = 0; | ||
1589 | |||
1543 | mmc_bus_get(host); | 1590 | mmc_bus_get(host); |
1544 | 1591 | ||
1545 | if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { | 1592 | if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { |
1546 | mmc_bus_put(host); | 1593 | mmc_bus_put(host); |
1547 | return; | 1594 | return -EINVAL; |
1548 | } | 1595 | } |
1549 | 1596 | ||
1550 | if (host->bus_ops->power_save) | 1597 | if (host->bus_ops->power_save) |
1551 | host->bus_ops->power_save(host); | 1598 | ret = host->bus_ops->power_save(host); |
1552 | 1599 | ||
1553 | mmc_bus_put(host); | 1600 | mmc_bus_put(host); |
1554 | 1601 | ||
1555 | mmc_power_off(host); | 1602 | mmc_power_off(host); |
1603 | |||
1604 | return ret; | ||
1556 | } | 1605 | } |
1557 | EXPORT_SYMBOL(mmc_power_save_host); | 1606 | EXPORT_SYMBOL(mmc_power_save_host); |
1558 | 1607 | ||
1559 | void mmc_power_restore_host(struct mmc_host *host) | 1608 | int mmc_power_restore_host(struct mmc_host *host) |
1560 | { | 1609 | { |
1610 | int ret; | ||
1611 | |||
1561 | mmc_bus_get(host); | 1612 | mmc_bus_get(host); |
1562 | 1613 | ||
1563 | if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { | 1614 | if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { |
1564 | mmc_bus_put(host); | 1615 | mmc_bus_put(host); |
1565 | return; | 1616 | return -EINVAL; |
1566 | } | 1617 | } |
1567 | 1618 | ||
1568 | mmc_power_up(host); | 1619 | mmc_power_up(host); |
1569 | host->bus_ops->power_restore(host); | 1620 | ret = host->bus_ops->power_restore(host); |
1570 | 1621 | ||
1571 | mmc_bus_put(host); | 1622 | mmc_bus_put(host); |
1623 | |||
1624 | return ret; | ||
1572 | } | 1625 | } |
1573 | EXPORT_SYMBOL(mmc_power_restore_host); | 1626 | EXPORT_SYMBOL(mmc_power_restore_host); |
1574 | 1627 | ||