diff options
Diffstat (limited to 'drivers/mmc/host/msm_sdcc.c')
-rw-r--r-- | drivers/mmc/host/msm_sdcc.c | 267 |
1 files changed, 148 insertions, 119 deletions
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 84b284e3a28..52485859790 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2007 Google Inc, | 4 | * Copyright (C) 2007 Google Inc, |
5 | * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. | 5 | * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. |
6 | * Copyright (C) 2009, Code Aurora Forum. All Rights Reserved. | ||
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
@@ -47,6 +48,7 @@ | |||
47 | 48 | ||
48 | #define DRIVER_NAME "msm-sdcc" | 49 | #define DRIVER_NAME "msm-sdcc" |
49 | 50 | ||
51 | #define BUSCLK_TIMEOUT (HZ * 5) | ||
50 | static unsigned int msmsdcc_fmin = 144000; | 52 | static unsigned int msmsdcc_fmin = 144000; |
51 | static unsigned int msmsdcc_fmax = 50000000; | 53 | static unsigned int msmsdcc_fmax = 50000000; |
52 | static unsigned int msmsdcc_4bit = 1; | 54 | static unsigned int msmsdcc_4bit = 1; |
@@ -106,8 +108,6 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, | |||
106 | static void | 108 | static void |
107 | msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) | 109 | msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) |
108 | { | 110 | { |
109 | msmsdcc_writel(host, 0, MMCICOMMAND); | ||
110 | |||
111 | BUG_ON(host->curr.data); | 111 | BUG_ON(host->curr.data); |
112 | 112 | ||
113 | host->curr.mrq = NULL; | 113 | host->curr.mrq = NULL; |
@@ -119,7 +119,7 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) | |||
119 | mdelay(5); | 119 | mdelay(5); |
120 | 120 | ||
121 | if (host->use_bustimer) | 121 | if (host->use_bustimer) |
122 | mod_timer(&host->busclk_timer, jiffies + HZ); | 122 | mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); |
123 | /* | 123 | /* |
124 | * Need to drop the host lock here; mmc_request_done may call | 124 | * Need to drop the host lock here; mmc_request_done may call |
125 | * back into the driver... | 125 | * back into the driver... |
@@ -132,7 +132,6 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) | |||
132 | static void | 132 | static void |
133 | msmsdcc_stop_data(struct msmsdcc_host *host) | 133 | msmsdcc_stop_data(struct msmsdcc_host *host) |
134 | { | 134 | { |
135 | msmsdcc_writel(host, 0, MMCIDATACTRL); | ||
136 | host->curr.data = NULL; | 135 | host->curr.data = NULL; |
137 | host->curr.got_dataend = host->curr.got_datablkend = 0; | 136 | host->curr.got_dataend = host->curr.got_datablkend = 0; |
138 | } | 137 | } |
@@ -153,6 +152,29 @@ uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) | |||
153 | return 0; | 152 | return 0; |
154 | } | 153 | } |
155 | 154 | ||
155 | static inline void | ||
156 | msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) { | ||
157 | msmsdcc_writel(host, arg, MMCIARGUMENT); | ||
158 | msmsdcc_writel(host, c, MMCICOMMAND); | ||
159 | } | ||
160 | |||
161 | static void | ||
162 | msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) | ||
163 | { | ||
164 | struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data; | ||
165 | |||
166 | writel(host->cmd_timeout, host->base + MMCIDATATIMER); | ||
167 | writel((unsigned int)host->curr.xfer_size, host->base + MMCIDATALENGTH); | ||
168 | writel(host->cmd_pio_irqmask, host->base + MMCIMASK1); | ||
169 | writel(host->cmd_datactrl, host->base + MMCIDATACTRL); | ||
170 | |||
171 | if (host->cmd_cmd) { | ||
172 | msmsdcc_start_command_exec(host, | ||
173 | (u32)host->cmd_cmd->arg, (u32)host->cmd_c); | ||
174 | } | ||
175 | host->dma.active = 1; | ||
176 | } | ||
177 | |||
156 | static void | 178 | static void |
157 | msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | 179 | msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, |
158 | unsigned int result, | 180 | unsigned int result, |
@@ -165,6 +187,8 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | |||
165 | struct mmc_request *mrq; | 187 | struct mmc_request *mrq; |
166 | 188 | ||
167 | spin_lock_irqsave(&host->lock, flags); | 189 | spin_lock_irqsave(&host->lock, flags); |
190 | host->dma.active = 0; | ||
191 | |||
168 | mrq = host->curr.mrq; | 192 | mrq = host->curr.mrq; |
169 | BUG_ON(!mrq); | 193 | BUG_ON(!mrq); |
170 | 194 | ||
@@ -190,7 +214,6 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | |||
190 | if (!mrq->data->error) | 214 | if (!mrq->data->error) |
191 | mrq->data->error = -EIO; | 215 | mrq->data->error = -EIO; |
192 | } | 216 | } |
193 | host->dma.busy = 0; | ||
194 | dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, | 217 | dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, |
195 | host->dma.dir); | 218 | host->dma.dir); |
196 | 219 | ||
@@ -203,6 +226,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | |||
203 | } | 226 | } |
204 | 227 | ||
205 | host->dma.sg = NULL; | 228 | host->dma.sg = NULL; |
229 | host->dma.busy = 0; | ||
206 | 230 | ||
207 | if ((host->curr.got_dataend && host->curr.got_datablkend) | 231 | if ((host->curr.got_dataend && host->curr.got_datablkend) |
208 | || mrq->data->error) { | 232 | || mrq->data->error) { |
@@ -262,6 +286,8 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) | |||
262 | host->dma.sg = data->sg; | 286 | host->dma.sg = data->sg; |
263 | host->dma.num_ents = data->sg_len; | 287 | host->dma.num_ents = data->sg_len; |
264 | 288 | ||
289 | BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */ | ||
290 | |||
265 | nc = host->dma.nc; | 291 | nc = host->dma.nc; |
266 | 292 | ||
267 | switch (host->pdev_id) { | 293 | switch (host->pdev_id) { |
@@ -290,22 +316,15 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) | |||
290 | 316 | ||
291 | host->curr.user_pages = 0; | 317 | host->curr.user_pages = 0; |
292 | 318 | ||
293 | n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, | ||
294 | host->dma.num_ents, host->dma.dir); | ||
295 | |||
296 | if (n != host->dma.num_ents) { | ||
297 | pr_err("%s: Unable to map in all sg elements\n", | ||
298 | mmc_hostname(host->mmc)); | ||
299 | host->dma.sg = NULL; | ||
300 | host->dma.num_ents = 0; | ||
301 | return -ENOMEM; | ||
302 | } | ||
303 | |||
304 | box = &nc->cmd[0]; | 319 | box = &nc->cmd[0]; |
305 | for (i = 0; i < host->dma.num_ents; i++) { | 320 | for (i = 0; i < host->dma.num_ents; i++) { |
306 | box->cmd = CMD_MODE_BOX; | 321 | box->cmd = CMD_MODE_BOX; |
307 | 322 | ||
308 | if (i == (host->dma.num_ents - 1)) | 323 | /* Initialize sg dma address */ |
324 | sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg)) | ||
325 | + sg->offset; | ||
326 | |||
327 | if (i == (host->dma.num_ents - 1)) | ||
309 | box->cmd |= CMD_LC; | 328 | box->cmd |= CMD_LC; |
310 | rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? | 329 | rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? |
311 | (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : | 330 | (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : |
@@ -343,13 +362,68 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) | |||
343 | host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | | 362 | host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | |
344 | DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); | 363 | DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); |
345 | host->dma.hdr.complete_func = msmsdcc_dma_complete_func; | 364 | host->dma.hdr.complete_func = msmsdcc_dma_complete_func; |
346 | host->dma.hdr.execute_func = NULL; | ||
347 | 365 | ||
366 | n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, | ||
367 | host->dma.num_ents, host->dma.dir); | ||
368 | /* dsb inside dma_map_sg will write nc out to mem as well */ | ||
369 | |||
370 | if (n != host->dma.num_ents) { | ||
371 | printk(KERN_ERR "%s: Unable to map in all sg elements\n", | ||
372 | mmc_hostname(host->mmc)); | ||
373 | host->dma.sg = NULL; | ||
374 | host->dma.num_ents = 0; | ||
375 | return -ENOMEM; | ||
376 | } | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static int | ||
382 | snoop_cccr_abort(struct mmc_command *cmd) | ||
383 | { | ||
384 | if ((cmd->opcode == 52) && | ||
385 | (cmd->arg & 0x80000000) && | ||
386 | (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) | ||
387 | return 1; | ||
348 | return 0; | 388 | return 0; |
349 | } | 389 | } |
350 | 390 | ||
351 | static void | 391 | static void |
352 | msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) | 392 | msmsdcc_start_command_deferred(struct msmsdcc_host *host, |
393 | struct mmc_command *cmd, u32 *c) | ||
394 | { | ||
395 | *c |= (cmd->opcode | MCI_CPSM_ENABLE); | ||
396 | |||
397 | if (cmd->flags & MMC_RSP_PRESENT) { | ||
398 | if (cmd->flags & MMC_RSP_136) | ||
399 | *c |= MCI_CPSM_LONGRSP; | ||
400 | *c |= MCI_CPSM_RESPONSE; | ||
401 | } | ||
402 | |||
403 | if (/*interrupt*/0) | ||
404 | *c |= MCI_CPSM_INTERRUPT; | ||
405 | |||
406 | if ((((cmd->opcode == 17) || (cmd->opcode == 18)) || | ||
407 | ((cmd->opcode == 24) || (cmd->opcode == 25))) || | ||
408 | (cmd->opcode == 53)) | ||
409 | *c |= MCI_CSPM_DATCMD; | ||
410 | |||
411 | if (cmd == cmd->mrq->stop) | ||
412 | *c |= MCI_CSPM_MCIABORT; | ||
413 | |||
414 | if (snoop_cccr_abort(cmd)) | ||
415 | *c |= MCI_CSPM_MCIABORT; | ||
416 | |||
417 | if (host->curr.cmd != NULL) { | ||
418 | printk(KERN_ERR "%s: Overlapping command requests\n", | ||
419 | mmc_hostname(host->mmc)); | ||
420 | } | ||
421 | host->curr.cmd = cmd; | ||
422 | } | ||
423 | |||
424 | static void | ||
425 | msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, | ||
426 | struct mmc_command *cmd, u32 c) | ||
353 | { | 427 | { |
354 | unsigned int datactrl, timeout; | 428 | unsigned int datactrl, timeout; |
355 | unsigned long long clks; | 429 | unsigned long long clks; |
@@ -364,13 +438,6 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) | |||
364 | 438 | ||
365 | memset(&host->pio, 0, sizeof(host->pio)); | 439 | memset(&host->pio, 0, sizeof(host->pio)); |
366 | 440 | ||
367 | clks = (unsigned long long)data->timeout_ns * host->clk_rate; | ||
368 | do_div(clks, NSEC_PER_SEC); | ||
369 | timeout = data->timeout_clks + (unsigned int)clks; | ||
370 | msmsdcc_writel(host, timeout, MMCIDATATIMER); | ||
371 | |||
372 | msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); | ||
373 | |||
374 | datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); | 441 | datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); |
375 | 442 | ||
376 | if (!msmsdcc_config_dma(host, data)) | 443 | if (!msmsdcc_config_dma(host, data)) |
@@ -391,56 +458,51 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) | |||
391 | if (data->flags & MMC_DATA_READ) | 458 | if (data->flags & MMC_DATA_READ) |
392 | datactrl |= MCI_DPSM_DIRECTION; | 459 | datactrl |= MCI_DPSM_DIRECTION; |
393 | 460 | ||
394 | msmsdcc_writel(host, pio_irqmask, MMCIMASK1); | 461 | clks = (unsigned long long)data->timeout_ns * host->clk_rate; |
395 | msmsdcc_writel(host, datactrl, MMCIDATACTRL); | 462 | do_div(clks, NSEC_PER_SEC); |
463 | timeout = data->timeout_clks + (unsigned int)clks*2 ; | ||
396 | 464 | ||
397 | if (datactrl & MCI_DPSM_DMAENABLE) { | 465 | if (datactrl & MCI_DPSM_DMAENABLE) { |
466 | /* Save parameters for the exec function */ | ||
467 | host->cmd_timeout = timeout; | ||
468 | host->cmd_pio_irqmask = pio_irqmask; | ||
469 | host->cmd_datactrl = datactrl; | ||
470 | host->cmd_cmd = cmd; | ||
471 | |||
472 | host->dma.hdr.execute_func = msmsdcc_dma_exec_func; | ||
473 | host->dma.hdr.data = (void *)host; | ||
398 | host->dma.busy = 1; | 474 | host->dma.busy = 1; |
475 | |||
476 | if (cmd) { | ||
477 | msmsdcc_start_command_deferred(host, cmd, &c); | ||
478 | host->cmd_c = c; | ||
479 | } | ||
399 | msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); | 480 | msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); |
400 | } | 481 | } else { |
401 | } | 482 | msmsdcc_writel(host, timeout, MMCIDATATIMER); |
402 | 483 | ||
403 | static int | 484 | msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); |
404 | snoop_cccr_abort(struct mmc_command *cmd) | 485 | |
405 | { | 486 | msmsdcc_writel(host, pio_irqmask, MMCIMASK1); |
406 | if ((cmd->opcode == 52) && | 487 | msmsdcc_writel(host, datactrl, MMCIDATACTRL); |
407 | (cmd->arg & 0x80000000) && | 488 | |
408 | (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) | 489 | if (cmd) { |
409 | return 1; | 490 | /* Daisy-chain the command if requested */ |
410 | return 0; | 491 | msmsdcc_start_command(host, cmd, c); |
492 | } | ||
493 | } | ||
411 | } | 494 | } |
412 | 495 | ||
413 | static void | 496 | static void |
414 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) | 497 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) |
415 | { | 498 | { |
416 | if (msmsdcc_readl(host, MMCICOMMAND) & MCI_CPSM_ENABLE) | ||
417 | msmsdcc_writel(host, 0, MMCICOMMAND); | ||
418 | |||
419 | c |= cmd->opcode | MCI_CPSM_ENABLE; | ||
420 | |||
421 | if (cmd->flags & MMC_RSP_PRESENT) { | ||
422 | if (cmd->flags & MMC_RSP_136) | ||
423 | c |= MCI_CPSM_LONGRSP; | ||
424 | c |= MCI_CPSM_RESPONSE; | ||
425 | } | ||
426 | |||
427 | if (cmd->opcode == 17 || cmd->opcode == 18 || | ||
428 | cmd->opcode == 24 || cmd->opcode == 25 || | ||
429 | cmd->opcode == 53) | ||
430 | c |= MCI_CSPM_DATCMD; | ||
431 | |||
432 | if (cmd == cmd->mrq->stop) | 499 | if (cmd == cmd->mrq->stop) |
433 | c |= MCI_CSPM_MCIABORT; | 500 | c |= MCI_CSPM_MCIABORT; |
434 | 501 | ||
435 | if (snoop_cccr_abort(cmd)) | ||
436 | c |= MCI_CSPM_MCIABORT; | ||
437 | |||
438 | host->curr.cmd = cmd; | ||
439 | |||
440 | host->stats.cmds++; | 502 | host->stats.cmds++; |
441 | 503 | ||
442 | msmsdcc_writel(host, cmd->arg, MMCIARGUMENT); | 504 | msmsdcc_start_command_deferred(host, cmd, &c); |
443 | msmsdcc_writel(host, c, MMCICOMMAND); | 505 | msmsdcc_start_command_exec(host, cmd->arg, c); |
444 | } | 506 | } |
445 | 507 | ||
446 | static void | 508 | static void |
@@ -611,7 +673,6 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) | |||
611 | cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); | 673 | cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); |
612 | cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); | 674 | cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); |
613 | 675 | ||
614 | del_timer(&host->command_timer); | ||
615 | if (status & MCI_CMDTIMEOUT) { | 676 | if (status & MCI_CMDTIMEOUT) { |
616 | cmd->error = -ETIMEDOUT; | 677 | cmd->error = -ETIMEDOUT; |
617 | } else if (status & MCI_CMDCRCFAIL && | 678 | } else if (status & MCI_CMDCRCFAIL && |
@@ -629,16 +690,24 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) | |||
629 | msmsdcc_request_end(host, cmd->mrq); | 690 | msmsdcc_request_end(host, cmd->mrq); |
630 | } else /* host->data == NULL */ | 691 | } else /* host->data == NULL */ |
631 | msmsdcc_request_end(host, cmd->mrq); | 692 | msmsdcc_request_end(host, cmd->mrq); |
632 | } else if (!(cmd->data->flags & MMC_DATA_READ)) | 693 | } else if (cmd->data) |
633 | msmsdcc_start_data(host, cmd->data); | 694 | if (!(cmd->data->flags & MMC_DATA_READ)) |
695 | msmsdcc_start_data(host, cmd->data, | ||
696 | NULL, 0); | ||
634 | } | 697 | } |
635 | 698 | ||
636 | static void | 699 | static void |
637 | msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, | 700 | msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, |
638 | void __iomem *base) | 701 | void __iomem *base) |
639 | { | 702 | { |
640 | struct mmc_data *data = host->curr.data; | 703 | struct mmc_data *data; |
641 | 704 | ||
705 | if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | | ||
706 | MCI_CMDTIMEOUT) && host->curr.cmd) { | ||
707 | msmsdcc_do_cmdirq(host, status); | ||
708 | } | ||
709 | |||
710 | data = host->curr.data; | ||
642 | if (!data) | 711 | if (!data) |
643 | return; | 712 | return; |
644 | 713 | ||
@@ -720,11 +789,6 @@ msmsdcc_irq(int irq, void *dev_id) | |||
720 | 789 | ||
721 | msmsdcc_handle_irq_data(host, status, base); | 790 | msmsdcc_handle_irq_data(host, status, base); |
722 | 791 | ||
723 | if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | | ||
724 | MCI_CMDTIMEOUT) && host->curr.cmd) { | ||
725 | msmsdcc_do_cmdirq(host, status); | ||
726 | } | ||
727 | |||
728 | if (status & MCI_SDIOINTOPER) { | 792 | if (status & MCI_SDIOINTOPER) { |
729 | cardint = 1; | 793 | cardint = 1; |
730 | status &= ~MCI_SDIOINTOPER; | 794 | status &= ~MCI_SDIOINTOPER; |
@@ -775,9 +839,10 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
775 | msmsdcc_enable_clocks(host, 1); | 839 | msmsdcc_enable_clocks(host, 1); |
776 | 840 | ||
777 | if (mrq->data && mrq->data->flags & MMC_DATA_READ) | 841 | if (mrq->data && mrq->data->flags & MMC_DATA_READ) |
778 | msmsdcc_start_data(host, mrq->data); | 842 | /* Queue/read data, daisy-chain command when data starts */ |
779 | 843 | msmsdcc_start_data(host, mrq->data, mrq->cmd, 0); | |
780 | msmsdcc_start_command(host, mrq->cmd, 0); | 844 | else |
845 | msmsdcc_start_command(host, mrq->cmd, 0); | ||
781 | 846 | ||
782 | if (host->cmdpoll && !msmsdcc_spin_on_status(host, | 847 | if (host->cmdpoll && !msmsdcc_spin_on_status(host, |
783 | MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, | 848 | MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, |
@@ -790,7 +855,6 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
790 | host->stats.cmdpoll_hits++; | 855 | host->stats.cmdpoll_hits++; |
791 | } else { | 856 | } else { |
792 | host->stats.cmdpoll_misses++; | 857 | host->stats.cmdpoll_misses++; |
793 | mod_timer(&host->command_timer, jiffies + HZ); | ||
794 | } | 858 | } |
795 | spin_unlock_irqrestore(&host->lock, flags); | 859 | spin_unlock_irqrestore(&host->lock, flags); |
796 | } | 860 | } |
@@ -943,42 +1007,6 @@ msmsdcc_busclk_expired(unsigned long _data) | |||
943 | spin_unlock_irqrestore(&host->lock, flags); | 1007 | spin_unlock_irqrestore(&host->lock, flags); |
944 | } | 1008 | } |
945 | 1009 | ||
946 | /* | ||
947 | * called when a command expires. | ||
948 | * Dump some debugging, and then error | ||
949 | * out the transaction. | ||
950 | */ | ||
951 | static void | ||
952 | msmsdcc_command_expired(unsigned long _data) | ||
953 | { | ||
954 | struct msmsdcc_host *host = (struct msmsdcc_host *) _data; | ||
955 | struct mmc_request *mrq; | ||
956 | unsigned long flags; | ||
957 | |||
958 | spin_lock_irqsave(&host->lock, flags); | ||
959 | mrq = host->curr.mrq; | ||
960 | |||
961 | if (!mrq) { | ||
962 | spin_unlock_irqrestore(&host->lock, flags); | ||
963 | return; | ||
964 | } | ||
965 | |||
966 | pr_err("%s: Controller lockup detected\n", | ||
967 | mmc_hostname(host->mmc)); | ||
968 | mrq->cmd->error = -ETIMEDOUT; | ||
969 | msmsdcc_stop_data(host); | ||
970 | |||
971 | msmsdcc_writel(host, 0, MMCICOMMAND); | ||
972 | |||
973 | host->curr.mrq = NULL; | ||
974 | host->curr.cmd = NULL; | ||
975 | |||
976 | if (host->clks_on) | ||
977 | msmsdcc_enable_clocks(host, 0); | ||
978 | spin_unlock_irqrestore(&host->lock, flags); | ||
979 | mmc_request_done(host->mmc, mrq); | ||
980 | } | ||
981 | |||
982 | static int | 1010 | static int |
983 | msmsdcc_init_dma(struct msmsdcc_host *host) | 1011 | msmsdcc_init_dma(struct msmsdcc_host *host) |
984 | { | 1012 | { |
@@ -1078,6 +1106,7 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1078 | host->pdev_id = pdev->id; | 1106 | host->pdev_id = pdev->id; |
1079 | host->plat = plat; | 1107 | host->plat = plat; |
1080 | host->mmc = mmc; | 1108 | host->mmc = mmc; |
1109 | host->curr.cmd = NULL; | ||
1081 | 1110 | ||
1082 | host->cmdpoll = 1; | 1111 | host->cmdpoll = 1; |
1083 | 1112 | ||
@@ -1194,14 +1223,6 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1194 | host->eject = !host->oldstat; | 1223 | host->eject = !host->oldstat; |
1195 | } | 1224 | } |
1196 | 1225 | ||
1197 | /* | ||
1198 | * Setup a command timer. We currently need this due to | ||
1199 | * some 'strange' timeout / error handling situations. | ||
1200 | */ | ||
1201 | init_timer(&host->command_timer); | ||
1202 | host->command_timer.data = (unsigned long) host; | ||
1203 | host->command_timer.function = msmsdcc_command_expired; | ||
1204 | |||
1205 | init_timer(&host->busclk_timer); | 1226 | init_timer(&host->busclk_timer); |
1206 | host->busclk_timer.data = (unsigned long) host; | 1227 | host->busclk_timer.data = (unsigned long) host; |
1207 | host->busclk_timer.function = msmsdcc_busclk_expired; | 1228 | host->busclk_timer.function = msmsdcc_busclk_expired; |
@@ -1243,7 +1264,7 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1243 | pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); | 1264 | pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); |
1244 | 1265 | ||
1245 | if (host->use_bustimer) | 1266 | if (host->use_bustimer) |
1246 | mod_timer(&host->busclk_timer, jiffies + HZ); | 1267 | mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); |
1247 | return 0; | 1268 | return 0; |
1248 | cmd_irq_free: | 1269 | cmd_irq_free: |
1249 | free_irq(cmd_irqres->start, host); | 1270 | free_irq(cmd_irqres->start, host); |
@@ -1267,10 +1288,14 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) | |||
1267 | { | 1288 | { |
1268 | struct mmc_host *mmc = mmc_get_drvdata(dev); | 1289 | struct mmc_host *mmc = mmc_get_drvdata(dev); |
1269 | int rc = 0; | 1290 | int rc = 0; |
1291 | unsigned long flags; | ||
1270 | 1292 | ||
1271 | if (mmc) { | 1293 | if (mmc) { |
1272 | struct msmsdcc_host *host = mmc_priv(mmc); | 1294 | struct msmsdcc_host *host = mmc_priv(mmc); |
1273 | 1295 | ||
1296 | if (host->use_bustimer) | ||
1297 | del_timer_sync(&host->busclk_timer); | ||
1298 | spin_lock_irqsave(&host->lock, flags); | ||
1274 | if (host->stat_irq) | 1299 | if (host->stat_irq) |
1275 | disable_irq(host->stat_irq); | 1300 | disable_irq(host->stat_irq); |
1276 | 1301 | ||
@@ -1282,6 +1307,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) | |||
1282 | if (host->clks_on) | 1307 | if (host->clks_on) |
1283 | msmsdcc_enable_clocks(host, 0); | 1308 | msmsdcc_enable_clocks(host, 0); |
1284 | } | 1309 | } |
1310 | spin_unlock_irqrestore(&host->lock, flags); | ||
1285 | } | 1311 | } |
1286 | return rc; | 1312 | return rc; |
1287 | } | 1313 | } |
@@ -1300,6 +1326,9 @@ msmsdcc_resume(struct platform_device *dev) | |||
1300 | if (!host->clks_on) | 1326 | if (!host->clks_on) |
1301 | msmsdcc_enable_clocks(host, 1); | 1327 | msmsdcc_enable_clocks(host, 1); |
1302 | 1328 | ||
1329 | if (host->use_bustimer) | ||
1330 | mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); | ||
1331 | |||
1303 | msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); | 1332 | msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); |
1304 | 1333 | ||
1305 | spin_unlock_irqrestore(&host->lock, flags); | 1334 | spin_unlock_irqrestore(&host->lock, flags); |