Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc:
  mmc_spi: support for non-byte-aligned cards
  omap_hsmmc: Do not expect cmd/data to be non-null when CC/TC occurs
  mmc: Fix compile for omap_hsmmc.c
  mmc_spi: convert timeout handling to jiffies and avoid busy waiting
  mmc_spi: do not check CID and CSD blocks with CRC16
  omap_hsmmc: Flush posted write to IRQ
  New mail address for Pierre Ossman
  imxmmc: move RSSR BLR
  imxmmc: init-exit rework
  mmc: Accept EXT_CSD rev 1.3 since it is backwards compatible with 1.2
This commit is contained in:
Linus Torvalds 2009-04-08 14:33:59 -07:00
commit d2e2d7ca14
9 changed files with 166 additions and 87 deletions

View file

@ -3057,7 +3057,7 @@ S: Supported
MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
P: Pierre Ossman P: Pierre Ossman
M: drzeus-mmc@drzeus.cx M: pierre@ossman.eu
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
S: Maintained S: Maintained
@ -3939,7 +3939,7 @@ S: Maintained
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
P: Pierre Ossman P: Pierre Ossman
M: drzeus-sdhci@drzeus.cx M: pierre@ossman.eu
L: sdhci-devel@lists.ossman.eu L: sdhci-devel@lists.ossman.eu
S: Maintained S: Maintained
@ -4926,7 +4926,7 @@ S: Maintained
W83L51xD SD/MMC CARD INTERFACE DRIVER W83L51xD SD/MMC CARD INTERFACE DRIVER
P: Pierre Ossman P: Pierre Ossman
M: drzeus-wbsd@drzeus.cx M: pierre@ossman.eu
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
S: Maintained S: Maintained

View file

@ -208,7 +208,7 @@ static int mmc_read_ext_csd(struct mmc_card *card)
} }
ext_csd_struct = ext_csd[EXT_CSD_REV]; ext_csd_struct = ext_csd[EXT_CSD_REV];
if (ext_csd_struct > 2) { if (ext_csd_struct > 3) {
printk(KERN_ERR "%s: unrecognised EXT_CSD structure " printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
"version %d\n", mmc_hostname(card->host), "version %d\n", mmc_hostname(card->host),
ext_csd_struct); ext_csd_struct);

View file

@ -362,15 +362,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
if (err) if (err)
goto err; goto err;
/*
* For SPI, enable CRC as appropriate.
*/
if (mmc_host_is_spi(host)) {
err = mmc_spi_set_crc(host, use_spi_crc);
if (err)
goto err;
}
/* /*
* Fetch CID from card. * Fetch CID from card.
*/ */
@ -457,6 +448,18 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
goto free_card; goto free_card;
} }
/*
* For SPI, enable CRC as appropriate.
* This CRC enable is located AFTER the reading of the
* card registers because some SDHC cards are not able
* to provide valid CRCs for non-512-byte blocks.
*/
if (mmc_host_is_spi(host)) {
err = mmc_spi_set_crc(host, use_spi_crc);
if (err)
goto free_card;
}
/* /*
* Attempt to change to high-speed (if supported) * Attempt to change to high-speed (if supported)
*/ */

View file

@ -307,13 +307,6 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
wmb(); wmb();
if (host->actual_bus_width == MMC_BUS_WIDTH_4)
BLR(host->dma) = 0; /* burst 64 byte read / 64 bytes write */
else
BLR(host->dma) = 16; /* burst 16 byte read / 16 bytes write */
RSSR(host->dma) = DMA_REQ_SDHC;
set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events); set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events); clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
@ -818,9 +811,11 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (ios->bus_width == MMC_BUS_WIDTH_4) { if (ios->bus_width == MMC_BUS_WIDTH_4) {
host->actual_bus_width = MMC_BUS_WIDTH_4; host->actual_bus_width = MMC_BUS_WIDTH_4;
imx_gpio_mode(PB11_PF_SD_DAT3); imx_gpio_mode(PB11_PF_SD_DAT3);
BLR(host->dma) = 0; /* burst 64 byte read/write */
} else { } else {
host->actual_bus_width = MMC_BUS_WIDTH_1; host->actual_bus_width = MMC_BUS_WIDTH_1;
imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11); imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
BLR(host->dma) = 16; /* burst 16 byte read/write */
} }
if (host->power_mode != ios->power_mode) { if (host->power_mode != ios->power_mode) {
@ -938,7 +933,7 @@ static void imxmci_check_status(unsigned long data)
mod_timer(&host->timer, jiffies + (HZ>>1)); mod_timer(&host->timer, jiffies + (HZ>>1));
} }
static int imxmci_probe(struct platform_device *pdev) static int __init imxmci_probe(struct platform_device *pdev)
{ {
struct mmc_host *mmc; struct mmc_host *mmc;
struct imxmci_host *host = NULL; struct imxmci_host *host = NULL;
@ -1034,6 +1029,7 @@ static int imxmci_probe(struct platform_device *pdev)
} }
host->dma_allocated = 1; host->dma_allocated = 1;
imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host); imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host);
RSSR(host->dma) = DMA_REQ_SDHC;
tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host); tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host);
host->status_reg=0; host->status_reg=0;
@ -1079,7 +1075,7 @@ out:
return ret; return ret;
} }
static int imxmci_remove(struct platform_device *pdev) static int __exit imxmci_remove(struct platform_device *pdev)
{ {
struct mmc_host *mmc = platform_get_drvdata(pdev); struct mmc_host *mmc = platform_get_drvdata(pdev);
@ -1145,8 +1141,7 @@ static int imxmci_resume(struct platform_device *dev)
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static struct platform_driver imxmci_driver = { static struct platform_driver imxmci_driver = {
.probe = imxmci_probe, .remove = __exit_p(imxmci_remove),
.remove = imxmci_remove,
.suspend = imxmci_suspend, .suspend = imxmci_suspend,
.resume = imxmci_resume, .resume = imxmci_resume,
.driver = { .driver = {
@ -1157,7 +1152,7 @@ static struct platform_driver imxmci_driver = {
static int __init imxmci_init(void) static int __init imxmci_init(void)
{ {
return platform_driver_register(&imxmci_driver); return platform_driver_probe(&imxmci_driver, imxmci_probe);
} }
static void __exit imxmci_exit(void) static void __exit imxmci_exit(void)

View file

@ -24,7 +24,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/hrtimer.h> #include <linux/sched.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
@ -95,7 +95,7 @@
* reads which takes nowhere near that long. Older cards may be able to use * reads which takes nowhere near that long. Older cards may be able to use
* shorter timeouts ... but why bother? * shorter timeouts ... but why bother?
*/ */
#define r1b_timeout ktime_set(3, 0) #define r1b_timeout (HZ * 3)
/****************************************************************************/ /****************************************************************************/
@ -183,12 +183,11 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)
return status; return status;
} }
static int static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout,
mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte) unsigned n, u8 byte)
{ {
u8 *cp = host->data->status; u8 *cp = host->data->status;
unsigned long start = jiffies;
timeout = ktime_add(timeout, ktime_get());
while (1) { while (1) {
int status; int status;
@ -203,22 +202,26 @@ mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte)
return cp[i]; return cp[i];
} }
/* REVISIT investigate msleep() to avoid busy-wait I/O if (time_is_before_jiffies(start + timeout))
* in at least some cases.
*/
if (ktime_to_ns(ktime_sub(ktime_get(), timeout)) > 0)
break; break;
/* If we need long timeouts, we may release the CPU.
* We use jiffies here because we want to have a relation
* between elapsed time and the blocking of the scheduler.
*/
if (time_is_before_jiffies(start+1))
schedule();
} }
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static inline int static inline int
mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout) mmc_spi_wait_unbusy(struct mmc_spi_host *host, unsigned long timeout)
{ {
return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0); return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
} }
static int mmc_spi_readtoken(struct mmc_spi_host *host, ktime_t timeout) static int mmc_spi_readtoken(struct mmc_spi_host *host, unsigned long timeout)
{ {
return mmc_spi_skip(host, timeout, 1, 0xff); return mmc_spi_skip(host, timeout, 1, 0xff);
} }
@ -251,6 +254,10 @@ static int mmc_spi_response_get(struct mmc_spi_host *host,
u8 *cp = host->data->status; u8 *cp = host->data->status;
u8 *end = cp + host->t.len; u8 *end = cp + host->t.len;
int value = 0; int value = 0;
int bitshift;
u8 leftover = 0;
unsigned short rotator;
int i;
char tag[32]; char tag[32];
snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s", snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s",
@ -268,9 +275,8 @@ static int mmc_spi_response_get(struct mmc_spi_host *host,
/* Data block reads (R1 response types) may need more data... */ /* Data block reads (R1 response types) may need more data... */
if (cp == end) { if (cp == end) {
unsigned i;
cp = host->data->status; cp = host->data->status;
end = cp+1;
/* Card sends N(CR) (== 1..8) bytes of all-ones then one /* Card sends N(CR) (== 1..8) bytes of all-ones then one
* status byte ... and we already scanned 2 bytes. * status byte ... and we already scanned 2 bytes.
@ -295,14 +301,28 @@ static int mmc_spi_response_get(struct mmc_spi_host *host,
} }
checkstatus: checkstatus:
bitshift = 0;
if (*cp & 0x80) { if (*cp & 0x80) {
dev_dbg(&host->spi->dev, "%s: INVALID RESPONSE, %02x\n", /* Houston, we have an ugly card with a bit-shifted response */
tag, *cp); rotator = *cp++ << 8;
value = -EBADR; /* read the next byte */
if (cp == end) {
value = mmc_spi_readbytes(host, 1);
if (value < 0)
goto done; goto done;
cp = host->data->status;
end = cp+1;
} }
rotator |= *cp++;
while (rotator & 0x8000) {
bitshift++;
rotator <<= 1;
}
cmd->resp[0] = rotator >> 8;
leftover = rotator;
} else {
cmd->resp[0] = *cp++; cmd->resp[0] = *cp++;
}
cmd->error = 0; cmd->error = 0;
/* Status byte: the entire seven-bit R1 response. */ /* Status byte: the entire seven-bit R1 response. */
@ -336,12 +356,45 @@ checkstatus:
* SPI R5 == R1 + data byte; IO_RW_DIRECT * SPI R5 == R1 + data byte; IO_RW_DIRECT
*/ */
case MMC_RSP_SPI_R2: case MMC_RSP_SPI_R2:
/* read the next byte */
if (cp == end) {
value = mmc_spi_readbytes(host, 1);
if (value < 0)
goto done;
cp = host->data->status;
end = cp+1;
}
if (bitshift) {
rotator = leftover << 8;
rotator |= *cp << bitshift;
cmd->resp[0] |= (rotator & 0xFF00);
} else {
cmd->resp[0] |= *cp << 8; cmd->resp[0] |= *cp << 8;
}
break; break;
/* SPI R3, R4, or R7 == R1 + 4 bytes */ /* SPI R3, R4, or R7 == R1 + 4 bytes */
case MMC_RSP_SPI_R3: case MMC_RSP_SPI_R3:
cmd->resp[1] = get_unaligned_be32(cp); rotator = leftover << 8;
cmd->resp[1] = 0;
for (i = 0; i < 4; i++) {
cmd->resp[1] <<= 8;
/* read the next byte */
if (cp == end) {
value = mmc_spi_readbytes(host, 1);
if (value < 0)
goto done;
cp = host->data->status;
end = cp+1;
}
if (bitshift) {
rotator |= *cp++ << bitshift;
cmd->resp[1] |= (rotator >> 8);
rotator <<= 8;
} else {
cmd->resp[1] |= *cp++;
}
}
break; break;
/* SPI R1 == just one status byte */ /* SPI R1 == just one status byte */
@ -607,7 +660,7 @@ mmc_spi_setup_data_message(
*/ */
static int static int
mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t, mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
ktime_t timeout) unsigned long timeout)
{ {
struct spi_device *spi = host->spi; struct spi_device *spi = host->spi;
int status, i; int status, i;
@ -717,11 +770,13 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
*/ */
static int static int
mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
ktime_t timeout) unsigned long timeout)
{ {
struct spi_device *spi = host->spi; struct spi_device *spi = host->spi;
int status; int status;
struct scratch *scratch = host->data; struct scratch *scratch = host->data;
unsigned int bitshift;
u8 leftover;
/* At least one SD card sends an all-zeroes byte when N(CX) /* At least one SD card sends an all-zeroes byte when N(CX)
* applies, before the all-ones bytes ... just cope with that. * applies, before the all-ones bytes ... just cope with that.
@ -733,7 +788,21 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
if (status == 0xff || status == 0) if (status == 0xff || status == 0)
status = mmc_spi_readtoken(host, timeout); status = mmc_spi_readtoken(host, timeout);
if (status == SPI_TOKEN_SINGLE) { if (status < 0) {
dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status);
return status;
}
/* The token may be bit-shifted...
* the first 0-bit precedes the data stream.
*/
bitshift = 7;
while (status & 0x80) {
status <<= 1;
bitshift--;
}
leftover = status << 1;
if (host->dma_dev) { if (host->dma_dev) {
dma_sync_single_for_device(host->dma_dev, dma_sync_single_for_device(host->dma_dev,
host->data_dma, sizeof(*scratch), host->data_dma, sizeof(*scratch),
@ -754,17 +823,25 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
} }
} else { if (bitshift) {
dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status); /* Walk through the data and the crc and do
* all the magic to get byte-aligned data.
/* we've read extra garbage, timed out, etc */
if (status < 0)
return status;
/* low four bits are an R2 subset, fifth seems to be
* vendor specific ... map them all to generic error..
*/ */
return -EIO; u8 *cp = t->rx_buf;
unsigned int len;
unsigned int bitright = 8 - bitshift;
u8 temp;
for (len = t->len; len; len--) {
temp = *cp;
*cp++ = leftover | (temp >> bitshift);
leftover = temp << bitright;
}
cp = (u8 *) &scratch->crc_val;
temp = *cp;
*cp++ = leftover | (temp >> bitshift);
leftover = temp << bitright;
temp = *cp;
*cp = leftover | (temp >> bitshift);
} }
if (host->mmc->use_spi_crc) { if (host->mmc->use_spi_crc) {
@ -803,7 +880,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
unsigned n_sg; unsigned n_sg;
int multiple = (data->blocks > 1); int multiple = (data->blocks > 1);
u32 clock_rate; u32 clock_rate;
ktime_t timeout; unsigned long timeout;
if (data->flags & MMC_DATA_READ) if (data->flags & MMC_DATA_READ)
direction = DMA_FROM_DEVICE; direction = DMA_FROM_DEVICE;
@ -817,8 +894,9 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
else else
clock_rate = spi->max_speed_hz; clock_rate = spi->max_speed_hz;
timeout = ktime_add_ns(ktime_set(0, 0), data->timeout_ns + timeout = data->timeout_ns +
data->timeout_clks * 1000000 / clock_rate); data->timeout_clks * 1000000 / clock_rate;
timeout = usecs_to_jiffies((unsigned int)(timeout / 1000)) + 1;
/* Handle scatterlist segments one at a time, with synch for /* Handle scatterlist segments one at a time, with synch for
* each 512-byte block * each 512-byte block

View file

@ -298,7 +298,6 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
struct mmc_request *mrq = host->mrq; struct mmc_request *mrq = host->mrq;
host->mrq = NULL; host->mrq = NULL;
mmc_omap_fclk_lazy_disable(host);
mmc_request_done(host->mmc, mrq); mmc_request_done(host->mmc, mrq);
return; return;
} }
@ -434,6 +433,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
if (host->mrq == NULL) { if (host->mrq == NULL) {
OMAP_HSMMC_WRITE(host->base, STAT, OMAP_HSMMC_WRITE(host->base, STAT,
OMAP_HSMMC_READ(host->base, STAT)); OMAP_HSMMC_READ(host->base, STAT));
/* Flush posted write */
OMAP_HSMMC_READ(host->base, STAT);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -489,8 +490,10 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
} }
OMAP_HSMMC_WRITE(host->base, STAT, status); OMAP_HSMMC_WRITE(host->base, STAT, status);
/* Flush posted write */
OMAP_HSMMC_READ(host->base, STAT);
if (end_cmd || (status & CC)) if (end_cmd || ((status & CC) && host->cmd))
mmc_omap_cmd_done(host, host->cmd); mmc_omap_cmd_done(host, host->cmd);
if (end_trans || (status & TC)) if (end_trans || (status & TC))
mmc_omap_xfer_done(host, data); mmc_omap_xfer_done(host, data);

View file

@ -729,6 +729,6 @@ static void __exit sdhci_drv_exit(void)
module_init(sdhci_drv_init); module_init(sdhci_drv_init);
module_exit(sdhci_drv_exit); module_exit(sdhci_drv_exit);
MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>"); MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver"); MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View file

@ -1935,7 +1935,7 @@ module_exit(sdhci_drv_exit);
module_param(debug_quirks, uint, 0444); module_param(debug_quirks, uint, 0444);
MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>"); MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver"); MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View file

@ -2036,7 +2036,7 @@ module_param_named(irq, param_irq, uint, 0444);
module_param_named(dma, param_dma, int, 0444); module_param_named(dma, param_dma, int, 0444);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>"); MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver"); MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
#ifdef CONFIG_PNP #ifdef CONFIG_PNP