linux-omap 2.6.39: initial add with beagleboard support
[openembedded.git] / recipes / linux / linux-omap-2.6.39 / sakoman / 0013-Enable-the-use-of-SDIO-card-interrupts.patch
blobf272276638f996bf671cd482a5a9d81727adbbf1
1 From bb4c074079c12d808367c8666cedcbba1dc456cc Mon Sep 17 00:00:00 2001
2 From: David Vrabel <david.vrabel@csr.com>
3 Date: Fri, 2 Apr 2010 08:42:22 -0700
4 Subject: [PATCH 13/28] Enable the use of SDIO card interrupts.
6 FCLK must be enabled while SDIO interrupts are enabled or the MMC
7 module won't wake-up (even though ENAWAKEUP in SYSCONFIG and IWE in
8 HTCL have been set). Enabling the MMC module to wake-up would require
9 configuring the MMC module (and the mmci_dat[1] GPIO when the CORE
10 power domain is OFF) as wake-up sources in the PRCM.
12 The writes to STAT and ISE when starting a command are unnecessary and
13 have been removed.
15 Signed-off-by: David Vrabel <david.vrabel@csr.com>
16 ---
17 drivers/mmc/host/omap_hsmmc.c | 118 +++++++++++++++++++++++++++++------------
18 1 files changed, 83 insertions(+), 35 deletions(-)
20 diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
21 index 83f93ab..d57686c 100644
22 --- a/drivers/mmc/host/omap_hsmmc.c
23 +++ b/drivers/mmc/host/omap_hsmmc.c
24 @@ -67,6 +67,7 @@
25 #define SDVS_MASK 0x00000E00
26 #define SDVSCLR 0xFFFFF1FF
27 #define SDVSDET 0x00000400
28 +#define ENAWAKEUP (1 << 2)
29 #define AUTOIDLE 0x1
30 #define SDBP (1 << 8)
31 #define DTO 0xe
32 @@ -77,10 +78,13 @@
33 #define CLKD_SHIFT 6
34 #define DTO_MASK 0x000F0000
35 #define DTO_SHIFT 16
36 +#define CIRQ_ENABLE (1 << 8)
37 #define INT_EN_MASK 0x307F0033
38 #define BWR_ENABLE (1 << 4)
39 #define BRR_ENABLE (1 << 5)
40 #define DTO_ENABLE (1 << 20)
41 +#define CTPL (1 << 11)
42 +#define CLKEXTFREE (1 << 16)
43 #define INIT_STREAM (1 << 1)
44 #define DP_SELECT (1 << 21)
45 #define DDIR (1 << 4)
46 @@ -88,10 +92,12 @@
47 #define MSBS (1 << 5)
48 #define BCE (1 << 1)
49 #define FOUR_BIT (1 << 1)
50 +#define IWE (1 << 24)
51 #define DW8 (1 << 5)
52 #define CC 0x1
53 #define TC 0x02
54 #define OD 0x1
55 +#define CIRQ (1 << 8)
56 #define ERR (1 << 15)
57 #define CMD_TIMEOUT (1 << 16)
58 #define DATA_TIMEOUT (1 << 20)
59 @@ -186,6 +192,7 @@ struct omap_hsmmc_host {
60 int protect_card;
61 int reqs_blocked;
62 int use_reg;
63 + int sdio_int;
65 struct omap_mmc_platform_data *pdata;
67 @@ -598,7 +605,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
70 OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
71 - OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
72 + OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE | ENAWAKEUP);
74 if (host->id == OMAP_MMC1_DEVID) {
75 if (host->power_mode != MMC_POWER_OFF &&
76 @@ -613,7 +620,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
79 OMAP_HSMMC_WRITE(host->base, HCTL,
80 - OMAP_HSMMC_READ(host->base, HCTL) | hctl);
81 + OMAP_HSMMC_READ(host->base, HCTL) | hctl | IWE);
83 OMAP_HSMMC_WRITE(host->base, CAPA,
84 OMAP_HSMMC_READ(host->base, CAPA) | capa);
85 @@ -627,7 +634,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
88 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
89 - OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
90 + OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK | CIRQ);
91 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
93 /* Do not initialize card-specific things if the power is off */
94 @@ -791,22 +798,19 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
95 struct mmc_data *data)
97 int cmdreg = 0, resptype = 0, cmdtype = 0;
98 + int int_en_mask = INT_EN_MASK;
100 dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
101 mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
102 host->cmd = cmd;
104 - /*
105 - * Clear status bits and enable interrupts
106 - */
107 - OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
108 - OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
110 if (host->use_dma)
111 - OMAP_HSMMC_WRITE(host->base, IE,
112 - INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE));
113 - else
114 - OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
115 + int_en_mask &= ~(BRR_ENABLE | BWR_ENABLE);
117 + if (host->sdio_int)
118 + int_en_mask |= CIRQ;
120 + OMAP_HSMMC_WRITE(host->base, IE, int_en_mask);
122 host->response_busy = 0;
123 if (cmd->flags & MMC_RSP_PRESENT) {
124 @@ -1019,23 +1023,26 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
126 struct omap_hsmmc_host *host = dev_id;
127 struct mmc_data *data;
128 - int end_cmd = 0, end_trans = 0, status;
129 + u32 status;
130 + int end_cmd = 0, end_trans = 0;
131 + bool card_irq = false;
133 spin_lock(&host->irq_lock);
135 - if (host->mrq == NULL) {
136 - OMAP_HSMMC_WRITE(host->base, STAT,
137 - OMAP_HSMMC_READ(host->base, STAT));
138 - /* Flush posted write */
139 - OMAP_HSMMC_READ(host->base, STAT);
140 - spin_unlock(&host->irq_lock);
141 - return IRQ_HANDLED;
144 - data = host->data;
145 status = OMAP_HSMMC_READ(host->base, STAT);
146 + OMAP_HSMMC_WRITE(host->base, STAT, status);
147 + OMAP_HSMMC_READ(host->base, STAT); /* Flush posted write. */
149 dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
151 + if (status & CIRQ)
152 + card_irq = true;
154 + if (host->mrq == NULL)
155 + goto out;
157 + data = host->data;
159 if (status & ERR) {
160 #ifdef CONFIG_MMC_DEBUG
161 omap_hsmmc_report_irq(host, status);
162 @@ -1085,17 +1092,16 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
166 - OMAP_HSMMC_WRITE(host->base, STAT, status);
167 - /* Flush posted write */
168 - OMAP_HSMMC_READ(host->base, STAT);
170 if (end_cmd || ((status & CC) && host->cmd))
171 omap_hsmmc_cmd_done(host, host->cmd);
172 if ((end_trans || (status & TC)) && host->mrq)
173 omap_hsmmc_xfer_done(host, data);
175 +out:
176 spin_unlock(&host->irq_lock);
178 + if (card_irq)
179 + mmc_signal_sdio_irq(host->mmc);
181 return IRQ_HANDLED;
184 @@ -1643,6 +1649,47 @@ static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
185 mmc_slot(host).init_card(card);
188 +static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
190 + struct omap_hsmmc_host *host = mmc_priv(mmc);
191 + u32 ie, con;
192 + unsigned long flags;
194 + spin_lock_irqsave(&host->irq_lock, flags);
196 + /*
197 + * When interrupts are enabled, CTPL must be set to enable
198 + * DAT1 input buffer (or the card interrupt is always
199 + * asserted) and FCLK must be enabled as wake-up does not
200 + * work. Take care to disable FCLK after all the register
201 + * accesses as they might not complete if FCLK is off.
203 + * FIXME: if the MMC module (and the mmci_dat[1] GPIO when the
204 + * CORE power domain is OFF) are configured as a wake-up
205 + * sources in the PRCM, then FCLK could be switched off. This
206 + * might add too much latency.
207 + */
208 + con = OMAP_HSMMC_READ(host->base, CON);
209 + ie = OMAP_HSMMC_READ(host->base, IE);
210 + if (enable) {
211 + clk_enable(host->fclk);
212 + ie |= CIRQ_ENABLE;
213 + con |= CTPL | CLKEXTFREE;
214 + host->sdio_int = 1;
215 + } else {
216 + ie &= ~CIRQ_ENABLE;
217 + con &= ~(CTPL | CLKEXTFREE);
218 + host->sdio_int = 0;
220 + OMAP_HSMMC_WRITE(host->base, CON, con);
221 + OMAP_HSMMC_WRITE(host->base, IE, ie);
222 + OMAP_HSMMC_READ(host->base, IE); /* flush posted write */
223 + if (!enable)
224 + clk_disable(host->fclk);
226 + spin_unlock_irqrestore(&host->irq_lock, flags);
229 static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
231 u32 hctl, capa, value;
232 @@ -1657,14 +1704,14 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
235 value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
236 - OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
237 + OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl | IWE);
239 value = OMAP_HSMMC_READ(host->base, CAPA);
240 OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
242 /* Set the controller to AUTO IDLE mode */
243 value = OMAP_HSMMC_READ(host->base, SYSCONFIG);
244 - OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE);
245 + OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE | ENAWAKEUP);
247 /* Set SD bus power bit */
248 set_sd_bus_power(host);
249 @@ -1918,7 +1965,7 @@ static const struct mmc_host_ops omap_hsmmc_ops = {
250 .get_cd = omap_hsmmc_get_cd,
251 .get_ro = omap_hsmmc_get_ro,
252 .init_card = omap_hsmmc_init_card,
253 - /* NYET -- enable_sdio_irq */
254 + .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
257 static const struct mmc_host_ops omap_hsmmc_ps_ops = {
258 @@ -1929,7 +1976,7 @@ static const struct mmc_host_ops omap_hsmmc_ps_ops = {
259 .get_cd = omap_hsmmc_get_cd,
260 .get_ro = omap_hsmmc_get_ro,
261 .init_card = omap_hsmmc_init_card,
262 - /* NYET -- enable_sdio_irq */
263 + .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
266 #ifdef CONFIG_DEBUG_FS
267 @@ -2145,7 +2192,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
268 mmc->max_seg_size = mmc->max_req_size;
270 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
271 - MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
272 + MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE |
273 + MMC_CAP_SDIO_IRQ;
275 mmc->caps |= mmc_slot(host).caps;
276 if (mmc->caps & MMC_CAP_8_BIT_DATA)
277 @@ -2224,7 +2272,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
278 pdata->resume = omap_hsmmc_resume_cdirq;
281 - OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
282 + OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK | CIRQ);
283 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
285 mmc_host_lazy_disable(host->mmc);
287 1.6.6.1