aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/s3cmci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/s3cmci.c')
-rw-r--r--drivers/mmc/host/s3cmci.c161
1 files changed, 151 insertions, 10 deletions
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index 8c2c8b456087..7660ac4572e5 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -190,7 +190,33 @@ static inline u32 disable_imask(struct s3cmci_host *host, u32 imask)
190 190
191static inline void clear_imask(struct s3cmci_host *host) 191static inline void clear_imask(struct s3cmci_host *host)
192{ 192{
193 writel(0, host->base + host->sdiimsk); 193 u32 mask = readl(host->base + host->sdiimsk);
194
195 /* preserve the SDIO IRQ mask state */
196 mask &= S3C2410_SDIIMSK_SDIOIRQ;
197 writel(mask, host->base + host->sdiimsk);
198}
199
200/**
201 * s3cmci_check_sdio_irq - test whether the SDIO IRQ is being signalled
202 * @host: The host to check.
203 *
204 * Test to see if the SDIO interrupt is being signalled in case the
205 * controller has failed to re-detect a card interrupt. Read GPE8 and
206 * see if it is low and if so, signal a SDIO interrupt.
207 *
208 * This is currently called if a request is finished (we assume that the
209 * bus is now idle) and when the SDIO IRQ is enabled in case the IRQ is
210 * already being indicated.
211*/
212static void s3cmci_check_sdio_irq(struct s3cmci_host *host)
213{
214 if (host->sdio_irqen) {
215 if (gpio_get_value(S3C2410_GPE(8)) == 0) {
216 printk(KERN_DEBUG "%s: signalling irq\n", __func__);
217 mmc_signal_sdio_irq(host->mmc);
218 }
219 }
194} 220}
195 221
196static inline int get_data_buffer(struct s3cmci_host *host, 222static inline int get_data_buffer(struct s3cmci_host *host,
@@ -238,6 +264,64 @@ static inline u32 fifo_free(struct s3cmci_host *host)
238 return 63 - fifostat; 264 return 63 - fifostat;
239} 265}
240 266
267/**
268 * s3cmci_enable_irq - enable IRQ, after having disabled it.
269 * @host: The device state.
270 * @more: True if more IRQs are expected from transfer.
271 *
272 * Enable the main IRQ if needed after it has been disabled.
273 *
274 * The IRQ can be one of the following states:
275 * - disabled during IDLE
276 * - disabled whilst processing data
277 * - enabled during transfer
278 * - enabled whilst awaiting SDIO interrupt detection
279 */
280static void s3cmci_enable_irq(struct s3cmci_host *host, bool more)
281{
282 unsigned long flags;
283 bool enable = false;
284
285 local_irq_save(flags);
286
287 host->irq_enabled = more;
288 host->irq_disabled = false;
289
290 enable = more | host->sdio_irqen;
291
292 if (host->irq_state != enable) {
293 host->irq_state = enable;
294
295 if (enable)
296 enable_irq(host->irq);
297 else
298 disable_irq(host->irq);
299 }
300
301 local_irq_restore(flags);
302}
303
304/**
305 *
306 */
307static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer)
308{
309 unsigned long flags;
310
311 local_irq_save(flags);
312
313 //printk(KERN_DEBUG "%s: transfer %d\n", __func__, transfer);
314
315 host->irq_disabled = transfer;
316
317 if (transfer && host->irq_state) {
318 host->irq_state = false;
319 disable_irq(host->irq);
320 }
321
322 local_irq_restore(flags);
323}
324
241static void do_pio_read(struct s3cmci_host *host) 325static void do_pio_read(struct s3cmci_host *host)
242{ 326{
243 int res; 327 int res;
@@ -374,8 +458,7 @@ static void pio_tasklet(unsigned long data)
374{ 458{
375 struct s3cmci_host *host = (struct s3cmci_host *) data; 459 struct s3cmci_host *host = (struct s3cmci_host *) data;
376 460
377 461 s3cmci_disable_irq(host, true);
378 disable_irq(host->irq);
379 462
380 if (host->pio_active == XFER_WRITE) 463 if (host->pio_active == XFER_WRITE)
381 do_pio_write(host); 464 do_pio_write(host);
@@ -395,9 +478,10 @@ static void pio_tasklet(unsigned long data)
395 host->mrq->data->error = -EINVAL; 478 host->mrq->data->error = -EINVAL;
396 } 479 }
397 480
481 s3cmci_enable_irq(host, false);
398 finalize_request(host); 482 finalize_request(host);
399 } else 483 } else
400 enable_irq(host->irq); 484 s3cmci_enable_irq(host, true);
401} 485}
402 486
403/* 487/*
@@ -432,17 +516,27 @@ static irqreturn_t s3cmci_irq(int irq, void *dev_id)
432 struct s3cmci_host *host = dev_id; 516 struct s3cmci_host *host = dev_id;
433 struct mmc_command *cmd; 517 struct mmc_command *cmd;
434 u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk; 518 u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk;
435 u32 mci_cclear, mci_dclear; 519 u32 mci_cclear = 0, mci_dclear;
436 unsigned long iflags; 520 unsigned long iflags;
437 521
522 mci_dsta = readl(host->base + S3C2410_SDIDSTA);
523 mci_imsk = readl(host->base + host->sdiimsk);
524
525 if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) {
526 if (mci_imsk & S3C2410_SDIIMSK_SDIOIRQ) {
527 mci_dclear = S3C2410_SDIDSTA_SDIOIRQDETECT;
528 writel(mci_dclear, host->base + S3C2410_SDIDSTA);
529
530 mmc_signal_sdio_irq(host->mmc);
531 return IRQ_HANDLED;
532 }
533 }
534
438 spin_lock_irqsave(&host->complete_lock, iflags); 535 spin_lock_irqsave(&host->complete_lock, iflags);
439 536
440 mci_csta = readl(host->base + S3C2410_SDICMDSTAT); 537 mci_csta = readl(host->base + S3C2410_SDICMDSTAT);
441 mci_dsta = readl(host->base + S3C2410_SDIDSTA);
442 mci_dcnt = readl(host->base + S3C2410_SDIDCNT); 538 mci_dcnt = readl(host->base + S3C2410_SDIDCNT);
443 mci_fsta = readl(host->base + S3C2410_SDIFSTA); 539 mci_fsta = readl(host->base + S3C2410_SDIFSTA);
444 mci_imsk = readl(host->base + host->sdiimsk);
445 mci_cclear = 0;
446 mci_dclear = 0; 540 mci_dclear = 0;
447 541
448 if ((host->complete_what == COMPLETION_NONE) || 542 if ((host->complete_what == COMPLETION_NONE) ||
@@ -776,6 +870,8 @@ static void finalize_request(struct s3cmci_host *host)
776request_done: 870request_done:
777 host->complete_what = COMPLETION_NONE; 871 host->complete_what = COMPLETION_NONE;
778 host->mrq = NULL; 872 host->mrq = NULL;
873
874 s3cmci_check_sdio_irq(host);
779 mmc_request_done(host->mmc, mrq); 875 mmc_request_done(host->mmc, mrq);
780} 876}
781 877
@@ -1037,7 +1133,7 @@ static void s3cmci_send_request(struct mmc_host *mmc)
1037 s3cmci_send_command(host, cmd); 1133 s3cmci_send_command(host, cmd);
1038 1134
1039 /* Enable Interrupt */ 1135 /* Enable Interrupt */
1040 enable_irq(host->irq); 1136 s3cmci_enable_irq(host, true);
1041} 1137}
1042 1138
1043static int s3cmci_card_present(struct mmc_host *mmc) 1139static int s3cmci_card_present(struct mmc_host *mmc)
@@ -1178,11 +1274,52 @@ static int s3cmci_get_ro(struct mmc_host *mmc)
1178 return ret; 1274 return ret;
1179} 1275}
1180 1276
1277static void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
1278{
1279 struct s3cmci_host *host = mmc_priv(mmc);
1280 unsigned long flags;
1281 u32 con;
1282
1283 local_irq_save(flags);
1284
1285 con = readl(host->base + S3C2410_SDICON);
1286 host->sdio_irqen = enable;
1287
1288 if (enable == host->sdio_irqen)
1289 goto same_state;
1290
1291 if (enable) {
1292 con |= S3C2410_SDICON_SDIOIRQ;
1293 enable_imask(host, S3C2410_SDIIMSK_SDIOIRQ);
1294
1295 if (!host->irq_state && !host->irq_disabled) {
1296 host->irq_state = true;
1297 enable_irq(host->irq);
1298 }
1299 } else {
1300 disable_imask(host, S3C2410_SDIIMSK_SDIOIRQ);
1301 con &= ~S3C2410_SDICON_SDIOIRQ;
1302
1303 if (!host->irq_enabled && host->irq_state) {
1304 disable_irq_nosync(host->irq);
1305 host->irq_state = false;
1306 }
1307 }
1308
1309 writel(con, host->base + S3C2410_SDICON);
1310
1311 same_state:
1312 local_irq_restore(flags);
1313
1314 s3cmci_check_sdio_irq(host);
1315}
1316
1181static struct mmc_host_ops s3cmci_ops = { 1317static struct mmc_host_ops s3cmci_ops = {
1182 .request = s3cmci_request, 1318 .request = s3cmci_request,
1183 .set_ios = s3cmci_set_ios, 1319 .set_ios = s3cmci_set_ios,
1184 .get_ro = s3cmci_get_ro, 1320 .get_ro = s3cmci_get_ro,
1185 .get_cd = s3cmci_card_present, 1321 .get_cd = s3cmci_card_present,
1322 .enable_sdio_irq = s3cmci_enable_sdio_irq,
1186}; 1323};
1187 1324
1188static struct s3c24xx_mci_pdata s3cmci_def_pdata = { 1325static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
@@ -1257,6 +1394,9 @@ static int s3cmci_state_show(struct seq_file *seq, void *v)
1257 seq_printf(seq, "Prescale = %d\n", host->prescaler); 1394 seq_printf(seq, "Prescale = %d\n", host->prescaler);
1258 seq_printf(seq, "is2440 = %d\n", host->is2440); 1395 seq_printf(seq, "is2440 = %d\n", host->is2440);
1259 seq_printf(seq, "IRQ = %d\n", host->irq); 1396 seq_printf(seq, "IRQ = %d\n", host->irq);
1397 seq_printf(seq, "IRQ enabled = %d\n", host->irq_enabled);
1398 seq_printf(seq, "IRQ disabled = %d\n", host->irq_disabled);
1399 seq_printf(seq, "IRQ state = %d\n", host->irq_state);
1260 seq_printf(seq, "CD IRQ = %d\n", host->irq_cd); 1400 seq_printf(seq, "CD IRQ = %d\n", host->irq_cd);
1261 seq_printf(seq, "Do DMA = %d\n", host->dodma); 1401 seq_printf(seq, "Do DMA = %d\n", host->dodma);
1262 seq_printf(seq, "SDIIMSK at %d\n", host->sdiimsk); 1402 seq_printf(seq, "SDIIMSK at %d\n", host->sdiimsk);
@@ -1468,6 +1608,7 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
1468 * ensure we don't lock the system with un-serviceable requests. */ 1608 * ensure we don't lock the system with un-serviceable requests. */
1469 1609
1470 disable_irq(host->irq); 1610 disable_irq(host->irq);
1611 host->irq_state = false;
1471 1612
1472 if (host->pdata->gpio_detect) { 1613 if (host->pdata->gpio_detect) {
1473 ret = gpio_request(host->pdata->gpio_detect, "s3cmci detect"); 1614 ret = gpio_request(host->pdata->gpio_detect, "s3cmci detect");
@@ -1526,7 +1667,7 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
1526 1667
1527 mmc->ops = &s3cmci_ops; 1668 mmc->ops = &s3cmci_ops;
1528 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 1669 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
1529 mmc->caps = MMC_CAP_4_BIT_DATA; 1670 mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
1530 mmc->f_min = host->clk_rate / (host->clk_div * 256); 1671 mmc->f_min = host->clk_rate / (host->clk_div * 256);
1531 mmc->f_max = host->clk_rate / host->clk_div; 1672 mmc->f_max = host->clk_rate / host->clk_div;
1532 1673