aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/imxmmc.c
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2006-05-06 14:59:18 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2006-05-06 14:59:18 -0400
commit5047f09b56d0bc3c21aec9cb16de60283da645c6 (patch)
tree09a07554b933c3bb912ce3bfc0ea7c7e1f16041c /drivers/mmc/imxmmc.c
parentc0f1fe00c3923135b2c2f443448585482da8a53e (diff)
parent5528e568a760442e0ec8fd2dea1f0791875a066b (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'drivers/mmc/imxmmc.c')
-rw-r--r--drivers/mmc/imxmmc.c60
1 files changed, 44 insertions, 16 deletions
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
index ffb7f55d3467..79358e223f57 100644
--- a/drivers/mmc/imxmmc.c
+++ b/drivers/mmc/imxmmc.c
@@ -102,6 +102,7 @@ struct imxmci_host {
102#define IMXMCI_PEND_CPU_DATA_b 5 102#define IMXMCI_PEND_CPU_DATA_b 5
103#define IMXMCI_PEND_CARD_XCHG_b 6 103#define IMXMCI_PEND_CARD_XCHG_b 6
104#define IMXMCI_PEND_SET_INIT_b 7 104#define IMXMCI_PEND_SET_INIT_b 7
105#define IMXMCI_PEND_STARTED_b 8
105 106
106#define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b) 107#define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b)
107#define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b) 108#define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b)
@@ -111,6 +112,7 @@ struct imxmci_host {
111#define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b) 112#define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b)
112#define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b) 113#define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b)
113#define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b) 114#define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b)
115#define IMXMCI_PEND_STARTED_m (1 << IMXMCI_PEND_STARTED_b)
114 116
115static void imxmci_stop_clock(struct imxmci_host *host) 117static void imxmci_stop_clock(struct imxmci_host *host)
116{ 118{
@@ -131,23 +133,52 @@ static void imxmci_stop_clock(struct imxmci_host *host)
131 dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n"); 133 dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n");
132} 134}
133 135
134static void imxmci_start_clock(struct imxmci_host *host) 136static int imxmci_start_clock(struct imxmci_host *host)
135{ 137{
136 int i = 0; 138 unsigned int trials = 0;
139 unsigned int delay_limit = 128;
140 unsigned long flags;
141
137 MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK; 142 MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK;
138 while(i < 0x1000) {
139 if(!(i & 0x7f))
140 MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
141 143
142 if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) { 144 clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
143 /* Check twice before cut */ 145
146 /*
147 * Command start of the clock, this usually succeeds in less
148 * then 6 delay loops, but during card detection (low clockrate)
149 * it takes up to 5000 delay loops and sometimes fails for the first time
150 */
151 MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
152
153 do {
154 unsigned int delay = delay_limit;
155
156 while(delay--){
144 if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) 157 if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
145 return; 158 /* Check twice before cut */
159 if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
160 return 0;
161
162 if(test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
163 return 0;
146 } 164 }
147 165
148 i++; 166 local_irq_save(flags);
149 } 167 /*
150 dev_dbg(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n"); 168 * Ensure, that request is not doubled under all possible circumstances.
169 * It is possible, that cock running state is missed, because some other
170 * IRQ or schedule delays this function execution and the clocks has
171 * been already stopped by other means (response processing, SDHC HW)
172 */
173 if(!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
174 MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
175 local_irq_restore(flags);
176
177 } while(++trials<256);
178
179 dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n");
180
181 return -1;
151} 182}
152 183
153static void imxmci_softreset(void) 184static void imxmci_softreset(void)
@@ -498,7 +529,7 @@ static int imxmci_data_done(struct imxmci_host *host, unsigned int stat)
498 529
499 data_error = imxmci_finish_data(host, stat); 530 data_error = imxmci_finish_data(host, stat);
500 531
501 if (host->req->stop && (data_error == MMC_ERR_NONE)) { 532 if (host->req->stop) {
502 imxmci_stop_clock(host); 533 imxmci_stop_clock(host);
503 imxmci_start_cmd(host, host->req->stop, 0); 534 imxmci_start_cmd(host, host->req->stop, 0);
504 } else { 535 } else {
@@ -622,6 +653,7 @@ static irqreturn_t imxmci_irq(int irq, void *devid, struct pt_regs *regs)
622 atomic_set(&host->stuck_timeout, 0); 653 atomic_set(&host->stuck_timeout, 0);
623 host->status_reg = stat; 654 host->status_reg = stat;
624 set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events); 655 set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
656 set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
625 tasklet_schedule(&host->tasklet); 657 tasklet_schedule(&host->tasklet);
626 658
627 return IRQ_RETVAL(handled);; 659 return IRQ_RETVAL(handled);;
@@ -775,10 +807,6 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
775 struct imxmci_host *host = mmc_priv(mmc); 807 struct imxmci_host *host = mmc_priv(mmc);
776 int prescaler; 808 int prescaler;
777 809
778 dev_dbg(mmc_dev(host->mmc), "clock %u power %u vdd %u width %u\n",
779 ios->clock, ios->power_mode, ios->vdd,
780 (ios->bus_width==MMC_BUS_WIDTH_4)?4:1);
781
782 if( ios->bus_width==MMC_BUS_WIDTH_4 ) { 810 if( ios->bus_width==MMC_BUS_WIDTH_4 ) {
783 host->actual_bus_width = MMC_BUS_WIDTH_4; 811 host->actual_bus_width = MMC_BUS_WIDTH_4;
784 imx_gpio_mode(PB11_PF_SD_DAT3); 812 imx_gpio_mode(PB11_PF_SD_DAT3);