diff options
Diffstat (limited to 'drivers/mmc/host/omap_hsmmc.c')
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 283 |
1 files changed, 262 insertions, 21 deletions
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 6b7b75585926..965672663ef0 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/timer.h> | 29 | #include <linux/timer.h> |
30 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
31 | #include <linux/of.h> | 31 | #include <linux/of.h> |
32 | #include <linux/of_irq.h> | ||
32 | #include <linux/of_gpio.h> | 33 | #include <linux/of_gpio.h> |
33 | #include <linux/of_device.h> | 34 | #include <linux/of_device.h> |
34 | #include <linux/omap-dmaengine.h> | 35 | #include <linux/omap-dmaengine.h> |
@@ -36,6 +37,7 @@ | |||
36 | #include <linux/mmc/core.h> | 37 | #include <linux/mmc/core.h> |
37 | #include <linux/mmc/mmc.h> | 38 | #include <linux/mmc/mmc.h> |
38 | #include <linux/io.h> | 39 | #include <linux/io.h> |
40 | #include <linux/irq.h> | ||
39 | #include <linux/gpio.h> | 41 | #include <linux/gpio.h> |
40 | #include <linux/regulator/consumer.h> | 42 | #include <linux/regulator/consumer.h> |
41 | #include <linux/pinctrl/consumer.h> | 43 | #include <linux/pinctrl/consumer.h> |
@@ -54,6 +56,7 @@ | |||
54 | #define OMAP_HSMMC_RSP54 0x0118 | 56 | #define OMAP_HSMMC_RSP54 0x0118 |
55 | #define OMAP_HSMMC_RSP76 0x011C | 57 | #define OMAP_HSMMC_RSP76 0x011C |
56 | #define OMAP_HSMMC_DATA 0x0120 | 58 | #define OMAP_HSMMC_DATA 0x0120 |
59 | #define OMAP_HSMMC_PSTATE 0x0124 | ||
57 | #define OMAP_HSMMC_HCTL 0x0128 | 60 | #define OMAP_HSMMC_HCTL 0x0128 |
58 | #define OMAP_HSMMC_SYSCTL 0x012C | 61 | #define OMAP_HSMMC_SYSCTL 0x012C |
59 | #define OMAP_HSMMC_STAT 0x0130 | 62 | #define OMAP_HSMMC_STAT 0x0130 |
@@ -91,7 +94,10 @@ | |||
91 | #define BCE (1 << 1) | 94 | #define BCE (1 << 1) |
92 | #define FOUR_BIT (1 << 1) | 95 | #define FOUR_BIT (1 << 1) |
93 | #define HSPE (1 << 2) | 96 | #define HSPE (1 << 2) |
97 | #define IWE (1 << 24) | ||
94 | #define DDR (1 << 19) | 98 | #define DDR (1 << 19) |
99 | #define CLKEXTFREE (1 << 16) | ||
100 | #define CTPL (1 << 11) | ||
95 | #define DW8 (1 << 5) | 101 | #define DW8 (1 << 5) |
96 | #define OD 0x1 | 102 | #define OD 0x1 |
97 | #define STAT_CLEAR 0xFFFFFFFF | 103 | #define STAT_CLEAR 0xFFFFFFFF |
@@ -101,11 +107,15 @@ | |||
101 | #define SRD (1 << 26) | 107 | #define SRD (1 << 26) |
102 | #define SOFTRESET (1 << 1) | 108 | #define SOFTRESET (1 << 1) |
103 | 109 | ||
110 | /* PSTATE */ | ||
111 | #define DLEV_DAT(x) (1 << (20 + (x))) | ||
112 | |||
104 | /* Interrupt masks for IE and ISE register */ | 113 | /* Interrupt masks for IE and ISE register */ |
105 | #define CC_EN (1 << 0) | 114 | #define CC_EN (1 << 0) |
106 | #define TC_EN (1 << 1) | 115 | #define TC_EN (1 << 1) |
107 | #define BWR_EN (1 << 4) | 116 | #define BWR_EN (1 << 4) |
108 | #define BRR_EN (1 << 5) | 117 | #define BRR_EN (1 << 5) |
118 | #define CIRQ_EN (1 << 8) | ||
109 | #define ERR_EN (1 << 15) | 119 | #define ERR_EN (1 << 15) |
110 | #define CTO_EN (1 << 16) | 120 | #define CTO_EN (1 << 16) |
111 | #define CCRC_EN (1 << 17) | 121 | #define CCRC_EN (1 << 17) |
@@ -140,7 +150,6 @@ | |||
140 | #define VDD_3V0 3000000 /* 300000 uV */ | 150 | #define VDD_3V0 3000000 /* 300000 uV */ |
141 | #define VDD_165_195 (ffs(MMC_VDD_165_195) - 1) | 151 | #define VDD_165_195 (ffs(MMC_VDD_165_195) - 1) |
142 | 152 | ||
143 | #define AUTO_CMD23 (1 << 1) /* Auto CMD23 support */ | ||
144 | /* | 153 | /* |
145 | * One controller can have multiple slots, like on some omap boards using | 154 | * One controller can have multiple slots, like on some omap boards using |
146 | * omap.c controller driver. Luckily this is not currently done on any known | 155 | * omap.c controller driver. Luckily this is not currently done on any known |
@@ -194,6 +203,7 @@ struct omap_hsmmc_host { | |||
194 | u32 sysctl; | 203 | u32 sysctl; |
195 | u32 capa; | 204 | u32 capa; |
196 | int irq; | 205 | int irq; |
206 | int wake_irq; | ||
197 | int use_dma, dma_ch; | 207 | int use_dma, dma_ch; |
198 | struct dma_chan *tx_chan; | 208 | struct dma_chan *tx_chan; |
199 | struct dma_chan *rx_chan; | 209 | struct dma_chan *rx_chan; |
@@ -206,6 +216,9 @@ struct omap_hsmmc_host { | |||
206 | int req_in_progress; | 216 | int req_in_progress; |
207 | unsigned long clk_rate; | 217 | unsigned long clk_rate; |
208 | unsigned int flags; | 218 | unsigned int flags; |
219 | #define AUTO_CMD23 (1 << 0) /* Auto CMD23 support */ | ||
220 | #define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */ | ||
221 | #define HSMMC_WAKE_IRQ_ENABLED (1 << 2) | ||
209 | struct omap_hsmmc_next next_data; | 222 | struct omap_hsmmc_next next_data; |
210 | struct omap_mmc_platform_data *pdata; | 223 | struct omap_mmc_platform_data *pdata; |
211 | }; | 224 | }; |
@@ -510,27 +523,40 @@ static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host) | |||
510 | static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host, | 523 | static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host, |
511 | struct mmc_command *cmd) | 524 | struct mmc_command *cmd) |
512 | { | 525 | { |
513 | unsigned int irq_mask; | 526 | u32 irq_mask = INT_EN_MASK; |
527 | unsigned long flags; | ||
514 | 528 | ||
515 | if (host->use_dma) | 529 | if (host->use_dma) |
516 | irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN); | 530 | irq_mask &= ~(BRR_EN | BWR_EN); |
517 | else | ||
518 | irq_mask = INT_EN_MASK; | ||
519 | 531 | ||
520 | /* Disable timeout for erases */ | 532 | /* Disable timeout for erases */ |
521 | if (cmd->opcode == MMC_ERASE) | 533 | if (cmd->opcode == MMC_ERASE) |
522 | irq_mask &= ~DTO_EN; | 534 | irq_mask &= ~DTO_EN; |
523 | 535 | ||
536 | spin_lock_irqsave(&host->irq_lock, flags); | ||
524 | OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); | 537 | OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); |
525 | OMAP_HSMMC_WRITE(host->base, ISE, irq_mask); | 538 | OMAP_HSMMC_WRITE(host->base, ISE, irq_mask); |
539 | |||
540 | /* latch pending CIRQ, but don't signal MMC core */ | ||
541 | if (host->flags & HSMMC_SDIO_IRQ_ENABLED) | ||
542 | irq_mask |= CIRQ_EN; | ||
526 | OMAP_HSMMC_WRITE(host->base, IE, irq_mask); | 543 | OMAP_HSMMC_WRITE(host->base, IE, irq_mask); |
544 | spin_unlock_irqrestore(&host->irq_lock, flags); | ||
527 | } | 545 | } |
528 | 546 | ||
529 | static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host) | 547 | static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host) |
530 | { | 548 | { |
531 | OMAP_HSMMC_WRITE(host->base, ISE, 0); | 549 | u32 irq_mask = 0; |
532 | OMAP_HSMMC_WRITE(host->base, IE, 0); | 550 | unsigned long flags; |
551 | |||
552 | spin_lock_irqsave(&host->irq_lock, flags); | ||
553 | /* no transfer running but need to keep cirq if enabled */ | ||
554 | if (host->flags & HSMMC_SDIO_IRQ_ENABLED) | ||
555 | irq_mask |= CIRQ_EN; | ||
556 | OMAP_HSMMC_WRITE(host->base, ISE, irq_mask); | ||
557 | OMAP_HSMMC_WRITE(host->base, IE, irq_mask); | ||
533 | OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); | 558 | OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); |
559 | spin_unlock_irqrestore(&host->irq_lock, flags); | ||
534 | } | 560 | } |
535 | 561 | ||
536 | /* Calculate divisor for the given clock frequency */ | 562 | /* Calculate divisor for the given clock frequency */ |
@@ -667,6 +693,9 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) | |||
667 | capa = VS18; | 693 | capa = VS18; |
668 | } | 694 | } |
669 | 695 | ||
696 | if (host->mmc->caps & MMC_CAP_SDIO_IRQ) | ||
697 | hctl |= IWE; | ||
698 | |||
670 | OMAP_HSMMC_WRITE(host->base, HCTL, | 699 | OMAP_HSMMC_WRITE(host->base, HCTL, |
671 | OMAP_HSMMC_READ(host->base, HCTL) | hctl); | 700 | OMAP_HSMMC_READ(host->base, HCTL) | hctl); |
672 | 701 | ||
@@ -681,7 +710,9 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) | |||
681 | && time_before(jiffies, timeout)) | 710 | && time_before(jiffies, timeout)) |
682 | ; | 711 | ; |
683 | 712 | ||
684 | omap_hsmmc_disable_irq(host); | 713 | OMAP_HSMMC_WRITE(host->base, ISE, 0); |
714 | OMAP_HSMMC_WRITE(host->base, IE, 0); | ||
715 | OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); | ||
685 | 716 | ||
686 | /* Do not initialize card-specific things if the power is off */ | 717 | /* Do not initialize card-specific things if the power is off */ |
687 | if (host->power_mode == MMC_POWER_OFF) | 718 | if (host->power_mode == MMC_POWER_OFF) |
@@ -1118,8 +1149,12 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id) | |||
1118 | int status; | 1149 | int status; |
1119 | 1150 | ||
1120 | status = OMAP_HSMMC_READ(host->base, STAT); | 1151 | status = OMAP_HSMMC_READ(host->base, STAT); |
1121 | while (status & INT_EN_MASK && host->req_in_progress) { | 1152 | while (status & (INT_EN_MASK | CIRQ_EN)) { |
1122 | omap_hsmmc_do_irq(host, status); | 1153 | if (host->req_in_progress) |
1154 | omap_hsmmc_do_irq(host, status); | ||
1155 | |||
1156 | if (status & CIRQ_EN) | ||
1157 | mmc_signal_sdio_irq(host->mmc); | ||
1123 | 1158 | ||
1124 | /* Flush posted write */ | 1159 | /* Flush posted write */ |
1125 | status = OMAP_HSMMC_READ(host->base, STAT); | 1160 | status = OMAP_HSMMC_READ(host->base, STAT); |
@@ -1128,6 +1163,22 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id) | |||
1128 | return IRQ_HANDLED; | 1163 | return IRQ_HANDLED; |
1129 | } | 1164 | } |
1130 | 1165 | ||
1166 | static irqreturn_t omap_hsmmc_wake_irq(int irq, void *dev_id) | ||
1167 | { | ||
1168 | struct omap_hsmmc_host *host = dev_id; | ||
1169 | |||
1170 | /* cirq is level triggered, disable to avoid infinite loop */ | ||
1171 | spin_lock(&host->irq_lock); | ||
1172 | if (host->flags & HSMMC_WAKE_IRQ_ENABLED) { | ||
1173 | disable_irq_nosync(host->wake_irq); | ||
1174 | host->flags &= ~HSMMC_WAKE_IRQ_ENABLED; | ||
1175 | } | ||
1176 | spin_unlock(&host->irq_lock); | ||
1177 | pm_request_resume(host->dev); /* no use counter */ | ||
1178 | |||
1179 | return IRQ_HANDLED; | ||
1180 | } | ||
1181 | |||
1131 | static void set_sd_bus_power(struct omap_hsmmc_host *host) | 1182 | static void set_sd_bus_power(struct omap_hsmmc_host *host) |
1132 | { | 1183 | { |
1133 | unsigned long i; | 1184 | unsigned long i; |
@@ -1639,6 +1690,103 @@ static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) | |||
1639 | mmc_slot(host).init_card(card); | 1690 | mmc_slot(host).init_card(card); |
1640 | } | 1691 | } |
1641 | 1692 | ||
1693 | static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) | ||
1694 | { | ||
1695 | struct omap_hsmmc_host *host = mmc_priv(mmc); | ||
1696 | u32 irq_mask, con; | ||
1697 | unsigned long flags; | ||
1698 | |||
1699 | spin_lock_irqsave(&host->irq_lock, flags); | ||
1700 | |||
1701 | con = OMAP_HSMMC_READ(host->base, CON); | ||
1702 | irq_mask = OMAP_HSMMC_READ(host->base, ISE); | ||
1703 | if (enable) { | ||
1704 | host->flags |= HSMMC_SDIO_IRQ_ENABLED; | ||
1705 | irq_mask |= CIRQ_EN; | ||
1706 | con |= CTPL | CLKEXTFREE; | ||
1707 | } else { | ||
1708 | host->flags &= ~HSMMC_SDIO_IRQ_ENABLED; | ||
1709 | irq_mask &= ~CIRQ_EN; | ||
1710 | con &= ~(CTPL | CLKEXTFREE); | ||
1711 | } | ||
1712 | OMAP_HSMMC_WRITE(host->base, CON, con); | ||
1713 | OMAP_HSMMC_WRITE(host->base, IE, irq_mask); | ||
1714 | |||
1715 | /* | ||
1716 | * if enable, piggy back detection on current request | ||
1717 | * but always disable immediately | ||
1718 | */ | ||
1719 | if (!host->req_in_progress || !enable) | ||
1720 | OMAP_HSMMC_WRITE(host->base, ISE, irq_mask); | ||
1721 | |||
1722 | /* flush posted write */ | ||
1723 | OMAP_HSMMC_READ(host->base, IE); | ||
1724 | |||
1725 | spin_unlock_irqrestore(&host->irq_lock, flags); | ||
1726 | } | ||
1727 | |||
1728 | static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host) | ||
1729 | { | ||
1730 | struct mmc_host *mmc = host->mmc; | ||
1731 | int ret; | ||
1732 | |||
1733 | /* | ||
1734 | * For omaps with wake-up path, wakeirq will be irq from pinctrl and | ||
1735 | * for other omaps, wakeirq will be from GPIO (dat line remuxed to | ||
1736 | * gpio). wakeirq is needed to detect sdio irq in runtime suspend state | ||
1737 | * with functional clock disabled. | ||
1738 | */ | ||
1739 | if (!host->dev->of_node || !host->wake_irq) | ||
1740 | return -ENODEV; | ||
1741 | |||
1742 | /* Prevent auto-enabling of IRQ */ | ||
1743 | irq_set_status_flags(host->wake_irq, IRQ_NOAUTOEN); | ||
1744 | ret = devm_request_irq(host->dev, host->wake_irq, omap_hsmmc_wake_irq, | ||
1745 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
1746 | mmc_hostname(mmc), host); | ||
1747 | if (ret) { | ||
1748 | dev_err(mmc_dev(host->mmc), "Unable to request wake IRQ\n"); | ||
1749 | goto err; | ||
1750 | } | ||
1751 | |||
1752 | /* | ||
1753 | * Some omaps don't have wake-up path from deeper idle states | ||
1754 | * and need to remux SDIO DAT1 to GPIO for wake-up from idle. | ||
1755 | */ | ||
1756 | if (host->pdata->controller_flags & OMAP_HSMMC_SWAKEUP_MISSING) { | ||
1757 | struct pinctrl *p = devm_pinctrl_get(host->dev); | ||
1758 | if (!p) { | ||
1759 | ret = -ENODEV; | ||
1760 | goto err_free_irq; | ||
1761 | } | ||
1762 | if (IS_ERR(pinctrl_lookup_state(p, PINCTRL_STATE_DEFAULT))) { | ||
1763 | dev_info(host->dev, "missing default pinctrl state\n"); | ||
1764 | devm_pinctrl_put(p); | ||
1765 | ret = -EINVAL; | ||
1766 | goto err_free_irq; | ||
1767 | } | ||
1768 | |||
1769 | if (IS_ERR(pinctrl_lookup_state(p, PINCTRL_STATE_IDLE))) { | ||
1770 | dev_info(host->dev, "missing idle pinctrl state\n"); | ||
1771 | devm_pinctrl_put(p); | ||
1772 | ret = -EINVAL; | ||
1773 | goto err_free_irq; | ||
1774 | } | ||
1775 | devm_pinctrl_put(p); | ||
1776 | } | ||
1777 | |||
1778 | OMAP_HSMMC_WRITE(host->base, HCTL, | ||
1779 | OMAP_HSMMC_READ(host->base, HCTL) | IWE); | ||
1780 | return 0; | ||
1781 | |||
1782 | err_free_irq: | ||
1783 | devm_free_irq(host->dev, host->wake_irq, host); | ||
1784 | err: | ||
1785 | dev_warn(host->dev, "no SDIO IRQ support, falling back to polling\n"); | ||
1786 | host->wake_irq = 0; | ||
1787 | return ret; | ||
1788 | } | ||
1789 | |||
1642 | static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host) | 1790 | static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host) |
1643 | { | 1791 | { |
1644 | u32 hctl, capa, value; | 1792 | u32 hctl, capa, value; |
@@ -1691,7 +1839,7 @@ static const struct mmc_host_ops omap_hsmmc_ops = { | |||
1691 | .get_cd = omap_hsmmc_get_cd, | 1839 | .get_cd = omap_hsmmc_get_cd, |
1692 | .get_ro = omap_hsmmc_get_ro, | 1840 | .get_ro = omap_hsmmc_get_ro, |
1693 | .init_card = omap_hsmmc_init_card, | 1841 | .init_card = omap_hsmmc_init_card, |
1694 | /* NYET -- enable_sdio_irq */ | 1842 | .enable_sdio_irq = omap_hsmmc_enable_sdio_irq, |
1695 | }; | 1843 | }; |
1696 | 1844 | ||
1697 | #ifdef CONFIG_DEBUG_FS | 1845 | #ifdef CONFIG_DEBUG_FS |
@@ -1701,13 +1849,23 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data) | |||
1701 | struct mmc_host *mmc = s->private; | 1849 | struct mmc_host *mmc = s->private; |
1702 | struct omap_hsmmc_host *host = mmc_priv(mmc); | 1850 | struct omap_hsmmc_host *host = mmc_priv(mmc); |
1703 | 1851 | ||
1704 | seq_printf(s, "mmc%d:\n ctx_loss:\t%d\n\nregs:\n", | 1852 | seq_printf(s, "mmc%d:\n", mmc->index); |
1705 | mmc->index, host->context_loss); | 1853 | seq_printf(s, "sdio irq mode\t%s\n", |
1854 | (mmc->caps & MMC_CAP_SDIO_IRQ) ? "interrupt" : "polling"); | ||
1706 | 1855 | ||
1707 | pm_runtime_get_sync(host->dev); | 1856 | if (mmc->caps & MMC_CAP_SDIO_IRQ) { |
1857 | seq_printf(s, "sdio irq \t%s\n", | ||
1858 | (host->flags & HSMMC_SDIO_IRQ_ENABLED) ? "enabled" | ||
1859 | : "disabled"); | ||
1860 | } | ||
1861 | seq_printf(s, "ctx_loss:\t%d\n", host->context_loss); | ||
1708 | 1862 | ||
1863 | pm_runtime_get_sync(host->dev); | ||
1864 | seq_puts(s, "\nregs:\n"); | ||
1709 | seq_printf(s, "CON:\t\t0x%08x\n", | 1865 | seq_printf(s, "CON:\t\t0x%08x\n", |
1710 | OMAP_HSMMC_READ(host->base, CON)); | 1866 | OMAP_HSMMC_READ(host->base, CON)); |
1867 | seq_printf(s, "PSTATE:\t\t0x%08x\n", | ||
1868 | OMAP_HSMMC_READ(host->base, PSTATE)); | ||
1711 | seq_printf(s, "HCTL:\t\t0x%08x\n", | 1869 | seq_printf(s, "HCTL:\t\t0x%08x\n", |
1712 | OMAP_HSMMC_READ(host->base, HCTL)); | 1870 | OMAP_HSMMC_READ(host->base, HCTL)); |
1713 | seq_printf(s, "SYSCTL:\t\t0x%08x\n", | 1871 | seq_printf(s, "SYSCTL:\t\t0x%08x\n", |
@@ -1761,6 +1919,10 @@ static const struct omap_mmc_of_data omap3_pre_es3_mmc_of_data = { | |||
1761 | static const struct omap_mmc_of_data omap4_mmc_of_data = { | 1919 | static const struct omap_mmc_of_data omap4_mmc_of_data = { |
1762 | .reg_offset = 0x100, | 1920 | .reg_offset = 0x100, |
1763 | }; | 1921 | }; |
1922 | static const struct omap_mmc_of_data am33xx_mmc_of_data = { | ||
1923 | .reg_offset = 0x100, | ||
1924 | .controller_flags = OMAP_HSMMC_SWAKEUP_MISSING, | ||
1925 | }; | ||
1764 | 1926 | ||
1765 | static const struct of_device_id omap_mmc_of_match[] = { | 1927 | static const struct of_device_id omap_mmc_of_match[] = { |
1766 | { | 1928 | { |
@@ -1777,6 +1939,10 @@ static const struct of_device_id omap_mmc_of_match[] = { | |||
1777 | .compatible = "ti,omap4-hsmmc", | 1939 | .compatible = "ti,omap4-hsmmc", |
1778 | .data = &omap4_mmc_of_data, | 1940 | .data = &omap4_mmc_of_data, |
1779 | }, | 1941 | }, |
1942 | { | ||
1943 | .compatible = "ti,am33xx-hsmmc", | ||
1944 | .data = &am33xx_mmc_of_data, | ||
1945 | }, | ||
1780 | {}, | 1946 | {}, |
1781 | }; | 1947 | }; |
1782 | MODULE_DEVICE_TABLE(of, omap_mmc_of_match); | 1948 | MODULE_DEVICE_TABLE(of, omap_mmc_of_match); |
@@ -1850,7 +2016,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) | |||
1850 | const struct of_device_id *match; | 2016 | const struct of_device_id *match; |
1851 | dma_cap_mask_t mask; | 2017 | dma_cap_mask_t mask; |
1852 | unsigned tx_req, rx_req; | 2018 | unsigned tx_req, rx_req; |
1853 | struct pinctrl *pinctrl; | ||
1854 | const struct omap_mmc_of_data *data; | 2019 | const struct omap_mmc_of_data *data; |
1855 | void __iomem *base; | 2020 | void __iomem *base; |
1856 | 2021 | ||
@@ -1913,6 +2078,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev) | |||
1913 | 2078 | ||
1914 | platform_set_drvdata(pdev, host); | 2079 | platform_set_drvdata(pdev, host); |
1915 | 2080 | ||
2081 | if (pdev->dev.of_node) | ||
2082 | host->wake_irq = irq_of_parse_and_map(pdev->dev.of_node, 1); | ||
2083 | |||
1916 | mmc->ops = &omap_hsmmc_ops; | 2084 | mmc->ops = &omap_hsmmc_ops; |
1917 | 2085 | ||
1918 | mmc->f_min = OMAP_MMC_MIN_CLOCK; | 2086 | mmc->f_min = OMAP_MMC_MIN_CLOCK; |
@@ -2061,10 +2229,17 @@ static int omap_hsmmc_probe(struct platform_device *pdev) | |||
2061 | 2229 | ||
2062 | omap_hsmmc_disable_irq(host); | 2230 | omap_hsmmc_disable_irq(host); |
2063 | 2231 | ||
2064 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); | 2232 | /* |
2065 | if (IS_ERR(pinctrl)) | 2233 | * For now, only support SDIO interrupt if we have a separate |
2066 | dev_warn(&pdev->dev, | 2234 | * wake-up interrupt configured from device tree. This is because |
2067 | "pins are not configured from the driver\n"); | 2235 | * the wake-up interrupt is needed for idle state and some |
2236 | * platforms need special quirks. And we don't want to add new | ||
2237 | * legacy mux platform init code callbacks any longer as we | ||
2238 | * are moving to DT based booting anyways. | ||
2239 | */ | ||
2240 | ret = omap_hsmmc_configure_wake_irq(host); | ||
2241 | if (!ret) | ||
2242 | mmc->caps |= MMC_CAP_SDIO_IRQ; | ||
2068 | 2243 | ||
2069 | omap_hsmmc_protect_card(host); | 2244 | omap_hsmmc_protect_card(host); |
2070 | 2245 | ||
@@ -2170,11 +2345,18 @@ static int omap_hsmmc_suspend(struct device *dev) | |||
2170 | pm_runtime_get_sync(host->dev); | 2345 | pm_runtime_get_sync(host->dev); |
2171 | 2346 | ||
2172 | if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) { | 2347 | if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) { |
2173 | omap_hsmmc_disable_irq(host); | 2348 | OMAP_HSMMC_WRITE(host->base, ISE, 0); |
2349 | OMAP_HSMMC_WRITE(host->base, IE, 0); | ||
2350 | OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); | ||
2174 | OMAP_HSMMC_WRITE(host->base, HCTL, | 2351 | OMAP_HSMMC_WRITE(host->base, HCTL, |
2175 | OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); | 2352 | OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); |
2176 | } | 2353 | } |
2177 | 2354 | ||
2355 | /* do not wake up due to sdio irq */ | ||
2356 | if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) && | ||
2357 | !(host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) | ||
2358 | disable_irq(host->wake_irq); | ||
2359 | |||
2178 | if (host->dbclk) | 2360 | if (host->dbclk) |
2179 | clk_disable_unprepare(host->dbclk); | 2361 | clk_disable_unprepare(host->dbclk); |
2180 | 2362 | ||
@@ -2200,6 +2382,10 @@ static int omap_hsmmc_resume(struct device *dev) | |||
2200 | 2382 | ||
2201 | omap_hsmmc_protect_card(host); | 2383 | omap_hsmmc_protect_card(host); |
2202 | 2384 | ||
2385 | if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) && | ||
2386 | !(host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) | ||
2387 | enable_irq(host->wake_irq); | ||
2388 | |||
2203 | pm_runtime_mark_last_busy(host->dev); | 2389 | pm_runtime_mark_last_busy(host->dev); |
2204 | pm_runtime_put_autosuspend(host->dev); | 2390 | pm_runtime_put_autosuspend(host->dev); |
2205 | return 0; | 2391 | return 0; |
@@ -2215,22 +2401,77 @@ static int omap_hsmmc_resume(struct device *dev) | |||
2215 | static int omap_hsmmc_runtime_suspend(struct device *dev) | 2401 | static int omap_hsmmc_runtime_suspend(struct device *dev) |
2216 | { | 2402 | { |
2217 | struct omap_hsmmc_host *host; | 2403 | struct omap_hsmmc_host *host; |
2404 | unsigned long flags; | ||
2405 | int ret = 0; | ||
2218 | 2406 | ||
2219 | host = platform_get_drvdata(to_platform_device(dev)); | 2407 | host = platform_get_drvdata(to_platform_device(dev)); |
2220 | omap_hsmmc_context_save(host); | 2408 | omap_hsmmc_context_save(host); |
2221 | dev_dbg(dev, "disabled\n"); | 2409 | dev_dbg(dev, "disabled\n"); |
2222 | 2410 | ||
2223 | return 0; | 2411 | spin_lock_irqsave(&host->irq_lock, flags); |
2412 | if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) && | ||
2413 | (host->flags & HSMMC_SDIO_IRQ_ENABLED)) { | ||
2414 | /* disable sdio irq handling to prevent race */ | ||
2415 | OMAP_HSMMC_WRITE(host->base, ISE, 0); | ||
2416 | OMAP_HSMMC_WRITE(host->base, IE, 0); | ||
2417 | |||
2418 | if (!(OMAP_HSMMC_READ(host->base, PSTATE) & DLEV_DAT(1))) { | ||
2419 | /* | ||
2420 | * dat1 line low, pending sdio irq | ||
2421 | * race condition: possible irq handler running on | ||
2422 | * multi-core, abort | ||
2423 | */ | ||
2424 | dev_dbg(dev, "pending sdio irq, abort suspend\n"); | ||
2425 | OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); | ||
2426 | OMAP_HSMMC_WRITE(host->base, ISE, CIRQ_EN); | ||
2427 | OMAP_HSMMC_WRITE(host->base, IE, CIRQ_EN); | ||
2428 | pm_runtime_mark_last_busy(dev); | ||
2429 | ret = -EBUSY; | ||
2430 | goto abort; | ||
2431 | } | ||
2432 | |||
2433 | pinctrl_pm_select_idle_state(dev); | ||
2434 | |||
2435 | WARN_ON(host->flags & HSMMC_WAKE_IRQ_ENABLED); | ||
2436 | enable_irq(host->wake_irq); | ||
2437 | host->flags |= HSMMC_WAKE_IRQ_ENABLED; | ||
2438 | } else { | ||
2439 | pinctrl_pm_select_idle_state(dev); | ||
2440 | } | ||
2441 | |||
2442 | abort: | ||
2443 | spin_unlock_irqrestore(&host->irq_lock, flags); | ||
2444 | return ret; | ||
2224 | } | 2445 | } |
2225 | 2446 | ||
2226 | static int omap_hsmmc_runtime_resume(struct device *dev) | 2447 | static int omap_hsmmc_runtime_resume(struct device *dev) |
2227 | { | 2448 | { |
2228 | struct omap_hsmmc_host *host; | 2449 | struct omap_hsmmc_host *host; |
2450 | unsigned long flags; | ||
2229 | 2451 | ||
2230 | host = platform_get_drvdata(to_platform_device(dev)); | 2452 | host = platform_get_drvdata(to_platform_device(dev)); |
2231 | omap_hsmmc_context_restore(host); | 2453 | omap_hsmmc_context_restore(host); |
2232 | dev_dbg(dev, "enabled\n"); | 2454 | dev_dbg(dev, "enabled\n"); |
2233 | 2455 | ||
2456 | spin_lock_irqsave(&host->irq_lock, flags); | ||
2457 | if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) && | ||
2458 | (host->flags & HSMMC_SDIO_IRQ_ENABLED)) { | ||
2459 | /* sdio irq flag can't change while in runtime suspend */ | ||
2460 | if (host->flags & HSMMC_WAKE_IRQ_ENABLED) { | ||
2461 | disable_irq_nosync(host->wake_irq); | ||
2462 | host->flags &= ~HSMMC_WAKE_IRQ_ENABLED; | ||
2463 | } | ||
2464 | |||
2465 | pinctrl_pm_select_default_state(host->dev); | ||
2466 | |||
2467 | /* irq lost, if pinmux incorrect */ | ||
2468 | OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); | ||
2469 | OMAP_HSMMC_WRITE(host->base, ISE, CIRQ_EN); | ||
2470 | OMAP_HSMMC_WRITE(host->base, IE, CIRQ_EN); | ||
2471 | } else { | ||
2472 | pinctrl_pm_select_default_state(host->dev); | ||
2473 | } | ||
2474 | spin_unlock_irqrestore(&host->irq_lock, flags); | ||
2234 | return 0; | 2475 | return 0; |
2235 | } | 2476 | } |
2236 | 2477 | ||