mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 14:43:16 +00:00
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:
commit
d2e2d7ca14
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
*/
|
*/
|
||||||
|
@ -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)
|
||||||
|
@ -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,20 +301,34 @@ static int mmc_spi_response_get(struct mmc_spi_host *host,
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkstatus:
|
checkstatus:
|
||||||
if (*cp & 0x80) {
|
bitshift = 0;
|
||||||
dev_dbg(&host->spi->dev, "%s: INVALID RESPONSE, %02x\n",
|
if (*cp & 0x80) {
|
||||||
tag, *cp);
|
/* Houston, we have an ugly card with a bit-shifted response */
|
||||||
value = -EBADR;
|
rotator = *cp++ << 8;
|
||||||
goto done;
|
/* 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;
|
||||||
|
}
|
||||||
|
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. */
|
||||||
if (cmd->resp[0] != 0) {
|
if (cmd->resp[0] != 0) {
|
||||||
if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS
|
if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS
|
||||||
| R1_SPI_ILLEGAL_COMMAND)
|
| R1_SPI_ILLEGAL_COMMAND)
|
||||||
& cmd->resp[0])
|
& cmd->resp[0])
|
||||||
value = -EINVAL;
|
value = -EINVAL;
|
||||||
else if (R1_SPI_COM_CRC & cmd->resp[0])
|
else if (R1_SPI_COM_CRC & cmd->resp[0])
|
||||||
@ -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:
|
||||||
cmd->resp[0] |= *cp << 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 = leftover << 8;
|
||||||
|
rotator |= *cp << bitshift;
|
||||||
|
cmd->resp[0] |= (rotator & 0xFF00);
|
||||||
|
} else {
|
||||||
|
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,38 +788,60 @@ 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) {
|
||||||
if (host->dma_dev) {
|
|
||||||
dma_sync_single_for_device(host->dma_dev,
|
|
||||||
host->data_dma, sizeof(*scratch),
|
|
||||||
DMA_BIDIRECTIONAL);
|
|
||||||
dma_sync_single_for_device(host->dma_dev,
|
|
||||||
t->rx_dma, t->len,
|
|
||||||
DMA_FROM_DEVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = spi_sync(spi, &host->m);
|
|
||||||
|
|
||||||
if (host->dma_dev) {
|
|
||||||
dma_sync_single_for_cpu(host->dma_dev,
|
|
||||||
host->data_dma, sizeof(*scratch),
|
|
||||||
DMA_BIDIRECTIONAL);
|
|
||||||
dma_sync_single_for_cpu(host->dma_dev,
|
|
||||||
t->rx_dma, t->len,
|
|
||||||
DMA_FROM_DEVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status);
|
dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/* we've read extra garbage, timed out, etc */
|
/* The token may be bit-shifted...
|
||||||
if (status < 0)
|
* the first 0-bit precedes the data stream.
|
||||||
return status;
|
*/
|
||||||
|
bitshift = 7;
|
||||||
|
while (status & 0x80) {
|
||||||
|
status <<= 1;
|
||||||
|
bitshift--;
|
||||||
|
}
|
||||||
|
leftover = status << 1;
|
||||||
|
|
||||||
/* low four bits are an R2 subset, fifth seems to be
|
if (host->dma_dev) {
|
||||||
* vendor specific ... map them all to generic error..
|
dma_sync_single_for_device(host->dma_dev,
|
||||||
|
host->data_dma, sizeof(*scratch),
|
||||||
|
DMA_BIDIRECTIONAL);
|
||||||
|
dma_sync_single_for_device(host->dma_dev,
|
||||||
|
t->rx_dma, t->len,
|
||||||
|
DMA_FROM_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = spi_sync(spi, &host->m);
|
||||||
|
|
||||||
|
if (host->dma_dev) {
|
||||||
|
dma_sync_single_for_cpu(host->dma_dev,
|
||||||
|
host->data_dma, sizeof(*scratch),
|
||||||
|
DMA_BIDIRECTIONAL);
|
||||||
|
dma_sync_single_for_cpu(host->dma_dev,
|
||||||
|
t->rx_dma, t->len,
|
||||||
|
DMA_FROM_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bitshift) {
|
||||||
|
/* Walk through the data and the crc and do
|
||||||
|
* all the magic to get byte-aligned data.
|
||||||
*/
|
*/
|
||||||
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
|
||||||
|
@ -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);
|
||||||
|
@ -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");
|
||||||
|
@ -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");
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user