diff options
author | Arnd Hannemann <arnd@arndnet.de> | 2010-12-28 17:22:31 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-01-08 23:52:30 -0500 |
commit | 845ecd20239c28e97e766ff54078a58be19f3a91 (patch) | |
tree | ac25a1b5e5769c9207c9fd886acd4380a3184701 /drivers/mmc | |
parent | 39a65a0dbbf73403daa9f4cc0ab30957ba61e60f (diff) |
mmc: tmio_mmc: implement SDIO IRQ support
This patch implements SDIO IRQ support for mfds which
announce the TMIO_MMC_SDIO_IRQ flag for tmio_mmc.
If MMC_CAP_SDIO_IRQ is also set SDIO IRQ signalling is activated.
Tested with a b43-based wireless SDIO card and sh_mobile_sdhi.
Signed-off-by: Arnd Hannemann <arnd@arndnet.de>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/tmio_mmc.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index f442c8205b0a..81bed310ddcd 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c | |||
@@ -53,6 +53,8 @@ | |||
53 | #define CTL_SD_ERROR_DETAIL_STATUS 0x2c | 53 | #define CTL_SD_ERROR_DETAIL_STATUS 0x2c |
54 | #define CTL_SD_DATA_PORT 0x30 | 54 | #define CTL_SD_DATA_PORT 0x30 |
55 | #define CTL_TRANSACTION_CTL 0x34 | 55 | #define CTL_TRANSACTION_CTL 0x34 |
56 | #define CTL_SDIO_STATUS 0x36 | ||
57 | #define CTL_SDIO_IRQ_MASK 0x38 | ||
56 | #define CTL_RESET_SD 0xe0 | 58 | #define CTL_RESET_SD 0xe0 |
57 | #define CTL_SDIO_REGS 0x100 | 59 | #define CTL_SDIO_REGS 0x100 |
58 | #define CTL_CLK_AND_WAIT_CTL 0x138 | 60 | #define CTL_CLK_AND_WAIT_CTL 0x138 |
@@ -81,6 +83,12 @@ | |||
81 | #define TMIO_STAT_CMD_BUSY 0x40000000 | 83 | #define TMIO_STAT_CMD_BUSY 0x40000000 |
82 | #define TMIO_STAT_ILL_ACCESS 0x80000000 | 84 | #define TMIO_STAT_ILL_ACCESS 0x80000000 |
83 | 85 | ||
86 | /* Definitions for values the CTRL_SDIO_STATUS register can take. */ | ||
87 | #define TMIO_SDIO_STAT_IOIRQ 0x0001 | ||
88 | #define TMIO_SDIO_STAT_EXPUB52 0x4000 | ||
89 | #define TMIO_SDIO_STAT_EXWT 0x8000 | ||
90 | #define TMIO_SDIO_MASK_ALL 0xc007 | ||
91 | |||
84 | /* Define some IRQ masks */ | 92 | /* Define some IRQ masks */ |
85 | /* This is the mask used at reset by the chip */ | 93 | /* This is the mask used at reset by the chip */ |
86 | #define TMIO_MASK_ALL 0x837f031d | 94 | #define TMIO_MASK_ALL 0x837f031d |
@@ -122,6 +130,7 @@ struct tmio_mmc_host { | |||
122 | struct mmc_data *data; | 130 | struct mmc_data *data; |
123 | struct mmc_host *mmc; | 131 | struct mmc_host *mmc; |
124 | int irq; | 132 | int irq; |
133 | unsigned int sdio_irq_enabled; | ||
125 | 134 | ||
126 | /* Callbacks for clock / power control */ | 135 | /* Callbacks for clock / power control */ |
127 | void (*set_pwr)(struct platform_device *host, int state); | 136 | void (*set_pwr)(struct platform_device *host, int state); |
@@ -249,6 +258,22 @@ void pr_debug_status(u32 status) | |||
249 | #define pr_debug_status(s) do { } while (0) | 258 | #define pr_debug_status(s) do { } while (0) |
250 | #endif | 259 | #endif |
251 | 260 | ||
261 | static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) | ||
262 | { | ||
263 | struct tmio_mmc_host *host = mmc_priv(mmc); | ||
264 | |||
265 | if (enable) { | ||
266 | host->sdio_irq_enabled = 1; | ||
267 | sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); | ||
268 | sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, | ||
269 | (TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ)); | ||
270 | } else { | ||
271 | sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL); | ||
272 | sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000); | ||
273 | host->sdio_irq_enabled = 0; | ||
274 | } | ||
275 | } | ||
276 | |||
252 | static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) | 277 | static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) |
253 | { | 278 | { |
254 | u32 clk = 0, clock; | 279 | u32 clk = 0, clock; |
@@ -268,8 +293,23 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) | |||
268 | 293 | ||
269 | static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) | 294 | static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) |
270 | { | 295 | { |
296 | struct mfd_cell *cell = host->pdev->dev.platform_data; | ||
297 | struct tmio_mmc_data *pdata = cell->driver_data; | ||
298 | |||
299 | /* | ||
300 | * Testing on sh-mobile showed that SDIO IRQs are unmasked when | ||
301 | * CTL_CLK_AND_WAIT_CTL gets written, so we have to disable the | ||
302 | * device IRQ here and restore the SDIO IRQ mask before | ||
303 | * re-enabling the device IRQ. | ||
304 | */ | ||
305 | if (pdata->flags & TMIO_MMC_SDIO_IRQ) | ||
306 | disable_irq(host->irq); | ||
271 | sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); | 307 | sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); |
272 | msleep(10); | 308 | msleep(10); |
309 | if (pdata->flags & TMIO_MMC_SDIO_IRQ) { | ||
310 | tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); | ||
311 | enable_irq(host->irq); | ||
312 | } | ||
273 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & | 313 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & |
274 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | 314 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); |
275 | msleep(10); | 315 | msleep(10); |
@@ -277,11 +317,21 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) | |||
277 | 317 | ||
278 | static void tmio_mmc_clk_start(struct tmio_mmc_host *host) | 318 | static void tmio_mmc_clk_start(struct tmio_mmc_host *host) |
279 | { | 319 | { |
320 | struct mfd_cell *cell = host->pdev->dev.platform_data; | ||
321 | struct tmio_mmc_data *pdata = cell->driver_data; | ||
322 | |||
280 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | | 323 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | |
281 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | 324 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); |
282 | msleep(10); | 325 | msleep(10); |
326 | /* see comment in tmio_mmc_clk_stop above */ | ||
327 | if (pdata->flags & TMIO_MMC_SDIO_IRQ) | ||
328 | disable_irq(host->irq); | ||
283 | sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); | 329 | sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); |
284 | msleep(10); | 330 | msleep(10); |
331 | if (pdata->flags & TMIO_MMC_SDIO_IRQ) { | ||
332 | tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); | ||
333 | enable_irq(host->irq); | ||
334 | } | ||
285 | } | 335 | } |
286 | 336 | ||
287 | static void reset(struct tmio_mmc_host *host) | 337 | static void reset(struct tmio_mmc_host *host) |
@@ -554,7 +604,10 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, | |||
554 | static irqreturn_t tmio_mmc_irq(int irq, void *devid) | 604 | static irqreturn_t tmio_mmc_irq(int irq, void *devid) |
555 | { | 605 | { |
556 | struct tmio_mmc_host *host = devid; | 606 | struct tmio_mmc_host *host = devid; |
607 | struct mfd_cell *cell = host->pdev->dev.platform_data; | ||
608 | struct tmio_mmc_data *pdata = cell->driver_data; | ||
557 | unsigned int ireg, irq_mask, status; | 609 | unsigned int ireg, irq_mask, status; |
610 | unsigned int sdio_ireg, sdio_irq_mask, sdio_status; | ||
558 | 611 | ||
559 | pr_debug("MMC IRQ begin\n"); | 612 | pr_debug("MMC IRQ begin\n"); |
560 | 613 | ||
@@ -562,6 +615,29 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid) | |||
562 | irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); | 615 | irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); |
563 | ireg = status & TMIO_MASK_IRQ & ~irq_mask; | 616 | ireg = status & TMIO_MASK_IRQ & ~irq_mask; |
564 | 617 | ||
618 | sdio_ireg = 0; | ||
619 | if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) { | ||
620 | sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS); | ||
621 | sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK); | ||
622 | sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask; | ||
623 | |||
624 | sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL); | ||
625 | |||
626 | if (sdio_ireg && !host->sdio_irq_enabled) { | ||
627 | pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n", | ||
628 | sdio_status, sdio_irq_mask, sdio_ireg); | ||
629 | tmio_mmc_enable_sdio_irq(host->mmc, 0); | ||
630 | goto out; | ||
631 | } | ||
632 | |||
633 | if (host->mmc->caps & MMC_CAP_SDIO_IRQ && | ||
634 | sdio_ireg & TMIO_SDIO_STAT_IOIRQ) | ||
635 | mmc_signal_sdio_irq(host->mmc); | ||
636 | |||
637 | if (sdio_ireg) | ||
638 | goto out; | ||
639 | } | ||
640 | |||
565 | pr_debug_status(status); | 641 | pr_debug_status(status); |
566 | pr_debug_status(ireg); | 642 | pr_debug_status(ireg); |
567 | 643 | ||
@@ -1047,6 +1123,7 @@ static const struct mmc_host_ops tmio_mmc_ops = { | |||
1047 | .set_ios = tmio_mmc_set_ios, | 1123 | .set_ios = tmio_mmc_set_ios, |
1048 | .get_ro = tmio_mmc_get_ro, | 1124 | .get_ro = tmio_mmc_get_ro, |
1049 | .get_cd = tmio_mmc_get_cd, | 1125 | .get_cd = tmio_mmc_get_cd, |
1126 | .enable_sdio_irq = tmio_mmc_enable_sdio_irq, | ||
1050 | }; | 1127 | }; |
1051 | 1128 | ||
1052 | #ifdef CONFIG_PM | 1129 | #ifdef CONFIG_PM |
@@ -1162,6 +1239,8 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) | |||
1162 | goto cell_disable; | 1239 | goto cell_disable; |
1163 | 1240 | ||
1164 | disable_mmc_irqs(host, TMIO_MASK_ALL); | 1241 | disable_mmc_irqs(host, TMIO_MASK_ALL); |
1242 | if (pdata->flags & TMIO_MMC_SDIO_IRQ) | ||
1243 | tmio_mmc_enable_sdio_irq(mmc, 0); | ||
1165 | 1244 | ||
1166 | ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED | | 1245 | ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED | |
1167 | IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host); | 1246 | IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host); |