diff options
author | Ludovic Desroches <ludovic.desroches@atmel.com> | 2012-05-16 09:25:59 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-05-17 08:41:34 -0400 |
commit | f51775471ac6155d3bb8494dcb5c0a13a84f611e (patch) | |
tree | 4d3e837b287c732c867f436df79bfdc559432df9 /drivers/mmc | |
parent | 7a90dcc2d7ceb64bb37044a8d2ee462b936ddf73 (diff) |
mmc: atmel-mci: change the state machine for compatibility with old IP
The state machine use in atmel-mci can't work with old IP versions
(< 0x200). This patch allows to have a common state machine for all
versions in order to remove at91-mci driver only used for old versions.
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/atmel-mci.c | 278 |
1 files changed, 162 insertions, 116 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 6f56ef025ab5..1baaaebbeda8 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c | |||
@@ -45,19 +45,19 @@ | |||
45 | #define ATMCI_DMA_THRESHOLD 16 | 45 | #define ATMCI_DMA_THRESHOLD 16 |
46 | 46 | ||
47 | enum { | 47 | enum { |
48 | EVENT_CMD_COMPLETE = 0, | 48 | EVENT_CMD_RDY = 0, |
49 | EVENT_XFER_COMPLETE, | 49 | EVENT_XFER_COMPLETE, |
50 | EVENT_DATA_COMPLETE, | 50 | EVENT_NOTBUSY, |
51 | EVENT_DATA_ERROR, | 51 | EVENT_DATA_ERROR, |
52 | }; | 52 | }; |
53 | 53 | ||
54 | enum atmel_mci_state { | 54 | enum atmel_mci_state { |
55 | STATE_IDLE = 0, | 55 | STATE_IDLE = 0, |
56 | STATE_SENDING_CMD, | 56 | STATE_SENDING_CMD, |
57 | STATE_SENDING_DATA, | 57 | STATE_DATA_XFER, |
58 | STATE_DATA_BUSY, | 58 | STATE_WAITING_NOTBUSY, |
59 | STATE_SENDING_STOP, | 59 | STATE_SENDING_STOP, |
60 | STATE_DATA_ERROR, | 60 | STATE_END_REQUEST, |
61 | }; | 61 | }; |
62 | 62 | ||
63 | enum atmci_xfer_dir { | 63 | enum atmci_xfer_dir { |
@@ -709,7 +709,6 @@ static void atmci_pdc_complete(struct atmel_mci *host) | |||
709 | if (host->data) { | 709 | if (host->data) { |
710 | atmci_set_pending(host, EVENT_XFER_COMPLETE); | 710 | atmci_set_pending(host, EVENT_XFER_COMPLETE); |
711 | tasklet_schedule(&host->tasklet); | 711 | tasklet_schedule(&host->tasklet); |
712 | atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); | ||
713 | } | 712 | } |
714 | } | 713 | } |
715 | 714 | ||
@@ -835,7 +834,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) | |||
835 | iflags |= ATMCI_ENDRX | ATMCI_RXBUFF; | 834 | iflags |= ATMCI_ENDRX | ATMCI_RXBUFF; |
836 | } else { | 835 | } else { |
837 | dir = DMA_TO_DEVICE; | 836 | dir = DMA_TO_DEVICE; |
838 | iflags |= ATMCI_ENDTX | ATMCI_TXBUFE; | 837 | iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE; |
839 | } | 838 | } |
840 | 839 | ||
841 | /* Set BLKLEN */ | 840 | /* Set BLKLEN */ |
@@ -975,8 +974,7 @@ static void atmci_stop_transfer(struct atmel_mci *host) | |||
975 | */ | 974 | */ |
976 | static void atmci_stop_transfer_pdc(struct atmel_mci *host) | 975 | static void atmci_stop_transfer_pdc(struct atmel_mci *host) |
977 | { | 976 | { |
978 | atmci_set_pending(host, EVENT_XFER_COMPLETE); | 977 | atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); |
979 | atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); | ||
980 | } | 978 | } |
981 | 979 | ||
982 | static void atmci_stop_transfer_dma(struct atmel_mci *host) | 980 | static void atmci_stop_transfer_dma(struct atmel_mci *host) |
@@ -1012,6 +1010,7 @@ static void atmci_start_request(struct atmel_mci *host, | |||
1012 | 1010 | ||
1013 | host->pending_events = 0; | 1011 | host->pending_events = 0; |
1014 | host->completed_events = 0; | 1012 | host->completed_events = 0; |
1013 | host->cmd_status = 0; | ||
1015 | host->data_status = 0; | 1014 | host->data_status = 0; |
1016 | 1015 | ||
1017 | if (host->need_reset) { | 1016 | if (host->need_reset) { |
@@ -1029,7 +1028,7 @@ static void atmci_start_request(struct atmel_mci *host, | |||
1029 | 1028 | ||
1030 | iflags = atmci_readl(host, ATMCI_IMR); | 1029 | iflags = atmci_readl(host, ATMCI_IMR); |
1031 | if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) | 1030 | if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) |
1032 | dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", | 1031 | dev_dbg(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", |
1033 | iflags); | 1032 | iflags); |
1034 | 1033 | ||
1035 | if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) { | 1034 | if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) { |
@@ -1367,19 +1366,6 @@ static void atmci_command_complete(struct atmel_mci *host, | |||
1367 | cmd->error = -EIO; | 1366 | cmd->error = -EIO; |
1368 | else | 1367 | else |
1369 | cmd->error = 0; | 1368 | cmd->error = 0; |
1370 | |||
1371 | if (cmd->error) { | ||
1372 | dev_dbg(&host->pdev->dev, | ||
1373 | "command error: status=0x%08x\n", status); | ||
1374 | |||
1375 | if (cmd->data) { | ||
1376 | host->stop_transfer(host); | ||
1377 | host->data = NULL; | ||
1378 | atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY | ||
1379 | | ATMCI_TXRDY | ATMCI_RXRDY | ||
1380 | | ATMCI_DATA_ERROR_FLAGS); | ||
1381 | } | ||
1382 | } | ||
1383 | } | 1369 | } |
1384 | 1370 | ||
1385 | static void atmci_detect_change(unsigned long data) | 1371 | static void atmci_detect_change(unsigned long data) |
@@ -1442,23 +1428,21 @@ static void atmci_detect_change(unsigned long data) | |||
1442 | break; | 1428 | break; |
1443 | case STATE_SENDING_CMD: | 1429 | case STATE_SENDING_CMD: |
1444 | mrq->cmd->error = -ENOMEDIUM; | 1430 | mrq->cmd->error = -ENOMEDIUM; |
1445 | if (!mrq->data) | 1431 | if (mrq->data) |
1446 | break; | 1432 | host->stop_transfer(host); |
1447 | /* fall through */ | 1433 | break; |
1448 | case STATE_SENDING_DATA: | 1434 | case STATE_DATA_XFER: |
1449 | mrq->data->error = -ENOMEDIUM; | 1435 | mrq->data->error = -ENOMEDIUM; |
1450 | host->stop_transfer(host); | 1436 | host->stop_transfer(host); |
1451 | break; | 1437 | break; |
1452 | case STATE_DATA_BUSY: | 1438 | case STATE_WAITING_NOTBUSY: |
1453 | case STATE_DATA_ERROR: | 1439 | mrq->data->error = -ENOMEDIUM; |
1454 | if (mrq->data->error == -EINPROGRESS) | 1440 | break; |
1455 | mrq->data->error = -ENOMEDIUM; | ||
1456 | if (!mrq->stop) | ||
1457 | break; | ||
1458 | /* fall through */ | ||
1459 | case STATE_SENDING_STOP: | 1441 | case STATE_SENDING_STOP: |
1460 | mrq->stop->error = -ENOMEDIUM; | 1442 | mrq->stop->error = -ENOMEDIUM; |
1461 | break; | 1443 | break; |
1444 | case STATE_END_REQUEST: | ||
1445 | break; | ||
1462 | } | 1446 | } |
1463 | 1447 | ||
1464 | atmci_request_end(host, mrq); | 1448 | atmci_request_end(host, mrq); |
@@ -1486,7 +1470,6 @@ static void atmci_tasklet_func(unsigned long priv) | |||
1486 | struct atmel_mci *host = (struct atmel_mci *)priv; | 1470 | struct atmel_mci *host = (struct atmel_mci *)priv; |
1487 | struct mmc_request *mrq = host->mrq; | 1471 | struct mmc_request *mrq = host->mrq; |
1488 | struct mmc_data *data = host->data; | 1472 | struct mmc_data *data = host->data; |
1489 | struct mmc_command *cmd = host->cmd; | ||
1490 | enum atmel_mci_state state = host->state; | 1473 | enum atmel_mci_state state = host->state; |
1491 | enum atmel_mci_state prev_state; | 1474 | enum atmel_mci_state prev_state; |
1492 | u32 status; | 1475 | u32 status; |
@@ -1508,101 +1491,164 @@ static void atmci_tasklet_func(unsigned long priv) | |||
1508 | break; | 1491 | break; |
1509 | 1492 | ||
1510 | case STATE_SENDING_CMD: | 1493 | case STATE_SENDING_CMD: |
1494 | /* | ||
1495 | * Command has been sent, we are waiting for command | ||
1496 | * ready. Then we have three next states possible: | ||
1497 | * END_REQUEST by default, WAITING_NOTBUSY if it's a | ||
1498 | * command needing it or DATA_XFER if there is data. | ||
1499 | */ | ||
1511 | if (!atmci_test_and_clear_pending(host, | 1500 | if (!atmci_test_and_clear_pending(host, |
1512 | EVENT_CMD_COMPLETE)) | 1501 | EVENT_CMD_RDY)) |
1513 | break; | 1502 | break; |
1514 | 1503 | ||
1515 | host->cmd = NULL; | 1504 | host->cmd = NULL; |
1516 | atmci_set_completed(host, EVENT_CMD_COMPLETE); | 1505 | atmci_set_completed(host, EVENT_CMD_RDY); |
1517 | atmci_command_complete(host, mrq->cmd); | 1506 | atmci_command_complete(host, mrq->cmd); |
1518 | if (!mrq->data || cmd->error) { | 1507 | if (mrq->data) { |
1519 | atmci_request_end(host, host->mrq); | 1508 | /* |
1520 | goto unlock; | 1509 | * If there is a command error don't start |
1521 | } | 1510 | * data transfer. |
1511 | */ | ||
1512 | if (mrq->cmd->error) { | ||
1513 | host->stop_transfer(host); | ||
1514 | host->data = NULL; | ||
1515 | atmci_writel(host, ATMCI_IDR, | ||
1516 | ATMCI_TXRDY | ATMCI_RXRDY | ||
1517 | | ATMCI_DATA_ERROR_FLAGS); | ||
1518 | state = STATE_END_REQUEST; | ||
1519 | } else | ||
1520 | state = STATE_DATA_XFER; | ||
1521 | } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) { | ||
1522 | atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); | ||
1523 | state = STATE_WAITING_NOTBUSY; | ||
1524 | } else | ||
1525 | state = STATE_END_REQUEST; | ||
1522 | 1526 | ||
1523 | prev_state = state = STATE_SENDING_DATA; | 1527 | break; |
1524 | /* fall through */ | ||
1525 | 1528 | ||
1526 | case STATE_SENDING_DATA: | 1529 | case STATE_DATA_XFER: |
1527 | if (atmci_test_and_clear_pending(host, | 1530 | if (atmci_test_and_clear_pending(host, |
1528 | EVENT_DATA_ERROR)) { | 1531 | EVENT_DATA_ERROR)) { |
1529 | host->stop_transfer(host); | 1532 | atmci_set_completed(host, EVENT_DATA_ERROR); |
1530 | if (data->stop) | 1533 | state = STATE_END_REQUEST; |
1531 | atmci_send_stop_cmd(host, data); | ||
1532 | state = STATE_DATA_ERROR; | ||
1533 | break; | 1534 | break; |
1534 | } | 1535 | } |
1535 | 1536 | ||
1537 | /* | ||
1538 | * A data transfer is in progress. The event expected | ||
1539 | * to move to the next state depends of data transfer | ||
1540 | * type (PDC or DMA). Once transfer done we can move | ||
1541 | * to the next step which is WAITING_NOTBUSY in write | ||
1542 | * case and directly SENDING_STOP in read case. | ||
1543 | */ | ||
1536 | if (!atmci_test_and_clear_pending(host, | 1544 | if (!atmci_test_and_clear_pending(host, |
1537 | EVENT_XFER_COMPLETE)) | 1545 | EVENT_XFER_COMPLETE)) |
1538 | break; | 1546 | break; |
1539 | 1547 | ||
1540 | atmci_set_completed(host, EVENT_XFER_COMPLETE); | 1548 | atmci_set_completed(host, EVENT_XFER_COMPLETE); |
1541 | prev_state = state = STATE_DATA_BUSY; | ||
1542 | /* fall through */ | ||
1543 | 1549 | ||
1544 | case STATE_DATA_BUSY: | 1550 | if (host->data->flags & MMC_DATA_WRITE) { |
1545 | if (!atmci_test_and_clear_pending(host, | 1551 | atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); |
1546 | EVENT_DATA_COMPLETE)) | 1552 | state = STATE_WAITING_NOTBUSY; |
1547 | break; | 1553 | } else if (host->mrq->stop) { |
1548 | 1554 | atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); | |
1549 | host->data = NULL; | 1555 | atmci_send_stop_cmd(host, data); |
1550 | atmci_set_completed(host, EVENT_DATA_COMPLETE); | 1556 | state = STATE_SENDING_STOP; |
1551 | status = host->data_status; | ||
1552 | if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) { | ||
1553 | if (status & ATMCI_DTOE) { | ||
1554 | dev_dbg(&host->pdev->dev, | ||
1555 | "data timeout error\n"); | ||
1556 | data->error = -ETIMEDOUT; | ||
1557 | } else if (status & ATMCI_DCRCE) { | ||
1558 | dev_dbg(&host->pdev->dev, | ||
1559 | "data CRC error\n"); | ||
1560 | data->error = -EILSEQ; | ||
1561 | } else { | ||
1562 | dev_dbg(&host->pdev->dev, | ||
1563 | "data FIFO error (status=%08x)\n", | ||
1564 | status); | ||
1565 | data->error = -EIO; | ||
1566 | } | ||
1567 | } else { | 1557 | } else { |
1558 | host->data = NULL; | ||
1568 | data->bytes_xfered = data->blocks * data->blksz; | 1559 | data->bytes_xfered = data->blocks * data->blksz; |
1569 | data->error = 0; | 1560 | data->error = 0; |
1570 | atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS); | 1561 | state = STATE_END_REQUEST; |
1571 | } | 1562 | } |
1563 | break; | ||
1572 | 1564 | ||
1573 | if (!data->stop) { | 1565 | case STATE_WAITING_NOTBUSY: |
1574 | atmci_request_end(host, host->mrq); | 1566 | /* |
1575 | goto unlock; | 1567 | * We can be in the state for two reasons: a command |
1576 | } | 1568 | * requiring waiting not busy signal (stop command |
1569 | * included) or a write operation. In the latest case, | ||
1570 | * we need to send a stop command. | ||
1571 | */ | ||
1572 | if (!atmci_test_and_clear_pending(host, | ||
1573 | EVENT_NOTBUSY)) | ||
1574 | break; | ||
1577 | 1575 | ||
1578 | prev_state = state = STATE_SENDING_STOP; | 1576 | atmci_set_completed(host, EVENT_NOTBUSY); |
1579 | if (!data->error) | 1577 | |
1580 | atmci_send_stop_cmd(host, data); | 1578 | if (host->data) { |
1581 | /* fall through */ | 1579 | /* |
1580 | * For some commands such as CMD53, even if | ||
1581 | * there is data transfer, there is no stop | ||
1582 | * command to send. | ||
1583 | */ | ||
1584 | if (host->mrq->stop) { | ||
1585 | atmci_writel(host, ATMCI_IER, | ||
1586 | ATMCI_CMDRDY); | ||
1587 | atmci_send_stop_cmd(host, data); | ||
1588 | state = STATE_SENDING_STOP; | ||
1589 | } else { | ||
1590 | host->data = NULL; | ||
1591 | data->bytes_xfered = data->blocks | ||
1592 | * data->blksz; | ||
1593 | data->error = 0; | ||
1594 | state = STATE_END_REQUEST; | ||
1595 | } | ||
1596 | } else | ||
1597 | state = STATE_END_REQUEST; | ||
1598 | break; | ||
1582 | 1599 | ||
1583 | case STATE_SENDING_STOP: | 1600 | case STATE_SENDING_STOP: |
1601 | /* | ||
1602 | * In this state, it is important to set host->data to | ||
1603 | * NULL (which is tested in the waiting notbusy state) | ||
1604 | * in order to go to the end request state instead of | ||
1605 | * sending stop again. | ||
1606 | */ | ||
1584 | if (!atmci_test_and_clear_pending(host, | 1607 | if (!atmci_test_and_clear_pending(host, |
1585 | EVENT_CMD_COMPLETE)) | 1608 | EVENT_CMD_RDY)) |
1586 | break; | 1609 | break; |
1587 | 1610 | ||
1588 | host->cmd = NULL; | 1611 | host->cmd = NULL; |
1612 | host->data = NULL; | ||
1613 | data->bytes_xfered = data->blocks * data->blksz; | ||
1614 | data->error = 0; | ||
1589 | atmci_command_complete(host, mrq->stop); | 1615 | atmci_command_complete(host, mrq->stop); |
1590 | atmci_request_end(host, host->mrq); | 1616 | if (mrq->stop->error) { |
1591 | goto unlock; | 1617 | host->stop_transfer(host); |
1618 | atmci_writel(host, ATMCI_IDR, | ||
1619 | ATMCI_TXRDY | ATMCI_RXRDY | ||
1620 | | ATMCI_DATA_ERROR_FLAGS); | ||
1621 | state = STATE_END_REQUEST; | ||
1622 | } else { | ||
1623 | atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); | ||
1624 | state = STATE_WAITING_NOTBUSY; | ||
1625 | } | ||
1626 | break; | ||
1592 | 1627 | ||
1593 | case STATE_DATA_ERROR: | 1628 | case STATE_END_REQUEST: |
1594 | if (!atmci_test_and_clear_pending(host, | 1629 | atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY | ATMCI_RXRDY |
1595 | EVENT_XFER_COMPLETE)) | 1630 | | ATMCI_DATA_ERROR_FLAGS); |
1596 | break; | 1631 | status = host->data_status; |
1632 | if (unlikely(status)) { | ||
1633 | host->stop_transfer(host); | ||
1634 | host->data = NULL; | ||
1635 | if (status & ATMCI_DTOE) { | ||
1636 | data->error = -ETIMEDOUT; | ||
1637 | } else if (status & ATMCI_DCRCE) { | ||
1638 | data->error = -EILSEQ; | ||
1639 | } else { | ||
1640 | data->error = -EIO; | ||
1641 | } | ||
1642 | } | ||
1597 | 1643 | ||
1598 | state = STATE_DATA_BUSY; | 1644 | atmci_request_end(host, host->mrq); |
1645 | state = STATE_IDLE; | ||
1599 | break; | 1646 | break; |
1600 | } | 1647 | } |
1601 | } while (state != prev_state); | 1648 | } while (state != prev_state); |
1602 | 1649 | ||
1603 | host->state = state; | 1650 | host->state = state; |
1604 | 1651 | ||
1605 | unlock: | ||
1606 | spin_unlock(&host->lock); | 1652 | spin_unlock(&host->lock); |
1607 | } | 1653 | } |
1608 | 1654 | ||
@@ -1655,9 +1701,6 @@ static void atmci_read_data_pio(struct atmel_mci *host) | |||
1655 | | ATMCI_DATA_ERROR_FLAGS)); | 1701 | | ATMCI_DATA_ERROR_FLAGS)); |
1656 | host->data_status = status; | 1702 | host->data_status = status; |
1657 | data->bytes_xfered += nbytes; | 1703 | data->bytes_xfered += nbytes; |
1658 | smp_wmb(); | ||
1659 | atmci_set_pending(host, EVENT_DATA_ERROR); | ||
1660 | tasklet_schedule(&host->tasklet); | ||
1661 | return; | 1704 | return; |
1662 | } | 1705 | } |
1663 | } while (status & ATMCI_RXRDY); | 1706 | } while (status & ATMCI_RXRDY); |
@@ -1726,9 +1769,6 @@ static void atmci_write_data_pio(struct atmel_mci *host) | |||
1726 | | ATMCI_DATA_ERROR_FLAGS)); | 1769 | | ATMCI_DATA_ERROR_FLAGS)); |
1727 | host->data_status = status; | 1770 | host->data_status = status; |
1728 | data->bytes_xfered += nbytes; | 1771 | data->bytes_xfered += nbytes; |
1729 | smp_wmb(); | ||
1730 | atmci_set_pending(host, EVENT_DATA_ERROR); | ||
1731 | tasklet_schedule(&host->tasklet); | ||
1732 | return; | 1772 | return; |
1733 | } | 1773 | } |
1734 | } while (status & ATMCI_TXRDY); | 1774 | } while (status & ATMCI_TXRDY); |
@@ -1746,16 +1786,6 @@ done: | |||
1746 | atmci_set_pending(host, EVENT_XFER_COMPLETE); | 1786 | atmci_set_pending(host, EVENT_XFER_COMPLETE); |
1747 | } | 1787 | } |
1748 | 1788 | ||
1749 | static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status) | ||
1750 | { | ||
1751 | atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); | ||
1752 | |||
1753 | host->cmd_status = status; | ||
1754 | smp_wmb(); | ||
1755 | atmci_set_pending(host, EVENT_CMD_COMPLETE); | ||
1756 | tasklet_schedule(&host->tasklet); | ||
1757 | } | ||
1758 | |||
1759 | static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status) | 1789 | static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status) |
1760 | { | 1790 | { |
1761 | int i; | 1791 | int i; |
@@ -1784,8 +1814,9 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) | |||
1784 | 1814 | ||
1785 | if (pending & ATMCI_DATA_ERROR_FLAGS) { | 1815 | if (pending & ATMCI_DATA_ERROR_FLAGS) { |
1786 | atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS | 1816 | atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS |
1787 | | ATMCI_RXRDY | ATMCI_TXRDY); | 1817 | | ATMCI_RXRDY | ATMCI_TXRDY |
1788 | pending &= atmci_readl(host, ATMCI_IMR); | 1818 | | ATMCI_ENDRX | ATMCI_ENDTX |
1819 | | ATMCI_RXBUFF | ATMCI_TXBUFE); | ||
1789 | 1820 | ||
1790 | host->data_status = status; | 1821 | host->data_status = status; |
1791 | smp_wmb(); | 1822 | smp_wmb(); |
@@ -1843,23 +1874,38 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) | |||
1843 | } | 1874 | } |
1844 | } | 1875 | } |
1845 | 1876 | ||
1877 | /* | ||
1878 | * First mci IPs, so mainly the ones having pdc, have some | ||
1879 | * issues with the notbusy signal. You can't get it after | ||
1880 | * data transmission if you have not sent a stop command. | ||
1881 | * The appropriate workaround is to use the BLKE signal. | ||
1882 | */ | ||
1883 | if (pending & ATMCI_BLKE) { | ||
1884 | atmci_writel(host, ATMCI_IDR, ATMCI_BLKE); | ||
1885 | smp_wmb(); | ||
1886 | atmci_set_pending(host, EVENT_NOTBUSY); | ||
1887 | tasklet_schedule(&host->tasklet); | ||
1888 | } | ||
1846 | 1889 | ||
1847 | if (pending & ATMCI_NOTBUSY) { | 1890 | if (pending & ATMCI_NOTBUSY) { |
1848 | atmci_writel(host, ATMCI_IDR, | 1891 | atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY); |
1849 | ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY); | ||
1850 | if (!host->data_status) | ||
1851 | host->data_status = status; | ||
1852 | smp_wmb(); | 1892 | smp_wmb(); |
1853 | atmci_set_pending(host, EVENT_DATA_COMPLETE); | 1893 | atmci_set_pending(host, EVENT_NOTBUSY); |
1854 | tasklet_schedule(&host->tasklet); | 1894 | tasklet_schedule(&host->tasklet); |
1855 | } | 1895 | } |
1896 | |||
1856 | if (pending & ATMCI_RXRDY) | 1897 | if (pending & ATMCI_RXRDY) |
1857 | atmci_read_data_pio(host); | 1898 | atmci_read_data_pio(host); |
1858 | if (pending & ATMCI_TXRDY) | 1899 | if (pending & ATMCI_TXRDY) |
1859 | atmci_write_data_pio(host); | 1900 | atmci_write_data_pio(host); |
1860 | 1901 | ||
1861 | if (pending & ATMCI_CMDRDY) | 1902 | if (pending & ATMCI_CMDRDY) { |
1862 | atmci_cmd_interrupt(host, status); | 1903 | atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); |
1904 | host->cmd_status = status; | ||
1905 | smp_wmb(); | ||
1906 | atmci_set_pending(host, EVENT_CMD_RDY); | ||
1907 | tasklet_schedule(&host->tasklet); | ||
1908 | } | ||
1863 | 1909 | ||
1864 | if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) | 1910 | if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) |
1865 | atmci_sdio_interrupt(host, status); | 1911 | atmci_sdio_interrupt(host, status); |