diff options
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/atmel_nand.c | 84 |
1 files changed, 62 insertions, 22 deletions
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 459acf01fefe..e321c564ff05 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
@@ -97,7 +97,9 @@ struct atmel_nfc { | |||
97 | bool write_by_sram; | 97 | bool write_by_sram; |
98 | 98 | ||
99 | bool is_initialized; | 99 | bool is_initialized; |
100 | struct completion comp_nfc; | 100 | struct completion comp_ready; |
101 | struct completion comp_cmd_done; | ||
102 | struct completion comp_xfer_done; | ||
101 | 103 | ||
102 | /* Point to the sram bank which include readed data via NFC */ | 104 | /* Point to the sram bank which include readed data via NFC */ |
103 | void __iomem *data_in_sram; | 105 | void __iomem *data_in_sram; |
@@ -1596,44 +1598,80 @@ static irqreturn_t hsmc_interrupt(int irq, void *dev_id) | |||
1596 | { | 1598 | { |
1597 | struct atmel_nand_host *host = dev_id; | 1599 | struct atmel_nand_host *host = dev_id; |
1598 | u32 status, mask, pending; | 1600 | u32 status, mask, pending; |
1599 | irqreturn_t ret = IRQ_HANDLED; | 1601 | irqreturn_t ret = IRQ_NONE; |
1600 | 1602 | ||
1601 | status = nfc_read_status(host); | 1603 | status = nfc_read_status(host); |
1602 | mask = nfc_readl(host->nfc->hsmc_regs, IMR); | 1604 | mask = nfc_readl(host->nfc->hsmc_regs, IMR); |
1603 | pending = status & mask; | 1605 | pending = status & mask; |
1604 | 1606 | ||
1605 | if (pending & NFC_SR_XFR_DONE) { | 1607 | if (pending & NFC_SR_XFR_DONE) { |
1606 | complete(&host->nfc->comp_nfc); | 1608 | complete(&host->nfc->comp_xfer_done); |
1607 | nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE); | 1609 | nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE); |
1608 | } else if (pending & NFC_SR_RB_EDGE) { | 1610 | ret = IRQ_HANDLED; |
1609 | complete(&host->nfc->comp_nfc); | 1611 | } |
1612 | if (pending & NFC_SR_RB_EDGE) { | ||
1613 | complete(&host->nfc->comp_ready); | ||
1610 | nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE); | 1614 | nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE); |
1611 | } else if (pending & NFC_SR_CMD_DONE) { | 1615 | ret = IRQ_HANDLED; |
1612 | complete(&host->nfc->comp_nfc); | 1616 | } |
1617 | if (pending & NFC_SR_CMD_DONE) { | ||
1618 | complete(&host->nfc->comp_cmd_done); | ||
1613 | nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_CMD_DONE); | 1619 | nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_CMD_DONE); |
1614 | } else { | 1620 | ret = IRQ_HANDLED; |
1615 | ret = IRQ_NONE; | ||
1616 | } | 1621 | } |
1617 | 1622 | ||
1618 | return ret; | 1623 | return ret; |
1619 | } | 1624 | } |
1620 | 1625 | ||
1621 | /* NFC(Nand Flash Controller) related functions */ | 1626 | /* NFC(Nand Flash Controller) related functions */ |
1622 | static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag) | 1627 | static void nfc_prepare_interrupt(struct atmel_nand_host *host, u32 flag) |
1623 | { | 1628 | { |
1624 | unsigned long timeout; | 1629 | if (flag & NFC_SR_XFR_DONE) |
1625 | init_completion(&host->nfc->comp_nfc); | 1630 | init_completion(&host->nfc->comp_xfer_done); |
1631 | |||
1632 | if (flag & NFC_SR_RB_EDGE) | ||
1633 | init_completion(&host->nfc->comp_ready); | ||
1634 | |||
1635 | if (flag & NFC_SR_CMD_DONE) | ||
1636 | init_completion(&host->nfc->comp_cmd_done); | ||
1626 | 1637 | ||
1627 | /* Enable interrupt that need to wait for */ | 1638 | /* Enable interrupt that need to wait for */ |
1628 | nfc_writel(host->nfc->hsmc_regs, IER, flag); | 1639 | nfc_writel(host->nfc->hsmc_regs, IER, flag); |
1640 | } | ||
1629 | 1641 | ||
1630 | timeout = wait_for_completion_timeout(&host->nfc->comp_nfc, | 1642 | static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag) |
1631 | msecs_to_jiffies(NFC_TIME_OUT_MS)); | 1643 | { |
1632 | if (timeout) | 1644 | int i, index = 0; |
1633 | return 0; | 1645 | struct completion *comp[3]; /* Support 3 interrupt completion */ |
1646 | |||
1647 | if (flag & NFC_SR_XFR_DONE) | ||
1648 | comp[index++] = &host->nfc->comp_xfer_done; | ||
1649 | |||
1650 | if (flag & NFC_SR_RB_EDGE) | ||
1651 | comp[index++] = &host->nfc->comp_ready; | ||
1634 | 1652 | ||
1635 | /* Time out to wait for the interrupt */ | 1653 | if (flag & NFC_SR_CMD_DONE) |
1654 | comp[index++] = &host->nfc->comp_cmd_done; | ||
1655 | |||
1656 | if (index == 0) { | ||
1657 | dev_err(host->dev, "Unkown interrupt flag: 0x%08x\n", flag); | ||
1658 | return -EINVAL; | ||
1659 | } | ||
1660 | |||
1661 | for (i = 0; i < index; i++) { | ||
1662 | if (wait_for_completion_timeout(comp[i], | ||
1663 | msecs_to_jiffies(NFC_TIME_OUT_MS))) | ||
1664 | continue; /* wait for next completion */ | ||
1665 | else | ||
1666 | goto err_timeout; | ||
1667 | } | ||
1668 | |||
1669 | return 0; | ||
1670 | |||
1671 | err_timeout: | ||
1636 | dev_err(host->dev, "Time out to wait for interrupt: 0x%08x\n", flag); | 1672 | dev_err(host->dev, "Time out to wait for interrupt: 0x%08x\n", flag); |
1673 | /* Disable the interrupt as it is not handled by interrupt handler */ | ||
1674 | nfc_writel(host->nfc->hsmc_regs, IDR, flag); | ||
1637 | return -ETIMEDOUT; | 1675 | return -ETIMEDOUT; |
1638 | } | 1676 | } |
1639 | 1677 | ||
@@ -1641,6 +1679,9 @@ static int nfc_send_command(struct atmel_nand_host *host, | |||
1641 | unsigned int cmd, unsigned int addr, unsigned char cycle0) | 1679 | unsigned int cmd, unsigned int addr, unsigned char cycle0) |
1642 | { | 1680 | { |
1643 | unsigned long timeout; | 1681 | unsigned long timeout; |
1682 | u32 flag = NFC_SR_CMD_DONE; | ||
1683 | flag |= cmd & NFCADDR_CMD_DATAEN ? NFC_SR_XFR_DONE : 0; | ||
1684 | |||
1644 | dev_dbg(host->dev, | 1685 | dev_dbg(host->dev, |
1645 | "nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n", | 1686 | "nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n", |
1646 | cmd, addr, cycle0); | 1687 | cmd, addr, cycle0); |
@@ -1654,9 +1695,11 @@ static int nfc_send_command(struct atmel_nand_host *host, | |||
1654 | return -ETIMEDOUT; | 1695 | return -ETIMEDOUT; |
1655 | } | 1696 | } |
1656 | } | 1697 | } |
1698 | |||
1699 | nfc_prepare_interrupt(host, flag); | ||
1657 | nfc_writel(host->nfc->hsmc_regs, CYCLE0, cycle0); | 1700 | nfc_writel(host->nfc->hsmc_regs, CYCLE0, cycle0); |
1658 | nfc_cmd_addr1234_writel(cmd, addr, host->nfc->base_cmd_regs); | 1701 | nfc_cmd_addr1234_writel(cmd, addr, host->nfc->base_cmd_regs); |
1659 | return nfc_wait_interrupt(host, NFC_SR_CMD_DONE); | 1702 | return nfc_wait_interrupt(host, flag); |
1660 | } | 1703 | } |
1661 | 1704 | ||
1662 | static int nfc_device_ready(struct mtd_info *mtd) | 1705 | static int nfc_device_ready(struct mtd_info *mtd) |
@@ -1822,10 +1865,6 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command, | |||
1822 | nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr; | 1865 | nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr; |
1823 | nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0); | 1866 | nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0); |
1824 | 1867 | ||
1825 | if (dataen == NFCADDR_CMD_DATAEN) | ||
1826 | if (nfc_wait_interrupt(host, NFC_SR_XFR_DONE)) | ||
1827 | dev_err(host->dev, "something wrong, No XFR_DONE interrupt comes.\n"); | ||
1828 | |||
1829 | /* | 1868 | /* |
1830 | * Program and erase have their own busy handlers status, sequential | 1869 | * Program and erase have their own busy handlers status, sequential |
1831 | * in, and deplete1 need no delay. | 1870 | * in, and deplete1 need no delay. |
@@ -1850,6 +1889,7 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command, | |||
1850 | } | 1889 | } |
1851 | /* fall through */ | 1890 | /* fall through */ |
1852 | default: | 1891 | default: |
1892 | nfc_prepare_interrupt(host, NFC_SR_RB_EDGE); | ||
1853 | nfc_wait_interrupt(host, NFC_SR_RB_EDGE); | 1893 | nfc_wait_interrupt(host, NFC_SR_RB_EDGE); |
1854 | } | 1894 | } |
1855 | } | 1895 | } |