diff options
author | Andy Ross <andy.ross@windriver.com> | 2011-01-03 13:36:56 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-01-08 23:52:25 -0500 |
commit | 807e8e40673d9628fa7dcdd14423424b4ee5f43b (patch) | |
tree | ca95bdb69d07f0169bbfc5388e15745b9811513e /drivers/mmc/core/core.c | |
parent | 08c82dfad2458f8f9b83126224a85e7ea9e2b046 (diff) |
mmc: Fix sd/sdio/mmc initialization frequency retries
Rewrite and clean up mmc_rescan() to properly retry frequencies lower
than 400kHz. Failures can happen both in sd_send_* calls and
mmc_attach_*. Break out "mmc_rescan_try_freq" from the frequency
selection loop. Symmetrize claim/release logic in mmc_attach_* API,
and move the sd_send_* calls there to make mmc_rescan easier to read.
Signed-off-by: Andy Ross <andy.ross@windriver.com>
Reviewed-and-Tested-by: Hein Tibosch <hein_tibosch@yahoo.es>
Reviewed-by: Chris Ball <cjb@laptop.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/core/core.c')
-rw-r--r-- | drivers/mmc/core/core.c | 119 |
1 files changed, 36 insertions, 83 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 97e0624eb9b6..198f70bad908 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -1485,25 +1485,41 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) | |||
1485 | } | 1485 | } |
1486 | EXPORT_SYMBOL(mmc_set_blocklen); | 1486 | EXPORT_SYMBOL(mmc_set_blocklen); |
1487 | 1487 | ||
1488 | static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) | ||
1489 | { | ||
1490 | host->f_init = freq; | ||
1491 | |||
1492 | #ifdef CONFIG_MMC_DEBUG | ||
1493 | pr_info("%s: %s: trying to init card at %u Hz\n", | ||
1494 | mmc_hostname(host), __func__, host->f_init); | ||
1495 | #endif | ||
1496 | mmc_power_up(host); | ||
1497 | sdio_reset(host); | ||
1498 | mmc_go_idle(host); | ||
1499 | |||
1500 | mmc_send_if_cond(host, host->ocr_avail); | ||
1501 | |||
1502 | /* Order's important: probe SDIO, then SD, then MMC */ | ||
1503 | if (!mmc_attach_sdio(host)) | ||
1504 | return 0; | ||
1505 | if (!mmc_attach_sd(host)) | ||
1506 | return 0; | ||
1507 | if (!mmc_attach_mmc(host)) | ||
1508 | return 0; | ||
1509 | |||
1510 | mmc_power_off(host); | ||
1511 | return -EIO; | ||
1512 | } | ||
1513 | |||
1488 | void mmc_rescan(struct work_struct *work) | 1514 | void mmc_rescan(struct work_struct *work) |
1489 | { | 1515 | { |
1516 | static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; | ||
1490 | struct mmc_host *host = | 1517 | struct mmc_host *host = |
1491 | container_of(work, struct mmc_host, detect.work); | 1518 | container_of(work, struct mmc_host, detect.work); |
1492 | u32 ocr; | ||
1493 | int err; | ||
1494 | unsigned long flags; | ||
1495 | int i; | 1519 | int i; |
1496 | const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; | ||
1497 | |||
1498 | spin_lock_irqsave(&host->lock, flags); | ||
1499 | 1520 | ||
1500 | if (host->rescan_disable) { | 1521 | if (host->rescan_disable) |
1501 | spin_unlock_irqrestore(&host->lock, flags); | ||
1502 | return; | 1522 | return; |
1503 | } | ||
1504 | |||
1505 | spin_unlock_irqrestore(&host->lock, flags); | ||
1506 | |||
1507 | 1523 | ||
1508 | mmc_bus_get(host); | 1524 | mmc_bus_get(host); |
1509 | 1525 | ||
@@ -1526,8 +1542,6 @@ void mmc_rescan(struct work_struct *work) | |||
1526 | goto out; | 1542 | goto out; |
1527 | } | 1543 | } |
1528 | 1544 | ||
1529 | /* detect a newly inserted card */ | ||
1530 | |||
1531 | /* | 1545 | /* |
1532 | * Only we can add a new handler, so it's safe to | 1546 | * Only we can add a new handler, so it's safe to |
1533 | * release the lock here. | 1547 | * release the lock here. |
@@ -1537,77 +1551,16 @@ void mmc_rescan(struct work_struct *work) | |||
1537 | if (host->ops->get_cd && host->ops->get_cd(host) == 0) | 1551 | if (host->ops->get_cd && host->ops->get_cd(host) == 0) |
1538 | goto out; | 1552 | goto out; |
1539 | 1553 | ||
1554 | mmc_claim_host(host); | ||
1540 | for (i = 0; i < ARRAY_SIZE(freqs); i++) { | 1555 | for (i = 0; i < ARRAY_SIZE(freqs); i++) { |
1541 | mmc_claim_host(host); | 1556 | if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) |
1542 | 1557 | break; | |
1543 | if (freqs[i] >= host->f_min) | 1558 | if (freqs[i] < host->f_min) |
1544 | host->f_init = freqs[i]; | 1559 | break; |
1545 | else if (!i || freqs[i-1] > host->f_min) | ||
1546 | host->f_init = host->f_min; | ||
1547 | else { | ||
1548 | mmc_release_host(host); | ||
1549 | goto out; | ||
1550 | } | ||
1551 | #ifdef CONFIG_MMC_DEBUG | ||
1552 | pr_info("%s: %s: trying to init card at %u Hz\n", | ||
1553 | mmc_hostname(host), __func__, host->f_init); | ||
1554 | #endif | ||
1555 | mmc_power_up(host); | ||
1556 | sdio_reset(host); | ||
1557 | mmc_go_idle(host); | ||
1558 | |||
1559 | mmc_send_if_cond(host, host->ocr_avail); | ||
1560 | |||
1561 | /* | ||
1562 | * First we search for SDIO... | ||
1563 | */ | ||
1564 | err = mmc_send_io_op_cond(host, 0, &ocr); | ||
1565 | if (!err) { | ||
1566 | if (mmc_attach_sdio(host, ocr)) { | ||
1567 | mmc_claim_host(host); | ||
1568 | /* | ||
1569 | * Try SDMEM (but not MMC) even if SDIO | ||
1570 | * is broken. | ||
1571 | */ | ||
1572 | mmc_power_up(host); | ||
1573 | sdio_reset(host); | ||
1574 | mmc_go_idle(host); | ||
1575 | mmc_send_if_cond(host, host->ocr_avail); | ||
1576 | |||
1577 | if (mmc_send_app_op_cond(host, 0, &ocr)) | ||
1578 | goto out_fail; | ||
1579 | |||
1580 | if (mmc_attach_sd(host, ocr)) | ||
1581 | mmc_power_off(host); | ||
1582 | } | ||
1583 | goto out; | ||
1584 | } | ||
1585 | |||
1586 | /* | ||
1587 | * ...then normal SD... | ||
1588 | */ | ||
1589 | err = mmc_send_app_op_cond(host, 0, &ocr); | ||
1590 | if (!err) { | ||
1591 | if (mmc_attach_sd(host, ocr)) | ||
1592 | mmc_power_off(host); | ||
1593 | goto out; | ||
1594 | } | ||
1595 | |||
1596 | /* | ||
1597 | * ...and finally MMC. | ||
1598 | */ | ||
1599 | err = mmc_send_op_cond(host, 0, &ocr); | ||
1600 | if (!err) { | ||
1601 | if (mmc_attach_mmc(host, ocr)) | ||
1602 | mmc_power_off(host); | ||
1603 | goto out; | ||
1604 | } | ||
1605 | |||
1606 | out_fail: | ||
1607 | mmc_release_host(host); | ||
1608 | mmc_power_off(host); | ||
1609 | } | 1560 | } |
1610 | out: | 1561 | mmc_release_host(host); |
1562 | |||
1563 | out: | ||
1611 | if (host->caps & MMC_CAP_NEEDS_POLL) | 1564 | if (host->caps & MMC_CAP_NEEDS_POLL) |
1612 | mmc_schedule_delayed_work(&host->detect, HZ); | 1565 | mmc_schedule_delayed_work(&host->detect, HZ); |
1613 | } | 1566 | } |