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: (24 commits) MMC: Use timeout values from CSR MMC: CSD and CID timeout values sdhci: 'scratch' may be used uninitialized mmc: explicitly mention SDIO support in Kconfig mmc: remove redundant "depends on" Fix comment in include/linux/mmc/host.h sdio: high-speed support mmc_block: hard code 512 byte block size sdhci: force high speed capability on some controllers mmc_block: filter out PC requests mmc_block: indicate strict ordering mmc_block: inform block layer about sector count restriction sdio: give sdio irq thread a host specific name sdio: make sleep on error interruptable sdhci: reduce card detection delay sdhci: let the controller wait for busy state to end atmel-mci: Add missing flush_dcache_page() in PIO transfer code atmel-mci: Don't overwrite error bits when NOTBUSY is set atmel-mci: Add experimental DMA support atmel-mci: support multiple mmc slots ...
This commit is contained in:
Коммит
46b5e34029
|
@ -53,8 +53,11 @@ static struct spi_board_info spi0_board_info[] __initdata = {
|
|||
};
|
||||
|
||||
static struct mci_platform_data __initdata mci0_data = {
|
||||
.detect_pin = GPIO_PIN_PC(25),
|
||||
.wp_pin = GPIO_PIN_PE(0),
|
||||
.slot[0] = {
|
||||
.bus_width = 4,
|
||||
.detect_pin = GPIO_PIN_PC(25),
|
||||
.wp_pin = GPIO_PIN_PE(0),
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -264,16 +264,20 @@ void __init setup_board(void)
|
|||
|
||||
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
|
||||
|
||||
static struct mci_platform_data __initdata mci0_data = {
|
||||
.slot[0] = {
|
||||
.bus_width = 4,
|
||||
|
||||
/* MMC card detect requires MACB0 *NOT* be used */
|
||||
#ifdef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
|
||||
static struct mci_platform_data __initdata mci0_data = {
|
||||
.detect_pin = GPIO_PIN_PC(14), /* gpio30/sdcd */
|
||||
.wp_pin = GPIO_PIN_PC(15), /* gpio31/sdwp */
|
||||
};
|
||||
#define MCI_PDATA &mci0_data
|
||||
.detect_pin = GPIO_PIN_PC(14), /* gpio30/sdcd */
|
||||
.wp_pin = GPIO_PIN_PC(15), /* gpio31/sdwp */
|
||||
#else
|
||||
#define MCI_PDATA NULL
|
||||
.detect_pin = -ENODEV,
|
||||
.wp_pin = -ENODEV,
|
||||
#endif /* SW6 for sd{cd,wp} routing */
|
||||
},
|
||||
};
|
||||
|
||||
#endif /* SW2 for MMC signal routing */
|
||||
|
||||
|
@ -326,7 +330,7 @@ static int __init atstk1002_init(void)
|
|||
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
|
||||
#endif
|
||||
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
|
||||
at32_add_device_mci(0, MCI_PDATA);
|
||||
at32_add_device_mci(0, &mci0_pdata);
|
||||
#endif
|
||||
#ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
|
||||
set_hw_addr(at32_add_device_eth(1, ð_data[1]));
|
||||
|
|
|
@ -66,6 +66,16 @@ static struct spi_board_info spi1_board_info[] __initdata = { {
|
|||
} };
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
|
||||
static struct mci_platform_data __initdata mci0_data = {
|
||||
.slot[0] = {
|
||||
.bus_width = 4,
|
||||
.detect_pin = -ENODEV,
|
||||
.wp_pin = -ENODEV,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
|
||||
static void __init atstk1003_setup_extdac(void)
|
||||
{
|
||||
|
@ -154,7 +164,7 @@ static int __init atstk1003_init(void)
|
|||
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
|
||||
#endif
|
||||
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
|
||||
at32_add_device_mci(0, NULL);
|
||||
at32_add_device_mci(0, &mci0_data);
|
||||
#endif
|
||||
at32_add_device_usba(0, NULL);
|
||||
#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
|
||||
|
|
|
@ -71,6 +71,16 @@ static struct spi_board_info spi1_board_info[] __initdata = { {
|
|||
} };
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
|
||||
static struct mci_platform_data __initdata mci0_data = {
|
||||
.slot[0] = {
|
||||
.bus_width = 4,
|
||||
.detect_pin = -ENODEV,
|
||||
.wp_pin = -ENODEV,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
|
||||
static void __init atstk1004_setup_extdac(void)
|
||||
{
|
||||
|
@ -137,7 +147,7 @@ static int __init atstk1004_init(void)
|
|||
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
|
||||
#endif
|
||||
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
|
||||
at32_add_device_mci(0, NULL);
|
||||
at32_add_device_mci(0, &mci0_data);
|
||||
#endif
|
||||
at32_add_device_lcdc(0, &atstk1000_lcdc_data,
|
||||
fbmem_start, fbmem_size, 0);
|
||||
|
|
|
@ -1,9 +1,39 @@
|
|||
#ifndef __ASM_AVR32_ATMEL_MCI_H
|
||||
#define __ASM_AVR32_ATMEL_MCI_H
|
||||
|
||||
struct mci_platform_data {
|
||||
#define ATMEL_MCI_MAX_NR_SLOTS 2
|
||||
|
||||
struct dma_slave;
|
||||
|
||||
/**
|
||||
* struct mci_slot_pdata - board-specific per-slot configuration
|
||||
* @bus_width: Number of data lines wired up the slot
|
||||
* @detect_pin: GPIO pin wired to the card detect switch
|
||||
* @wp_pin: GPIO pin wired to the write protect sensor
|
||||
*
|
||||
* If a given slot is not present on the board, @bus_width should be
|
||||
* set to 0. The other fields are ignored in this case.
|
||||
*
|
||||
* Any pins that aren't available should be set to a negative value.
|
||||
*
|
||||
* Note that support for multiple slots is experimental -- some cards
|
||||
* might get upset if we don't get the clock management exactly right.
|
||||
* But in most cases, it should work just fine.
|
||||
*/
|
||||
struct mci_slot_pdata {
|
||||
unsigned int bus_width;
|
||||
int detect_pin;
|
||||
int wp_pin;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mci_platform_data - board-specific MMC/SDcard configuration
|
||||
* @dma_slave: DMA slave interface to use in data transfers, or NULL.
|
||||
* @slot: Per-slot configuration data.
|
||||
*/
|
||||
struct mci_platform_data {
|
||||
struct dma_slave *dma_slave;
|
||||
struct mci_slot_pdata slot[ATMEL_MCI_MAX_NR_SLOTS];
|
||||
};
|
||||
|
||||
#endif /* __ASM_AVR32_ATMEL_MCI_H */
|
||||
|
|
|
@ -1272,10 +1272,14 @@ static struct clk atmel_mci0_pclk = {
|
|||
struct platform_device *__init
|
||||
at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
|
||||
{
|
||||
struct mci_platform_data _data;
|
||||
struct platform_device *pdev;
|
||||
struct dw_dma_slave *dws;
|
||||
|
||||
if (id != 0)
|
||||
if (id != 0 || !data)
|
||||
return NULL;
|
||||
|
||||
/* Must have at least one usable slot */
|
||||
if (!data->slot[0].bus_width && !data->slot[1].bus_width)
|
||||
return NULL;
|
||||
|
||||
pdev = platform_device_alloc("atmel_mci", id);
|
||||
|
@ -1286,28 +1290,76 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
|
|||
ARRAY_SIZE(atmel_mci0_resource)))
|
||||
goto fail;
|
||||
|
||||
if (!data) {
|
||||
data = &_data;
|
||||
memset(data, -1, sizeof(struct mci_platform_data));
|
||||
data->detect_pin = GPIO_PIN_NONE;
|
||||
data->wp_pin = GPIO_PIN_NONE;
|
||||
}
|
||||
if (data->dma_slave)
|
||||
dws = kmemdup(to_dw_dma_slave(data->dma_slave),
|
||||
sizeof(struct dw_dma_slave), GFP_KERNEL);
|
||||
else
|
||||
dws = kzalloc(sizeof(struct dw_dma_slave), GFP_KERNEL);
|
||||
|
||||
dws->slave.dev = &pdev->dev;
|
||||
dws->slave.dma_dev = &dw_dmac0_device.dev;
|
||||
dws->slave.reg_width = DMA_SLAVE_WIDTH_32BIT;
|
||||
dws->cfg_hi = (DWC_CFGH_SRC_PER(0)
|
||||
| DWC_CFGH_DST_PER(1));
|
||||
dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL
|
||||
| DWC_CFGL_HS_SRC_POL);
|
||||
|
||||
data->dma_slave = &dws->slave;
|
||||
|
||||
if (platform_device_add_data(pdev, data,
|
||||
sizeof(struct mci_platform_data)))
|
||||
goto fail;
|
||||
|
||||
select_peripheral(PA(10), PERIPH_A, 0); /* CLK */
|
||||
select_peripheral(PA(11), PERIPH_A, 0); /* CMD */
|
||||
select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
|
||||
select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
|
||||
select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
|
||||
select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
|
||||
/* CLK line is common to both slots */
|
||||
select_peripheral(PA(10), PERIPH_A, 0);
|
||||
|
||||
if (gpio_is_valid(data->detect_pin))
|
||||
at32_select_gpio(data->detect_pin, 0);
|
||||
if (gpio_is_valid(data->wp_pin))
|
||||
at32_select_gpio(data->wp_pin, 0);
|
||||
switch (data->slot[0].bus_width) {
|
||||
case 4:
|
||||
select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
|
||||
select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
|
||||
select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
|
||||
/* fall through */
|
||||
case 1:
|
||||
select_peripheral(PA(11), PERIPH_A, 0); /* CMD */
|
||||
select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
|
||||
|
||||
if (gpio_is_valid(data->slot[0].detect_pin))
|
||||
at32_select_gpio(data->slot[0].detect_pin, 0);
|
||||
if (gpio_is_valid(data->slot[0].wp_pin))
|
||||
at32_select_gpio(data->slot[0].wp_pin, 0);
|
||||
break;
|
||||
case 0:
|
||||
/* Slot is unused */
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
switch (data->slot[1].bus_width) {
|
||||
case 4:
|
||||
select_peripheral(PB(8), PERIPH_B, 0); /* DATA1 */
|
||||
select_peripheral(PB(9), PERIPH_B, 0); /* DATA2 */
|
||||
select_peripheral(PB(10), PERIPH_B, 0); /* DATA3 */
|
||||
/* fall through */
|
||||
case 1:
|
||||
select_peripheral(PB(6), PERIPH_B, 0); /* CMD */
|
||||
select_peripheral(PB(7), PERIPH_B, 0); /* DATA0 */
|
||||
|
||||
if (gpio_is_valid(data->slot[1].detect_pin))
|
||||
at32_select_gpio(data->slot[1].detect_pin, 0);
|
||||
if (gpio_is_valid(data->slot[1].wp_pin))
|
||||
at32_select_gpio(data->slot[1].wp_pin, 0);
|
||||
break;
|
||||
case 0:
|
||||
/* Slot is unused */
|
||||
break;
|
||||
default:
|
||||
if (!data->slot[0].bus_width)
|
||||
goto fail;
|
||||
|
||||
data->slot[1].bus_width = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
atmel_mci0_pclk.dev = &pdev->dev;
|
||||
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
#
|
||||
|
||||
menuconfig MMC
|
||||
tristate "MMC/SD card support"
|
||||
tristate "MMC/SD/SDIO card support"
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
MMC is the "multi-media card" bus protocol.
|
||||
This selects MultiMediaCard, Secure Digital and Secure
|
||||
Digital I/O support.
|
||||
|
||||
If you want MMC support, you should say Y here and also
|
||||
to the specific driver for your MMC interface.
|
||||
If you want MMC/SD/SDIO support, you should say Y here and
|
||||
also to your specific host controller driver.
|
||||
|
||||
config MMC_DEBUG
|
||||
bool "MMC debugging"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# MMC/SD card drivers
|
||||
#
|
||||
|
||||
comment "MMC/SD Card Drivers"
|
||||
comment "MMC/SD/SDIO Card Drivers"
|
||||
|
||||
config MMC_BLOCK
|
||||
tristate "MMC block device driver"
|
||||
|
@ -34,7 +34,6 @@ config MMC_BLOCK_BOUNCE
|
|||
|
||||
config SDIO_UART
|
||||
tristate "SDIO UART/GPS class support"
|
||||
depends on MMC
|
||||
help
|
||||
SDIO function driver for SDIO cards that implements the UART
|
||||
class, as well as the GPS class which appears like a UART.
|
||||
|
|
|
@ -58,7 +58,6 @@ struct mmc_blk_data {
|
|||
struct mmc_queue queue;
|
||||
|
||||
unsigned int usage;
|
||||
unsigned int block_bits;
|
||||
unsigned int read_only;
|
||||
};
|
||||
|
||||
|
@ -216,8 +215,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
|||
struct mmc_blk_data *md = mq->data;
|
||||
struct mmc_card *card = md->queue.card;
|
||||
struct mmc_blk_request brq;
|
||||
int ret = 1, data_size, i;
|
||||
struct scatterlist *sg;
|
||||
int ret = 1;
|
||||
|
||||
mmc_claim_host(card->host);
|
||||
|
||||
|
@ -233,13 +231,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
|||
if (!mmc_card_blockaddr(card))
|
||||
brq.cmd.arg <<= 9;
|
||||
brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
brq.data.blksz = 1 << md->block_bits;
|
||||
brq.data.blksz = 512;
|
||||
brq.stop.opcode = MMC_STOP_TRANSMISSION;
|
||||
brq.stop.arg = 0;
|
||||
brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
|
||||
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
|
||||
if (brq.data.blocks > card->host->max_blk_count)
|
||||
brq.data.blocks = card->host->max_blk_count;
|
||||
brq.data.blocks = req->nr_sectors;
|
||||
|
||||
if (brq.data.blocks > 1) {
|
||||
/* SPI multiblock writes terminate using a special
|
||||
|
@ -271,24 +267,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
|||
|
||||
mmc_queue_bounce_pre(mq);
|
||||
|
||||
/*
|
||||
* Adjust the sg list so it is the same size as the
|
||||
* request.
|
||||
*/
|
||||
if (brq.data.blocks !=
|
||||
(req->nr_sectors >> (md->block_bits - 9))) {
|
||||
data_size = brq.data.blocks * brq.data.blksz;
|
||||
for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
|
||||
data_size -= sg->length;
|
||||
if (data_size <= 0) {
|
||||
sg->length += data_size;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
brq.data.sg_len = i;
|
||||
}
|
||||
|
||||
mmc_wait_for_req(card->host, &brq.mrq);
|
||||
|
||||
mmc_queue_bounce_post(mq);
|
||||
|
@ -373,16 +351,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
|||
if (rq_data_dir(req) != READ) {
|
||||
if (mmc_card_sd(card)) {
|
||||
u32 blocks;
|
||||
unsigned int bytes;
|
||||
|
||||
blocks = mmc_sd_num_wr_blocks(card);
|
||||
if (blocks != (u32)-1) {
|
||||
if (card->csd.write_partial)
|
||||
bytes = blocks << md->block_bits;
|
||||
else
|
||||
bytes = blocks << 9;
|
||||
spin_lock_irq(&md->lock);
|
||||
ret = __blk_end_request(req, 0, bytes);
|
||||
ret = __blk_end_request(req, 0, blocks << 9);
|
||||
spin_unlock_irq(&md->lock);
|
||||
}
|
||||
} else {
|
||||
|
@ -432,13 +405,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
|
|||
*/
|
||||
md->read_only = mmc_blk_readonly(card);
|
||||
|
||||
/*
|
||||
* Both SD and MMC specifications state (although a bit
|
||||
* unclearly in the MMC case) that a block size of 512
|
||||
* bytes must always be supported by the card.
|
||||
*/
|
||||
md->block_bits = 9;
|
||||
|
||||
md->disk = alloc_disk(1 << MMC_SHIFT);
|
||||
if (md->disk == NULL) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -476,7 +442,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
|
|||
|
||||
sprintf(md->disk->disk_name, "mmcblk%d", devidx);
|
||||
|
||||
blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
|
||||
blk_queue_hardsect_size(md->queue.queue, 512);
|
||||
|
||||
if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
|
||||
/*
|
||||
|
@ -514,7 +480,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
|
|||
|
||||
mmc_claim_host(card->host);
|
||||
cmd.opcode = MMC_SET_BLOCKLEN;
|
||||
cmd.arg = 1 << md->block_bits;
|
||||
cmd.arg = 512;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
|
||||
err = mmc_wait_for_cmd(card->host, &cmd, 5);
|
||||
mmc_release_host(card->host);
|
||||
|
|
|
@ -31,7 +31,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
|
|||
/*
|
||||
* We only like normal block requests.
|
||||
*/
|
||||
if (!blk_fs_request(req) && !blk_pc_request(req)) {
|
||||
if (!blk_fs_request(req)) {
|
||||
blk_dump_rq_flags(req, "MMC bad request");
|
||||
return BLKPREP_KILL;
|
||||
}
|
||||
|
@ -131,6 +131,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
|
|||
mq->req = NULL;
|
||||
|
||||
blk_queue_prep_rq(mq->queue, mmc_prep_request);
|
||||
blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL);
|
||||
|
||||
#ifdef CONFIG_MMC_BLOCK_BOUNCE
|
||||
if (host->max_hw_segs == 1) {
|
||||
|
@ -142,12 +143,19 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
|
|||
bouncesz = host->max_req_size;
|
||||
if (bouncesz > host->max_seg_size)
|
||||
bouncesz = host->max_seg_size;
|
||||
if (bouncesz > (host->max_blk_count * 512))
|
||||
bouncesz = host->max_blk_count * 512;
|
||||
|
||||
mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
|
||||
if (!mq->bounce_buf) {
|
||||
printk(KERN_WARNING "%s: unable to allocate "
|
||||
"bounce buffer\n", mmc_card_name(card));
|
||||
} else {
|
||||
if (bouncesz > 512) {
|
||||
mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
|
||||
if (!mq->bounce_buf) {
|
||||
printk(KERN_WARNING "%s: unable to "
|
||||
"allocate bounce buffer\n",
|
||||
mmc_card_name(card));
|
||||
}
|
||||
}
|
||||
|
||||
if (mq->bounce_buf) {
|
||||
blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
|
||||
blk_queue_max_sectors(mq->queue, bouncesz / 512);
|
||||
blk_queue_max_phys_segments(mq->queue, bouncesz / 512);
|
||||
|
@ -175,7 +183,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
|
|||
|
||||
if (!mq->bounce_buf) {
|
||||
blk_queue_bounce_limit(mq->queue, limit);
|
||||
blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
|
||||
blk_queue_max_sectors(mq->queue,
|
||||
min(host->max_blk_count, host->max_req_size / 512));
|
||||
blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
|
||||
blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
|
||||
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
|
||||
|
|
|
@ -248,8 +248,12 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
|
|||
|
||||
sg_init_one(&sg, data_buf, len);
|
||||
|
||||
if (card)
|
||||
mmc_set_data_timeout(&data, card);
|
||||
/*
|
||||
* The spec states that CSR and CID accesses have a timeout
|
||||
* of 64 clock cycles.
|
||||
*/
|
||||
data.timeout_ns = 0;
|
||||
data.timeout_clks = 64;
|
||||
|
||||
mmc_wait_for_req(host, &mrq);
|
||||
|
||||
|
|
|
@ -164,6 +164,36 @@ static int sdio_enable_wide(struct mmc_card *card)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if the card supports high-speed mode and, if so, switch to it.
|
||||
*/
|
||||
static int sdio_enable_hs(struct mmc_card *card)
|
||||
{
|
||||
int ret;
|
||||
u8 speed;
|
||||
|
||||
if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
|
||||
return 0;
|
||||
|
||||
if (!card->cccr.high_speed)
|
||||
return 0;
|
||||
|
||||
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
speed |= SDIO_SPEED_EHS;
|
||||
|
||||
ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mmc_card_set_highspeed(card);
|
||||
mmc_set_timing(card->host, MMC_TIMING_SD_HS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Host is being removed. Free up the current card.
|
||||
*/
|
||||
|
@ -333,10 +363,26 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
|
|||
goto remove;
|
||||
|
||||
/*
|
||||
* No support for high-speed yet, so just set
|
||||
* the card's maximum speed.
|
||||
* Switch to high-speed (if supported).
|
||||
*/
|
||||
mmc_set_clock(host, card->cis.max_dtr);
|
||||
err = sdio_enable_hs(card);
|
||||
if (err)
|
||||
goto remove;
|
||||
|
||||
/*
|
||||
* Change to the card's maximum speed.
|
||||
*/
|
||||
if (mmc_card_highspeed(card)) {
|
||||
/*
|
||||
* The SDIO specification doesn't mention how
|
||||
* the CIS transfer speed register relates to
|
||||
* high-speed, but it seems that 50 MHz is
|
||||
* mandatory.
|
||||
*/
|
||||
mmc_set_clock(host, 50000000);
|
||||
} else {
|
||||
mmc_set_clock(host, card->cis.max_dtr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch to wider bus (if supported).
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* Created: June 18, 2007
|
||||
* Copyright: MontaVista Software Inc.
|
||||
*
|
||||
* Copyright 2008 Pierre Ossman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
|
@ -107,11 +109,14 @@ static int sdio_irq_thread(void *_host)
|
|||
|
||||
/*
|
||||
* Give other threads a chance to run in the presence of
|
||||
* errors. FIXME: determine if due to card removal and
|
||||
* possibly exit this thread if so.
|
||||
* errors.
|
||||
*/
|
||||
if (ret < 0)
|
||||
ssleep(1);
|
||||
if (ret < 0) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (!kthread_should_stop())
|
||||
schedule_timeout(HZ);
|
||||
set_current_state(TASK_RUNNING);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adaptive polling frequency based on the assumption
|
||||
|
@ -154,7 +159,8 @@ static int sdio_card_irq_get(struct mmc_card *card)
|
|||
if (!host->sdio_irqs++) {
|
||||
atomic_set(&host->sdio_irq_thread_abort, 0);
|
||||
host->sdio_irq_thread =
|
||||
kthread_run(sdio_irq_thread, host, "ksdiorqd");
|
||||
kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",
|
||||
mmc_hostname(host));
|
||||
if (IS_ERR(host->sdio_irq_thread)) {
|
||||
int err = PTR_ERR(host->sdio_irq_thread);
|
||||
host->sdio_irqs--;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# MMC/SD host controller drivers
|
||||
#
|
||||
|
||||
comment "MMC/SD Host Controller Drivers"
|
||||
comment "MMC/SD/SDIO Host Controller Drivers"
|
||||
|
||||
config MMC_ARMMMCI
|
||||
tristate "ARM AMBA Multimedia Card Interface support"
|
||||
|
@ -114,6 +114,17 @@ config MMC_ATMELMCI
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config MMC_ATMELMCI_DMA
|
||||
bool "Atmel MCI DMA support (EXPERIMENTAL)"
|
||||
depends on MMC_ATMELMCI && DMA_ENGINE && EXPERIMENTAL
|
||||
help
|
||||
Say Y here to have the Atmel MCI driver use a DMA engine to
|
||||
do data transfers and thus increase the throughput and
|
||||
reduce the CPU utilization. Note that this is highly
|
||||
experimental and may cause the driver to lock up.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config MMC_IMX
|
||||
tristate "Motorola i.MX Multimedia Card Interface support"
|
||||
depends on ARCH_IMX
|
||||
|
@ -141,21 +152,22 @@ config MMC_TIFM_SD
|
|||
module will be called tifm_sd.
|
||||
|
||||
config MMC_SPI
|
||||
tristate "MMC/SD over SPI"
|
||||
depends on MMC && SPI_MASTER && !HIGHMEM && HAS_DMA
|
||||
tristate "MMC/SD/SDIO over SPI"
|
||||
depends on SPI_MASTER && !HIGHMEM && HAS_DMA
|
||||
select CRC7
|
||||
select CRC_ITU_T
|
||||
help
|
||||
Some systems accss MMC/SD cards using a SPI controller instead of
|
||||
using a "native" MMC/SD controller. This has a disadvantage of
|
||||
being relatively high overhead, but a compensating advantage of
|
||||
working on many systems without dedicated MMC/SD controllers.
|
||||
Some systems accss MMC/SD/SDIO cards using a SPI controller
|
||||
instead of using a "native" MMC/SD/SDIO controller. This has a
|
||||
disadvantage of being relatively high overhead, but a compensating
|
||||
advantage of working on many systems without dedicated MMC/SD/SDIO
|
||||
controllers.
|
||||
|
||||
If unsure, or if your system has no SPI master driver, say N.
|
||||
|
||||
config MMC_S3C
|
||||
tristate "Samsung S3C SD/MMC Card Interface support"
|
||||
depends on ARCH_S3C2410 && MMC
|
||||
depends on ARCH_S3C2410
|
||||
help
|
||||
This selects a driver for the MCI interface found in
|
||||
Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
|
||||
|
@ -166,7 +178,7 @@ config MMC_S3C
|
|||
|
||||
config MMC_SDRICOH_CS
|
||||
tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && MMC && PCI && PCMCIA
|
||||
depends on EXPERIMENTAL && PCI && PCMCIA
|
||||
help
|
||||
Say Y here if your Notebook reports a Ricoh Bay1Controller PCMCIA
|
||||
card whenever you insert a MMC or SD card into the card slot.
|
||||
|
|
|
@ -25,8 +25,10 @@
|
|||
#define MCI_SDCR 0x000c /* SD Card / SDIO */
|
||||
# define MCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */
|
||||
# define MCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */
|
||||
# define MCI_SDCBUS_1BIT ( 0 << 7) /* 1-bit data bus */
|
||||
# define MCI_SDCBUS_4BIT ( 1 << 7) /* 4-bit data bus */
|
||||
# define MCI_SDCSEL_MASK ( 3 << 0)
|
||||
# define MCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */
|
||||
# define MCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */
|
||||
# define MCI_SDCBUS_MASK ( 3 << 6)
|
||||
#define MCI_ARGR 0x0010 /* Command Argument */
|
||||
#define MCI_CMDR 0x0014 /* Command */
|
||||
# define MCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -95,8 +95,6 @@
|
|||
* reads which takes nowhere near that long. Older cards may be able to use
|
||||
* shorter timeouts ... but why bother?
|
||||
*/
|
||||
#define readblock_timeout ktime_set(0, 100 * 1000 * 1000)
|
||||
#define writeblock_timeout ktime_set(0, 250 * 1000 * 1000)
|
||||
#define r1b_timeout ktime_set(3, 0)
|
||||
|
||||
|
||||
|
@ -220,9 +218,9 @@ mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout)
|
|||
return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
|
||||
}
|
||||
|
||||
static int mmc_spi_readtoken(struct mmc_spi_host *host)
|
||||
static int mmc_spi_readtoken(struct mmc_spi_host *host, ktime_t timeout)
|
||||
{
|
||||
return mmc_spi_skip(host, readblock_timeout, 1, 0xff);
|
||||
return mmc_spi_skip(host, timeout, 1, 0xff);
|
||||
}
|
||||
|
||||
|
||||
|
@ -605,7 +603,8 @@ mmc_spi_setup_data_message(
|
|||
* Return negative errno, else success.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
struct spi_device *spi = host->spi;
|
||||
int status, i;
|
||||
|
@ -673,7 +672,7 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
|
|||
if (scratch->status[i] != 0)
|
||||
return 0;
|
||||
}
|
||||
return mmc_spi_wait_unbusy(host, writeblock_timeout);
|
||||
return mmc_spi_wait_unbusy(host, timeout);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -693,7 +692,8 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
|
|||
* STOP_TRANSMISSION command.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
struct spi_device *spi = host->spi;
|
||||
int status;
|
||||
|
@ -707,7 +707,7 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
|
|||
return status;
|
||||
status = scratch->status[0];
|
||||
if (status == 0xff || status == 0)
|
||||
status = mmc_spi_readtoken(host);
|
||||
status = mmc_spi_readtoken(host, timeout);
|
||||
|
||||
if (status == SPI_TOKEN_SINGLE) {
|
||||
if (host->dma_dev) {
|
||||
|
@ -778,6 +778,8 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
|
|||
struct scatterlist *sg;
|
||||
unsigned n_sg;
|
||||
int multiple = (data->blocks > 1);
|
||||
u32 clock_rate;
|
||||
ktime_t timeout;
|
||||
|
||||
if (data->flags & MMC_DATA_READ)
|
||||
direction = DMA_FROM_DEVICE;
|
||||
|
@ -786,6 +788,14 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
|
|||
mmc_spi_setup_data_message(host, multiple, direction);
|
||||
t = &host->t;
|
||||
|
||||
if (t->speed_hz)
|
||||
clock_rate = t->speed_hz;
|
||||
else
|
||||
clock_rate = spi->max_speed_hz;
|
||||
|
||||
timeout = ktime_add_ns(ktime_set(0, 0), data->timeout_ns +
|
||||
data->timeout_clks * 1000000 / clock_rate);
|
||||
|
||||
/* Handle scatterlist segments one at a time, with synch for
|
||||
* each 512-byte block
|
||||
*/
|
||||
|
@ -832,9 +842,9 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
|
|||
t->len);
|
||||
|
||||
if (direction == DMA_TO_DEVICE)
|
||||
status = mmc_spi_writeblock(host, t);
|
||||
status = mmc_spi_writeblock(host, t, timeout);
|
||||
else
|
||||
status = mmc_spi_readblock(host, t);
|
||||
status = mmc_spi_readblock(host, t, timeout);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
||||
|
@ -917,7 +927,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
|
|||
if (scratch->status[tmp] != 0)
|
||||
return;
|
||||
}
|
||||
tmp = mmc_spi_wait_unbusy(host, writeblock_timeout);
|
||||
tmp = mmc_spi_wait_unbusy(host, timeout);
|
||||
if (tmp < 0 && !data->error)
|
||||
data->error = tmp;
|
||||
}
|
||||
|
|
|
@ -144,7 +144,8 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
|
|||
SDHCI_QUIRK_32BIT_DMA_SIZE |
|
||||
SDHCI_QUIRK_32BIT_ADMA_SIZE |
|
||||
SDHCI_QUIRK_RESET_AFTER_REQUEST |
|
||||
SDHCI_QUIRK_BROKEN_SMALL_PIO;
|
||||
SDHCI_QUIRK_BROKEN_SMALL_PIO |
|
||||
SDHCI_QUIRK_FORCE_HIGHSPEED;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -177,7 +177,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
|
|||
{
|
||||
unsigned long flags;
|
||||
size_t blksize, len, chunk;
|
||||
u32 scratch;
|
||||
u32 uninitialized_var(scratch);
|
||||
u8 *buf;
|
||||
|
||||
DBG("PIO reading\n");
|
||||
|
@ -1154,7 +1154,7 @@ static void sdhci_tasklet_card(unsigned long param)
|
|||
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
mmc_detect_change(host->mmc, msecs_to_jiffies(500));
|
||||
mmc_detect_change(host->mmc, msecs_to_jiffies(200));
|
||||
}
|
||||
|
||||
static void sdhci_tasklet_finish(unsigned long param)
|
||||
|
@ -1266,9 +1266,31 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
|
|||
SDHCI_INT_INDEX))
|
||||
host->cmd->error = -EILSEQ;
|
||||
|
||||
if (host->cmd->error)
|
||||
if (host->cmd->error) {
|
||||
tasklet_schedule(&host->finish_tasklet);
|
||||
else if (intmask & SDHCI_INT_RESPONSE)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The host can send and interrupt when the busy state has
|
||||
* ended, allowing us to wait without wasting CPU cycles.
|
||||
* Unfortunately this is overloaded on the "data complete"
|
||||
* interrupt, so we need to take some care when handling
|
||||
* it.
|
||||
*
|
||||
* Note: The 1.0 specification is a bit ambiguous about this
|
||||
* feature so there might be some problems with older
|
||||
* controllers.
|
||||
*/
|
||||
if (host->cmd->flags & MMC_RSP_BUSY) {
|
||||
if (host->cmd->data)
|
||||
DBG("Cannot wait for busy signal when also "
|
||||
"doing a data transfer");
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
if (intmask & SDHCI_INT_RESPONSE)
|
||||
sdhci_finish_command(host);
|
||||
}
|
||||
|
||||
|
@ -1278,11 +1300,16 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
|
|||
|
||||
if (!host->data) {
|
||||
/*
|
||||
* A data end interrupt is sent together with the response
|
||||
* for the stop command.
|
||||
* The "data complete" interrupt is also used to
|
||||
* indicate that a busy state has ended. See comment
|
||||
* above in sdhci_cmd_irq().
|
||||
*/
|
||||
if (intmask & SDHCI_INT_DATA_END)
|
||||
return;
|
||||
if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
|
||||
if (intmask & SDHCI_INT_DATA_END) {
|
||||
sdhci_finish_command(host);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
|
||||
"though no data operation was in progress.\n",
|
||||
|
@ -1604,7 +1631,8 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
mmc->f_max = host->max_clk;
|
||||
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
|
||||
|
||||
if (caps & SDHCI_CAN_DO_HISPD)
|
||||
if ((caps & SDHCI_CAN_DO_HISPD) ||
|
||||
(host->quirks & SDHCI_QUIRK_FORCE_HIGHSPEED))
|
||||
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
|
||||
|
||||
mmc->ocr_avail = 0;
|
||||
|
|
|
@ -208,6 +208,8 @@ struct sdhci_host {
|
|||
#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12)
|
||||
/* Controller has an issue with buffer bits for small transfers */
|
||||
#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13)
|
||||
/* Controller supports high speed but doesn't have the caps bit set */
|
||||
#define SDHCI_QUIRK_FORCE_HIGHSPEED (1<<14)
|
||||
|
||||
int irq; /* Device IRQ */
|
||||
void __iomem * ioaddr; /* Mapped address */
|
||||
|
|
|
@ -65,7 +65,7 @@ struct mmc_host_ops {
|
|||
* -ENOSYS when not supported (equal to NULL callback)
|
||||
* or a negative errno value when something bad happened
|
||||
*
|
||||
* Return values for the get_ro callback should be:
|
||||
* Return values for the get_cd callback should be:
|
||||
* 0 for a absent card
|
||||
* 1 for a present card
|
||||
* -ENOSYS when not supported (equal to NULL callback)
|
||||
|
|
Загрузка…
Ссылка в новой задаче