Commit ca78bf35 authored by Russell King's avatar Russell King

[MMC] Fix PXA MMC interface issues.

- Wait for STAT_CLK_EN to clear rather than waiting for the CLK_IS_OFF
  interrupt when stopping the MMC clock.
- Always return the number of data blocks transferred no matter what.
- Set the device driver data correctly.
parent e5638b44
...@@ -7,8 +7,11 @@ ...@@ -7,8 +7,11 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* This hardware is really sick. No way to clear interrupts. Have * This hardware is really sick:
* to turn off the clock whenever we touch the device. Yuck! * - No way to clear interrupts.
* - Have to turn off the clock whenever we touch the device.
* - Doesn't tell you how many data blocks were transferred.
* Yuck!
* *
* 1 and 3 byte data transfers not supported * 1 and 3 byte data transfers not supported
* max block length up to 1023 * max block length up to 1023
...@@ -74,23 +77,20 @@ static inline unsigned int ns_to_clocks(unsigned int ns) ...@@ -74,23 +77,20 @@ static inline unsigned int ns_to_clocks(unsigned int ns)
static void pxamci_stop_clock(struct pxamci_host *host) static void pxamci_stop_clock(struct pxamci_host *host)
{ {
if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
unsigned long flags; unsigned long timeout = 10000;
unsigned int v; unsigned int v;
writel(STOP_CLOCK, host->base + MMC_STRPCL); writel(STOP_CLOCK, host->base + MMC_STRPCL);
/*
* Wait for the "clock has stopped" interrupt.
* We need to unmask the interrupt to receive
* the notification. Sigh.
*/
spin_lock_irqsave(&host->lock, flags);
writel(host->imask & ~CLK_IS_OFF, host->base + MMC_I_MASK);
do { do {
v = readl(host->base + MMC_I_REG); v = readl(host->base + MMC_STAT);
} while (!(v & CLK_IS_OFF)); if (!(v & STAT_CLK_EN))
writel(host->imask, host->base + MMC_I_MASK); break;
spin_unlock_irqrestore(&host->lock, flags); udelay(1);
} while (timeout--);
if (v & STAT_CLK_EN)
dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
} }
} }
...@@ -279,8 +279,13 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) ...@@ -279,8 +279,13 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
data->error = MMC_ERR_BADCRC; data->error = MMC_ERR_BADCRC;
data->bytes_xfered = (data->blocks - readl(host->base + MMC_NOB)) /*
<< data->blksz_bits; * There appears to be a hardware design bug here. There seems to
* be no way to find out how much data was transferred to the card.
* This means that if there was an error on any block, we mark all
* data blocks as being in error.
*/
data->bytes_xfered = data->blocks << data->blksz_bits;
pxamci_disable_irq(host, DATA_TRAN_DONE); pxamci_disable_irq(host, DATA_TRAN_DONE);
...@@ -493,7 +498,7 @@ static int pxamci_probe(struct device *dev) ...@@ -493,7 +498,7 @@ static int pxamci_probe(struct device *dev)
if (ret) if (ret)
goto out; goto out;
dev_set_drvdata(dev, host); dev_set_drvdata(dev, mmc);
mmc_add_host(mmc); mmc_add_host(mmc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment