Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/drzeus/mmc: mmc: correct request error handling mmc: Flush block queue when removing card mmc: sdhci high speed support mmc: Support for high speed SD cards mmc: Fix mmc_delay() function mmc: Add support for mmc v4 wide-bus modes [PATCH] mmc: Add support for mmc v4 high speed mode trivial change for mmc/Kconfig: MMC_PXA does not mean only PXA255 Make general code cleanups Add MMC_CAP_{MULTIWRITE,BYTEBLOCK} flags Platform device error handling cleanup Move register definitions away from the header file Change OMAP_MMC_{READ,WRITE} macros to use the host pointer Replace base with virt_base and phys_base mmc: constify mmc_host_ops vectors mmc: remove kernel_thread()
This commit is contained in:
commit
cdb54fac35
17 changed files with 592 additions and 228 deletions
|
@ -40,7 +40,7 @@ config MMC_ARMMMCI
|
|||
If unsure, say N.
|
||||
|
||||
config MMC_PXA
|
||||
tristate "Intel PXA255 Multimedia Card Interface support"
|
||||
tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
|
||||
depends on ARCH_PXA && MMC
|
||||
help
|
||||
This selects the Intel(R) PXA(R) Multimedia card Interface.
|
||||
|
|
|
@ -793,7 +793,7 @@ int at91_mci_get_ro(struct mmc_host *mmc)
|
|||
return read_only;
|
||||
}
|
||||
|
||||
static struct mmc_host_ops at91_mci_ops = {
|
||||
static const struct mmc_host_ops at91_mci_ops = {
|
||||
.request = at91_mci_request,
|
||||
.set_ios = at91_mci_set_ios,
|
||||
.get_ro = at91_mci_get_ro,
|
||||
|
|
|
@ -875,7 +875,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host)
|
|||
host->rx_chan = rxchan;
|
||||
}
|
||||
|
||||
struct mmc_host_ops au1xmmc_ops = {
|
||||
struct const mmc_host_ops au1xmmc_ops = {
|
||||
.request = au1xmmc_request,
|
||||
.set_ios = au1xmmc_set_ios,
|
||||
};
|
||||
|
|
|
@ -877,7 +877,7 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
}
|
||||
}
|
||||
|
||||
static struct mmc_host_ops imxmci_ops = {
|
||||
static const struct mmc_host_ops imxmci_ops = {
|
||||
.request = imxmci_request,
|
||||
.set_ios = imxmci_set_ios,
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
|
||||
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
|
||||
* SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
|
||||
* MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -396,23 +397,23 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
|
|||
return err;
|
||||
|
||||
/*
|
||||
* Default bus width is 1 bit.
|
||||
*/
|
||||
host->ios.bus_width = MMC_BUS_WIDTH_1;
|
||||
|
||||
/*
|
||||
* We can only change the bus width of the selected
|
||||
* card so therefore we have to put the handling
|
||||
* We can only change the bus width of SD cards when
|
||||
* they are selected so we have to put the handling
|
||||
* here.
|
||||
*
|
||||
* The card is in 1 bit mode by default so
|
||||
* we only need to change if it supports the
|
||||
* wider version.
|
||||
*/
|
||||
if (host->caps & MMC_CAP_4_BIT_DATA) {
|
||||
if (mmc_card_sd(card) &&
|
||||
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
|
||||
|
||||
/*
|
||||
* The card is in 1 bit mode by default so
|
||||
* we only need to change if it supports the
|
||||
* wider version.
|
||||
*/
|
||||
if (mmc_card_sd(card) &&
|
||||
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
|
||||
* Default bus width is 1 bit.
|
||||
*/
|
||||
host->ios.bus_width = MMC_BUS_WIDTH_1;
|
||||
|
||||
if (host->caps & MMC_CAP_4_BIT_DATA) {
|
||||
struct mmc_command cmd;
|
||||
cmd.opcode = SD_APP_SET_BUS_WIDTH;
|
||||
cmd.arg = SD_BUS_WIDTH_4;
|
||||
|
@ -453,11 +454,11 @@ static void mmc_deselect_cards(struct mmc_host *host)
|
|||
|
||||
static inline void mmc_delay(unsigned int ms)
|
||||
{
|
||||
if (ms < HZ / 1000) {
|
||||
yield();
|
||||
if (ms < 1000 / HZ) {
|
||||
cond_resched();
|
||||
mdelay(ms);
|
||||
} else {
|
||||
msleep_interruptible (ms);
|
||||
msleep(ms);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -953,6 +954,137 @@ static void mmc_read_csds(struct mmc_host *host)
|
|||
}
|
||||
}
|
||||
|
||||
static void mmc_process_ext_csds(struct mmc_host *host)
|
||||
{
|
||||
int err;
|
||||
struct mmc_card *card;
|
||||
|
||||
struct mmc_request mrq;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
|
||||
struct scatterlist sg;
|
||||
|
||||
/*
|
||||
* As the ext_csd is so large and mostly unused, we don't store the
|
||||
* raw block in mmc_card.
|
||||
*/
|
||||
u8 *ext_csd;
|
||||
ext_csd = kmalloc(512, GFP_KERNEL);
|
||||
if (!ext_csd) {
|
||||
printk("%s: could not allocate a buffer to receive the ext_csd."
|
||||
"mmc v4 cards will be treated as v3.\n",
|
||||
mmc_hostname(host));
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_entry(card, &host->cards, node) {
|
||||
if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
|
||||
continue;
|
||||
if (mmc_card_sd(card))
|
||||
continue;
|
||||
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
|
||||
continue;
|
||||
|
||||
err = mmc_select_card(host, card);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
mmc_card_set_dead(card);
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = MMC_SEND_EXT_CSD;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
mmc_set_data_timeout(&data, card, 0);
|
||||
|
||||
data.blksz = 512;
|
||||
data.blocks = 1;
|
||||
data.flags = MMC_DATA_READ;
|
||||
data.sg = &sg;
|
||||
data.sg_len = 1;
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
|
||||
sg_init_one(&sg, ext_csd, 512);
|
||||
|
||||
mmc_wait_for_req(host, &mrq);
|
||||
|
||||
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
|
||||
mmc_card_set_dead(card);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (ext_csd[EXT_CSD_CARD_TYPE]) {
|
||||
case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
|
||||
card->ext_csd.hs_max_dtr = 52000000;
|
||||
break;
|
||||
case EXT_CSD_CARD_TYPE_26:
|
||||
card->ext_csd.hs_max_dtr = 26000000;
|
||||
break;
|
||||
default:
|
||||
/* MMC v4 spec says this cannot happen */
|
||||
printk("%s: card is mmc v4 but doesn't support "
|
||||
"any high-speed modes.\n",
|
||||
mmc_hostname(card->host));
|
||||
mmc_card_set_bad(card);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Activate highspeed support. */
|
||||
cmd.opcode = MMC_SWITCH;
|
||||
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
|
||||
(EXT_CSD_HS_TIMING << 16) |
|
||||
(1 << 8) |
|
||||
EXT_CSD_CMD_SET_NORMAL;
|
||||
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
printk("%s: failed to switch card to mmc v4 "
|
||||
"high-speed mode.\n",
|
||||
mmc_hostname(card->host));
|
||||
continue;
|
||||
}
|
||||
|
||||
mmc_card_set_highspeed(card);
|
||||
|
||||
/* Check for host support for wide-bus modes. */
|
||||
if (!(host->caps & MMC_CAP_4_BIT_DATA)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Activate 4-bit support. */
|
||||
cmd.opcode = MMC_SWITCH;
|
||||
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
|
||||
(EXT_CSD_BUS_WIDTH << 16) |
|
||||
(EXT_CSD_BUS_WIDTH_4 << 8) |
|
||||
EXT_CSD_CMD_SET_NORMAL;
|
||||
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
printk("%s: failed to switch card to "
|
||||
"mmc v4 4-bit bus mode.\n",
|
||||
mmc_hostname(card->host));
|
||||
continue;
|
||||
}
|
||||
|
||||
host->ios.bus_width = MMC_BUS_WIDTH_4;
|
||||
}
|
||||
|
||||
kfree(ext_csd);
|
||||
|
||||
mmc_deselect_cards(host);
|
||||
}
|
||||
|
||||
static void mmc_read_scrs(struct mmc_host *host)
|
||||
{
|
||||
int err;
|
||||
|
@ -1025,14 +1157,133 @@ static void mmc_read_scrs(struct mmc_host *host)
|
|||
mmc_deselect_cards(host);
|
||||
}
|
||||
|
||||
static void mmc_read_switch_caps(struct mmc_host *host)
|
||||
{
|
||||
int err;
|
||||
struct mmc_card *card;
|
||||
struct mmc_request mrq;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
unsigned char *status;
|
||||
struct scatterlist sg;
|
||||
|
||||
status = kmalloc(64, GFP_KERNEL);
|
||||
if (!status) {
|
||||
printk(KERN_WARNING "%s: Unable to allocate buffer for "
|
||||
"reading switch capabilities.\n",
|
||||
mmc_hostname(host));
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_entry(card, &host->cards, node) {
|
||||
if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
|
||||
continue;
|
||||
if (!mmc_card_sd(card))
|
||||
continue;
|
||||
if (card->scr.sda_vsn < SCR_SPEC_VER_1)
|
||||
continue;
|
||||
|
||||
err = mmc_select_card(host, card);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
mmc_card_set_dead(card);
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = SD_SWITCH;
|
||||
cmd.arg = 0x00FFFFF1;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
mmc_set_data_timeout(&data, card, 0);
|
||||
|
||||
data.blksz = 64;
|
||||
data.blocks = 1;
|
||||
data.flags = MMC_DATA_READ;
|
||||
data.sg = &sg;
|
||||
data.sg_len = 1;
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
|
||||
sg_init_one(&sg, status, 64);
|
||||
|
||||
mmc_wait_for_req(host, &mrq);
|
||||
|
||||
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
|
||||
mmc_card_set_dead(card);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status[13] & 0x02)
|
||||
card->sw_caps.hs_max_dtr = 50000000;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = SD_SWITCH;
|
||||
cmd.arg = 0x80FFFFF1;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
mmc_set_data_timeout(&data, card, 0);
|
||||
|
||||
data.blksz = 64;
|
||||
data.blocks = 1;
|
||||
data.flags = MMC_DATA_READ;
|
||||
data.sg = &sg;
|
||||
data.sg_len = 1;
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
|
||||
sg_init_one(&sg, status, 64);
|
||||
|
||||
mmc_wait_for_req(host, &mrq);
|
||||
|
||||
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
|
||||
mmc_card_set_dead(card);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((status[16] & 0xF) != 1) {
|
||||
printk(KERN_WARNING "%s: Problem switching card "
|
||||
"into high-speed mode!\n",
|
||||
mmc_hostname(host));
|
||||
continue;
|
||||
}
|
||||
|
||||
mmc_card_set_highspeed(card);
|
||||
}
|
||||
|
||||
kfree(status);
|
||||
|
||||
mmc_deselect_cards(host);
|
||||
}
|
||||
|
||||
static unsigned int mmc_calculate_clock(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_card *card;
|
||||
unsigned int max_dtr = host->f_max;
|
||||
|
||||
list_for_each_entry(card, &host->cards, node)
|
||||
if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr)
|
||||
max_dtr = card->csd.max_dtr;
|
||||
if (!mmc_card_dead(card)) {
|
||||
if (mmc_card_highspeed(card) && mmc_card_sd(card)) {
|
||||
if (max_dtr > card->sw_caps.hs_max_dtr)
|
||||
max_dtr = card->sw_caps.hs_max_dtr;
|
||||
} else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) {
|
||||
if (max_dtr > card->ext_csd.hs_max_dtr)
|
||||
max_dtr = card->ext_csd.hs_max_dtr;
|
||||
} else if (max_dtr > card->csd.max_dtr) {
|
||||
max_dtr = card->csd.max_dtr;
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("%s: selected %d.%03dMHz transfer rate\n",
|
||||
mmc_hostname(host),
|
||||
|
@ -1150,8 +1401,11 @@ static void mmc_setup(struct mmc_host *host)
|
|||
|
||||
mmc_read_csds(host);
|
||||
|
||||
if (host->mode == MMC_MODE_SD)
|
||||
if (host->mode == MMC_MODE_SD) {
|
||||
mmc_read_scrs(host);
|
||||
mmc_read_switch_caps(host);
|
||||
} else
|
||||
mmc_process_ext_csds(host);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -83,7 +83,6 @@ static void mmc_blk_put(struct mmc_blk_data *md)
|
|||
md->usage--;
|
||||
if (md->usage == 0) {
|
||||
put_disk(md->disk);
|
||||
mmc_cleanup_queue(&md->queue);
|
||||
kfree(md);
|
||||
}
|
||||
mutex_unlock(&open_lock);
|
||||
|
@ -225,10 +224,10 @@ 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;
|
||||
int ret = 1;
|
||||
|
||||
if (mmc_card_claim_host(card))
|
||||
goto cmd_err;
|
||||
goto flush_queue;
|
||||
|
||||
do {
|
||||
struct mmc_command cmd;
|
||||
|
@ -345,8 +344,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
|||
return 1;
|
||||
|
||||
cmd_err:
|
||||
ret = 1;
|
||||
|
||||
/*
|
||||
* If this is an SD card and we're writing, we can first
|
||||
* mark the known good sectors as ok.
|
||||
|
@ -380,6 +377,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
|||
|
||||
mmc_card_release_host(card);
|
||||
|
||||
flush_queue:
|
||||
spin_lock_irq(&md->lock);
|
||||
while (ret) {
|
||||
ret = end_that_request_chunk(req, 0,
|
||||
|
@ -553,12 +551,11 @@ static void mmc_blk_remove(struct mmc_card *card)
|
|||
if (md) {
|
||||
int devidx;
|
||||
|
||||
/* Stop new requests from getting into the queue */
|
||||
del_gendisk(md->disk);
|
||||
|
||||
/*
|
||||
* I think this is needed.
|
||||
*/
|
||||
md->disk->queue = NULL;
|
||||
/* Then flush out any already in there */
|
||||
mmc_cleanup_queue(&md->queue);
|
||||
|
||||
devidx = md->disk->first_minor >> MMC_SHIFT;
|
||||
__clear_bit(devidx, dev_use);
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include "mmc_queue.h"
|
||||
|
||||
#define MMC_QUEUE_EXIT (1 << 0)
|
||||
#define MMC_QUEUE_SUSPENDED (1 << 1)
|
||||
#define MMC_QUEUE_SUSPENDED (1 << 0)
|
||||
|
||||
/*
|
||||
* Prepare a MMC request. Essentially, this means passing the
|
||||
|
@ -59,7 +59,6 @@ static int mmc_queue_thread(void *d)
|
|||
{
|
||||
struct mmc_queue *mq = d;
|
||||
struct request_queue *q = mq->queue;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
/*
|
||||
* Set iothread to ensure that we aren't put to sleep by
|
||||
|
@ -67,12 +66,7 @@ static int mmc_queue_thread(void *d)
|
|||
*/
|
||||
current->flags |= PF_MEMALLOC|PF_NOFREEZE;
|
||||
|
||||
daemonize("mmcqd");
|
||||
|
||||
complete(&mq->thread_complete);
|
||||
|
||||
down(&mq->thread_sem);
|
||||
add_wait_queue(&mq->thread_wq, &wait);
|
||||
do {
|
||||
struct request *req = NULL;
|
||||
|
||||
|
@ -84,7 +78,7 @@ static int mmc_queue_thread(void *d)
|
|||
spin_unlock_irq(q->queue_lock);
|
||||
|
||||
if (!req) {
|
||||
if (mq->flags & MMC_QUEUE_EXIT)
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
up(&mq->thread_sem);
|
||||
schedule();
|
||||
|
@ -95,10 +89,8 @@ static int mmc_queue_thread(void *d)
|
|||
|
||||
mq->issue_fn(mq, req);
|
||||
} while (1);
|
||||
remove_wait_queue(&mq->thread_wq, &wait);
|
||||
up(&mq->thread_sem);
|
||||
|
||||
complete_and_exit(&mq->thread_complete, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -111,9 +103,22 @@ static int mmc_queue_thread(void *d)
|
|||
static void mmc_request(request_queue_t *q)
|
||||
{
|
||||
struct mmc_queue *mq = q->queuedata;
|
||||
struct request *req;
|
||||
int ret;
|
||||
|
||||
if (!mq) {
|
||||
printk(KERN_ERR "MMC: killing requests for dead queue\n");
|
||||
while ((req = elv_next_request(q)) != NULL) {
|
||||
do {
|
||||
ret = end_that_request_chunk(req, 0,
|
||||
req->current_nr_sectors << 9);
|
||||
} while (ret);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mq->req)
|
||||
wake_up(&mq->thread_wq);
|
||||
wake_up_process(mq->thread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -152,36 +157,40 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
|
|||
GFP_KERNEL);
|
||||
if (!mq->sg) {
|
||||
ret = -ENOMEM;
|
||||
goto cleanup;
|
||||
goto cleanup_queue;
|
||||
}
|
||||
|
||||
init_completion(&mq->thread_complete);
|
||||
init_waitqueue_head(&mq->thread_wq);
|
||||
init_MUTEX(&mq->thread_sem);
|
||||
|
||||
ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL);
|
||||
if (ret >= 0) {
|
||||
wait_for_completion(&mq->thread_complete);
|
||||
init_completion(&mq->thread_complete);
|
||||
ret = 0;
|
||||
goto out;
|
||||
mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");
|
||||
if (IS_ERR(mq->thread)) {
|
||||
ret = PTR_ERR(mq->thread);
|
||||
goto free_sg;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return 0;
|
||||
|
||||
free_sg:
|
||||
kfree(mq->sg);
|
||||
mq->sg = NULL;
|
||||
|
||||
cleanup_queue:
|
||||
blk_cleanup_queue(mq->queue);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_init_queue);
|
||||
|
||||
void mmc_cleanup_queue(struct mmc_queue *mq)
|
||||
{
|
||||
mq->flags |= MMC_QUEUE_EXIT;
|
||||
wake_up(&mq->thread_wq);
|
||||
wait_for_completion(&mq->thread_complete);
|
||||
request_queue_t *q = mq->queue;
|
||||
unsigned long flags;
|
||||
|
||||
/* Mark that we should start throwing out stragglers */
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
q->queuedata = NULL;
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
|
||||
/* Then terminate our worker thread */
|
||||
kthread_stop(mq->thread);
|
||||
|
||||
kfree(mq->sg);
|
||||
mq->sg = NULL;
|
||||
|
|
|
@ -6,8 +6,7 @@ struct task_struct;
|
|||
|
||||
struct mmc_queue {
|
||||
struct mmc_card *card;
|
||||
struct completion thread_complete;
|
||||
wait_queue_head_t thread_wq;
|
||||
struct task_struct *thread;
|
||||
struct semaphore thread_sem;
|
||||
unsigned int flags;
|
||||
struct request *req;
|
||||
|
|
|
@ -443,7 +443,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
}
|
||||
}
|
||||
|
||||
static struct mmc_host_ops mmci_ops = {
|
||||
static const struct mmc_host_ops mmci_ops = {
|
||||
.request = mmci_request,
|
||||
.set_ios = mmci_set_ios,
|
||||
};
|
||||
|
|
|
@ -38,7 +38,57 @@
|
|||
#include <asm/arch/fpga.h>
|
||||
#include <asm/arch/tps65010.h>
|
||||
|
||||
#include "omap.h"
|
||||
#define OMAP_MMC_REG_CMD 0x00
|
||||
#define OMAP_MMC_REG_ARGL 0x04
|
||||
#define OMAP_MMC_REG_ARGH 0x08
|
||||
#define OMAP_MMC_REG_CON 0x0c
|
||||
#define OMAP_MMC_REG_STAT 0x10
|
||||
#define OMAP_MMC_REG_IE 0x14
|
||||
#define OMAP_MMC_REG_CTO 0x18
|
||||
#define OMAP_MMC_REG_DTO 0x1c
|
||||
#define OMAP_MMC_REG_DATA 0x20
|
||||
#define OMAP_MMC_REG_BLEN 0x24
|
||||
#define OMAP_MMC_REG_NBLK 0x28
|
||||
#define OMAP_MMC_REG_BUF 0x2c
|
||||
#define OMAP_MMC_REG_SDIO 0x34
|
||||
#define OMAP_MMC_REG_REV 0x3c
|
||||
#define OMAP_MMC_REG_RSP0 0x40
|
||||
#define OMAP_MMC_REG_RSP1 0x44
|
||||
#define OMAP_MMC_REG_RSP2 0x48
|
||||
#define OMAP_MMC_REG_RSP3 0x4c
|
||||
#define OMAP_MMC_REG_RSP4 0x50
|
||||
#define OMAP_MMC_REG_RSP5 0x54
|
||||
#define OMAP_MMC_REG_RSP6 0x58
|
||||
#define OMAP_MMC_REG_RSP7 0x5c
|
||||
#define OMAP_MMC_REG_IOSR 0x60
|
||||
#define OMAP_MMC_REG_SYSC 0x64
|
||||
#define OMAP_MMC_REG_SYSS 0x68
|
||||
|
||||
#define OMAP_MMC_STAT_CARD_ERR (1 << 14)
|
||||
#define OMAP_MMC_STAT_CARD_IRQ (1 << 13)
|
||||
#define OMAP_MMC_STAT_OCR_BUSY (1 << 12)
|
||||
#define OMAP_MMC_STAT_A_EMPTY (1 << 11)
|
||||
#define OMAP_MMC_STAT_A_FULL (1 << 10)
|
||||
#define OMAP_MMC_STAT_CMD_CRC (1 << 8)
|
||||
#define OMAP_MMC_STAT_CMD_TOUT (1 << 7)
|
||||
#define OMAP_MMC_STAT_DATA_CRC (1 << 6)
|
||||
#define OMAP_MMC_STAT_DATA_TOUT (1 << 5)
|
||||
#define OMAP_MMC_STAT_END_BUSY (1 << 4)
|
||||
#define OMAP_MMC_STAT_END_OF_DATA (1 << 3)
|
||||
#define OMAP_MMC_STAT_CARD_BUSY (1 << 2)
|
||||
#define OMAP_MMC_STAT_END_OF_CMD (1 << 0)
|
||||
|
||||
#define OMAP_MMC_READ(host, reg) __raw_readw((host)->virt_base + OMAP_MMC_REG_##reg)
|
||||
#define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG_##reg)
|
||||
|
||||
/*
|
||||
* Command types
|
||||
*/
|
||||
#define OMAP_MMC_CMDTYPE_BC 0
|
||||
#define OMAP_MMC_CMDTYPE_BCR 1
|
||||
#define OMAP_MMC_CMDTYPE_AC 2
|
||||
#define OMAP_MMC_CMDTYPE_ADTC 3
|
||||
|
||||
|
||||
#define DRIVER_NAME "mmci-omap"
|
||||
#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
|
||||
|
@ -60,8 +110,9 @@ struct mmc_omap_host {
|
|||
unsigned char id; /* 16xx chips have 2 MMC blocks */
|
||||
struct clk * iclk;
|
||||
struct clk * fclk;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
struct resource *mem_res;
|
||||
void __iomem *virt_base;
|
||||
unsigned int phys_base;
|
||||
int irq;
|
||||
unsigned char bus_mode;
|
||||
unsigned char hw_bus_mode;
|
||||
|
@ -191,16 +242,16 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
|
|||
|
||||
clk_enable(host->fclk);
|
||||
|
||||
OMAP_MMC_WRITE(host->base, CTO, 200);
|
||||
OMAP_MMC_WRITE(host->base, ARGL, cmd->arg & 0xffff);
|
||||
OMAP_MMC_WRITE(host->base, ARGH, cmd->arg >> 16);
|
||||
OMAP_MMC_WRITE(host->base, IE,
|
||||
OMAP_MMC_WRITE(host, CTO, 200);
|
||||
OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
|
||||
OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16);
|
||||
OMAP_MMC_WRITE(host, IE,
|
||||
OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL |
|
||||
OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT |
|
||||
OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_TOUT |
|
||||
OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR |
|
||||
OMAP_MMC_STAT_END_OF_DATA);
|
||||
OMAP_MMC_WRITE(host->base, CMD, cmdreg);
|
||||
OMAP_MMC_WRITE(host, CMD, cmdreg);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -296,22 +347,22 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
|
|||
if (cmd->flags & MMC_RSP_136) {
|
||||
/* response type 2 */
|
||||
cmd->resp[3] =
|
||||
OMAP_MMC_READ(host->base, RSP0) |
|
||||
(OMAP_MMC_READ(host->base, RSP1) << 16);
|
||||
OMAP_MMC_READ(host, RSP0) |
|
||||
(OMAP_MMC_READ(host, RSP1) << 16);
|
||||
cmd->resp[2] =
|
||||
OMAP_MMC_READ(host->base, RSP2) |
|
||||
(OMAP_MMC_READ(host->base, RSP3) << 16);
|
||||
OMAP_MMC_READ(host, RSP2) |
|
||||
(OMAP_MMC_READ(host, RSP3) << 16);
|
||||
cmd->resp[1] =
|
||||
OMAP_MMC_READ(host->base, RSP4) |
|
||||
(OMAP_MMC_READ(host->base, RSP5) << 16);
|
||||
OMAP_MMC_READ(host, RSP4) |
|
||||
(OMAP_MMC_READ(host, RSP5) << 16);
|
||||
cmd->resp[0] =
|
||||
OMAP_MMC_READ(host->base, RSP6) |
|
||||
(OMAP_MMC_READ(host->base, RSP7) << 16);
|
||||
OMAP_MMC_READ(host, RSP6) |
|
||||
(OMAP_MMC_READ(host, RSP7) << 16);
|
||||
} else {
|
||||
/* response types 1, 1b, 3, 4, 5, 6 */
|
||||
cmd->resp[0] =
|
||||
OMAP_MMC_READ(host->base, RSP6) |
|
||||
(OMAP_MMC_READ(host->base, RSP7) << 16);
|
||||
OMAP_MMC_READ(host, RSP6) |
|
||||
(OMAP_MMC_READ(host, RSP7) << 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -354,9 +405,9 @@ mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
|
|||
host->data->bytes_xfered += n;
|
||||
|
||||
if (write) {
|
||||
__raw_writesw(host->base + OMAP_MMC_REG_DATA, host->buffer, n);
|
||||
__raw_writesw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
|
||||
} else {
|
||||
__raw_readsw(host->base + OMAP_MMC_REG_DATA, host->buffer, n);
|
||||
__raw_readsw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,11 +437,11 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
|
|||
int transfer_error;
|
||||
|
||||
if (host->cmd == NULL && host->data == NULL) {
|
||||
status = OMAP_MMC_READ(host->base, STAT);
|
||||
status = OMAP_MMC_READ(host, STAT);
|
||||
dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status);
|
||||
if (status != 0) {
|
||||
OMAP_MMC_WRITE(host->base, STAT, status);
|
||||
OMAP_MMC_WRITE(host->base, IE, 0);
|
||||
OMAP_MMC_WRITE(host, STAT, status);
|
||||
OMAP_MMC_WRITE(host, IE, 0);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -399,8 +450,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
|
|||
end_transfer = 0;
|
||||
transfer_error = 0;
|
||||
|
||||
while ((status = OMAP_MMC_READ(host->base, STAT)) != 0) {
|
||||
OMAP_MMC_WRITE(host->base, STAT, status);
|
||||
while ((status = OMAP_MMC_READ(host, STAT)) != 0) {
|
||||
OMAP_MMC_WRITE(host, STAT, status);
|
||||
#ifdef CONFIG_MMC_DEBUG
|
||||
dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ",
|
||||
status, host->cmd != NULL ? host->cmd->opcode : -1);
|
||||
|
@ -470,8 +521,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
|
|||
|
||||
if (status & OMAP_MMC_STAT_CARD_ERR) {
|
||||
if (host->cmd && host->cmd->opcode == MMC_STOP_TRANSMISSION) {
|
||||
u32 response = OMAP_MMC_READ(host->base, RSP6)
|
||||
| (OMAP_MMC_READ(host->base, RSP7) << 16);
|
||||
u32 response = OMAP_MMC_READ(host, RSP6)
|
||||
| (OMAP_MMC_READ(host, RSP7) << 16);
|
||||
/* STOP sometimes sets must-ignore bits */
|
||||
if (!(response & (R1_CC_ERROR
|
||||
| R1_ILLEGAL_COMMAND
|
||||
|
@ -530,12 +581,6 @@ static void mmc_omap_switch_timer(unsigned long arg)
|
|||
schedule_work(&host->switch_work);
|
||||
}
|
||||
|
||||
/* FIXME: Handle card insertion and removal properly. Maybe use a mask
|
||||
* for MMC state? */
|
||||
static void mmc_omap_switch_callback(unsigned long data, u8 mmc_mask)
|
||||
{
|
||||
}
|
||||
|
||||
static void mmc_omap_switch_handler(void *data)
|
||||
{
|
||||
struct mmc_omap_host *host = (struct mmc_omap_host *) data;
|
||||
|
@ -581,7 +626,7 @@ mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
|
|||
int dst_port = 0;
|
||||
int sync_dev = 0;
|
||||
|
||||
data_addr = io_v2p((u32) host->base) + OMAP_MMC_REG_DATA;
|
||||
data_addr = host->phys_base + OMAP_MMC_REG_DATA;
|
||||
frame = data->blksz;
|
||||
count = sg_dma_len(sg);
|
||||
|
||||
|
@ -642,7 +687,7 @@ mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
|
|||
/* Max limit for DMA frame count is 0xffff */
|
||||
BUG_ON(count > 0xffff);
|
||||
|
||||
OMAP_MMC_WRITE(host->base, BUF, buf);
|
||||
OMAP_MMC_WRITE(host, BUF, buf);
|
||||
omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16,
|
||||
frame, count, OMAP_DMA_SYNC_FRAME,
|
||||
sync_dev, 0);
|
||||
|
@ -727,11 +772,11 @@ static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_reques
|
|||
{
|
||||
u16 reg;
|
||||
|
||||
reg = OMAP_MMC_READ(host->base, SDIO);
|
||||
reg = OMAP_MMC_READ(host, SDIO);
|
||||
reg &= ~(1 << 5);
|
||||
OMAP_MMC_WRITE(host->base, SDIO, reg);
|
||||
OMAP_MMC_WRITE(host, SDIO, reg);
|
||||
/* Set maximum timeout */
|
||||
OMAP_MMC_WRITE(host->base, CTO, 0xff);
|
||||
OMAP_MMC_WRITE(host, CTO, 0xff);
|
||||
}
|
||||
|
||||
static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req)
|
||||
|
@ -745,14 +790,14 @@ static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_reque
|
|||
timeout = req->data->timeout_clks + req->data->timeout_ns / 500;
|
||||
|
||||
/* Check if we need to use timeout multiplier register */
|
||||
reg = OMAP_MMC_READ(host->base, SDIO);
|
||||
reg = OMAP_MMC_READ(host, SDIO);
|
||||
if (timeout > 0xffff) {
|
||||
reg |= (1 << 5);
|
||||
timeout /= 1024;
|
||||
} else
|
||||
reg &= ~(1 << 5);
|
||||
OMAP_MMC_WRITE(host->base, SDIO, reg);
|
||||
OMAP_MMC_WRITE(host->base, DTO, timeout);
|
||||
OMAP_MMC_WRITE(host, SDIO, reg);
|
||||
OMAP_MMC_WRITE(host, DTO, timeout);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -764,19 +809,18 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
|
|||
|
||||
host->data = data;
|
||||
if (data == NULL) {
|
||||
OMAP_MMC_WRITE(host->base, BLEN, 0);
|
||||
OMAP_MMC_WRITE(host->base, NBLK, 0);
|
||||
OMAP_MMC_WRITE(host->base, BUF, 0);
|
||||
OMAP_MMC_WRITE(host, BLEN, 0);
|
||||
OMAP_MMC_WRITE(host, NBLK, 0);
|
||||
OMAP_MMC_WRITE(host, BUF, 0);
|
||||
host->dma_in_use = 0;
|
||||
set_cmd_timeout(host, req);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
block_size = data->blksz;
|
||||
|
||||
OMAP_MMC_WRITE(host->base, NBLK, data->blocks - 1);
|
||||
OMAP_MMC_WRITE(host->base, BLEN, block_size - 1);
|
||||
OMAP_MMC_WRITE(host, NBLK, data->blocks - 1);
|
||||
OMAP_MMC_WRITE(host, BLEN, block_size - 1);
|
||||
set_data_timeout(host, req);
|
||||
|
||||
/* cope with calling layer confusion; it issues "single
|
||||
|
@ -818,7 +862,7 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
|
|||
|
||||
/* Revert to PIO? */
|
||||
if (!use_dma) {
|
||||
OMAP_MMC_WRITE(host->base, BUF, 0x1f1f);
|
||||
OMAP_MMC_WRITE(host, BUF, 0x1f1f);
|
||||
host->total_bytes_left = data->blocks * block_size;
|
||||
host->sg_len = sg_len;
|
||||
mmc_omap_sg_to_buf(host);
|
||||
|
@ -844,7 +888,6 @@ static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req)
|
|||
static void innovator_fpga_socket_power(int on)
|
||||
{
|
||||
#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX)
|
||||
|
||||
if (on) {
|
||||
fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3),
|
||||
OMAP1510_FPGA_POWER);
|
||||
|
@ -870,8 +913,8 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on)
|
|||
/* GPIO 4 of TPS65010 sends SD_EN signal */
|
||||
tps65010_set_gpio_out_value(GPIO4, HIGH);
|
||||
else if (cpu_is_omap24xx()) {
|
||||
u16 reg = OMAP_MMC_READ(host->base, CON);
|
||||
OMAP_MMC_WRITE(host->base, CON, reg | (1 << 11));
|
||||
u16 reg = OMAP_MMC_READ(host, CON);
|
||||
OMAP_MMC_WRITE(host, CON, reg | (1 << 11));
|
||||
} else
|
||||
if (host->power_pin >= 0)
|
||||
omap_set_gpio_dataout(host->power_pin, 1);
|
||||
|
@ -883,8 +926,8 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on)
|
|||
else if (machine_is_omap_h3())
|
||||
tps65010_set_gpio_out_value(GPIO4, LOW);
|
||||
else if (cpu_is_omap24xx()) {
|
||||
u16 reg = OMAP_MMC_READ(host->base, CON);
|
||||
OMAP_MMC_WRITE(host->base, CON, reg & ~(1 << 11));
|
||||
u16 reg = OMAP_MMC_READ(host, CON);
|
||||
OMAP_MMC_WRITE(host, CON, reg & ~(1 << 11));
|
||||
} else
|
||||
if (host->power_pin >= 0)
|
||||
omap_set_gpio_dataout(host->power_pin, 0);
|
||||
|
@ -926,7 +969,7 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
case MMC_POWER_UP:
|
||||
case MMC_POWER_ON:
|
||||
mmc_omap_power(host, 1);
|
||||
dsor |= 1<<11;
|
||||
dsor |= 1 << 11;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -940,14 +983,14 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
* which results in the while loop below getting stuck.
|
||||
* Writing to the CON register twice seems to do the trick. */
|
||||
for (i = 0; i < 2; i++)
|
||||
OMAP_MMC_WRITE(host->base, CON, dsor);
|
||||
OMAP_MMC_WRITE(host, CON, dsor);
|
||||
if (ios->power_mode == MMC_POWER_UP) {
|
||||
/* Send clock cycles, poll completion */
|
||||
OMAP_MMC_WRITE(host->base, IE, 0);
|
||||
OMAP_MMC_WRITE(host->base, STAT, 0xffff);
|
||||
OMAP_MMC_WRITE(host->base, CMD, 1<<7);
|
||||
while (0 == (OMAP_MMC_READ(host->base, STAT) & 1));
|
||||
OMAP_MMC_WRITE(host->base, STAT, 1);
|
||||
OMAP_MMC_WRITE(host, IE, 0);
|
||||
OMAP_MMC_WRITE(host, STAT, 0xffff);
|
||||
OMAP_MMC_WRITE(host, CMD, 1 << 7);
|
||||
while ((OMAP_MMC_READ(host, STAT) & 1) == 0);
|
||||
OMAP_MMC_WRITE(host, STAT, 1);
|
||||
}
|
||||
clk_disable(host->fclk);
|
||||
}
|
||||
|
@ -959,7 +1002,7 @@ static int mmc_omap_get_ro(struct mmc_host *mmc)
|
|||
return host->wp_pin && omap_get_gpio_datain(host->wp_pin);
|
||||
}
|
||||
|
||||
static struct mmc_host_ops mmc_omap_ops = {
|
||||
static const struct mmc_host_ops mmc_omap_ops = {
|
||||
.request = mmc_omap_request,
|
||||
.set_ios = mmc_omap_set_ios,
|
||||
.get_ro = mmc_omap_get_ro,
|
||||
|
@ -970,25 +1013,29 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
|
|||
struct omap_mmc_conf *minfo = pdev->dev.platform_data;
|
||||
struct mmc_host *mmc;
|
||||
struct mmc_omap_host *host = NULL;
|
||||
struct resource *r;
|
||||
struct resource *res;
|
||||
int ret = 0;
|
||||
int irq;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
if (minfo == NULL) {
|
||||
dev_err(&pdev->dev, "platform data missing\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (!r || irq < 0)
|
||||
if (res == NULL || irq < 0)
|
||||
return -ENXIO;
|
||||
|
||||
r = request_mem_region(pdev->resource[0].start,
|
||||
pdev->resource[0].end - pdev->resource[0].start + 1,
|
||||
pdev->name);
|
||||
if (!r)
|
||||
res = request_mem_region(res->start, res->end - res->start + 1,
|
||||
pdev->name);
|
||||
if (res == NULL)
|
||||
return -EBUSY;
|
||||
|
||||
mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev);
|
||||
if (!mmc) {
|
||||
if (mmc == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
goto err_free_mem_region;
|
||||
}
|
||||
|
||||
host = mmc_priv(mmc);
|
||||
|
@ -1000,13 +1047,13 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
|
|||
host->dma_timer.data = (unsigned long) host;
|
||||
|
||||
host->id = pdev->id;
|
||||
host->res = r;
|
||||
host->mem_res = res;
|
||||
host->irq = irq;
|
||||
|
||||
if (cpu_is_omap24xx()) {
|
||||
host->iclk = clk_get(&pdev->dev, "mmc_ick");
|
||||
if (IS_ERR(host->iclk))
|
||||
goto out;
|
||||
goto err_free_mmc_host;
|
||||
clk_enable(host->iclk);
|
||||
}
|
||||
|
||||
|
@ -1017,7 +1064,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
|
|||
|
||||
if (IS_ERR(host->fclk)) {
|
||||
ret = PTR_ERR(host->fclk);
|
||||
goto out;
|
||||
goto err_free_iclk;
|
||||
}
|
||||
|
||||
/* REVISIT:
|
||||
|
@ -1030,14 +1077,15 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
|
|||
host->use_dma = 1;
|
||||
host->dma_ch = -1;
|
||||
|
||||
host->irq = pdev->resource[1].start;
|
||||
host->base = (void __iomem*)IO_ADDRESS(r->start);
|
||||
host->irq = irq;
|
||||
host->phys_base = host->mem_res->start;
|
||||
host->virt_base = (void __iomem *) IO_ADDRESS(host->phys_base);
|
||||
|
||||
mmc->ops = &mmc_omap_ops;
|
||||
mmc->f_min = 400000;
|
||||
mmc->f_max = 24000000;
|
||||
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
|
||||
mmc->caps = MMC_CAP_BYTEBLOCK;
|
||||
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
|
||||
mmc->caps = MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
|
||||
|
||||
if (minfo->wire4)
|
||||
mmc->caps |= MMC_CAP_4_BIT_DATA;
|
||||
|
@ -1055,20 +1103,18 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
|
|||
if ((ret = omap_request_gpio(host->power_pin)) != 0) {
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"Unable to get GPIO pin for MMC power\n");
|
||||
goto out;
|
||||
goto err_free_fclk;
|
||||
}
|
||||
omap_set_gpio_direction(host->power_pin, 0);
|
||||
}
|
||||
|
||||
ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
|
||||
if (ret)
|
||||
goto out;
|
||||
goto err_free_power_gpio;
|
||||
|
||||
host->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, host);
|
||||
|
||||
mmc_add_host(mmc);
|
||||
|
||||
if (host->switch_pin >= 0) {
|
||||
INIT_WORK(&host->switch_work, mmc_omap_switch_handler, host);
|
||||
init_timer(&host->switch_timer);
|
||||
|
@ -1106,10 +1152,11 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
|
|||
schedule_work(&host->switch_work);
|
||||
}
|
||||
|
||||
no_switch:
|
||||
mmc_add_host(mmc);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
no_switch:
|
||||
/* FIXME: Free other resources too. */
|
||||
if (host) {
|
||||
if (host->iclk && !IS_ERR(host->iclk))
|
||||
|
@ -1118,6 +1165,20 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
|
|||
clk_put(host->fclk);
|
||||
mmc_free_host(host->mmc);
|
||||
}
|
||||
err_free_power_gpio:
|
||||
if (host->power_pin >= 0)
|
||||
omap_free_gpio(host->power_pin);
|
||||
err_free_fclk:
|
||||
clk_put(host->fclk);
|
||||
err_free_iclk:
|
||||
if (host->iclk != NULL) {
|
||||
clk_disable(host->iclk);
|
||||
clk_put(host->iclk);
|
||||
}
|
||||
err_free_mmc_host:
|
||||
mmc_free_host(host->mmc);
|
||||
err_free_mem_region:
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1127,30 +1188,31 @@ static int mmc_omap_remove(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
if (host) {
|
||||
mmc_remove_host(host->mmc);
|
||||
free_irq(host->irq, host);
|
||||
BUG_ON(host == NULL);
|
||||
|
||||
if (host->power_pin >= 0)
|
||||
omap_free_gpio(host->power_pin);
|
||||
if (host->switch_pin >= 0) {
|
||||
device_remove_file(&pdev->dev, &dev_attr_enable_poll);
|
||||
device_remove_file(&pdev->dev, &dev_attr_cover_switch);
|
||||
free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
|
||||
omap_free_gpio(host->switch_pin);
|
||||
host->switch_pin = -1;
|
||||
del_timer_sync(&host->switch_timer);
|
||||
flush_scheduled_work();
|
||||
}
|
||||
if (host->iclk && !IS_ERR(host->iclk))
|
||||
clk_put(host->iclk);
|
||||
if (host->fclk && !IS_ERR(host->fclk))
|
||||
clk_put(host->fclk);
|
||||
mmc_free_host(host->mmc);
|
||||
mmc_remove_host(host->mmc);
|
||||
free_irq(host->irq, host);
|
||||
|
||||
if (host->power_pin >= 0)
|
||||
omap_free_gpio(host->power_pin);
|
||||
if (host->switch_pin >= 0) {
|
||||
device_remove_file(&pdev->dev, &dev_attr_enable_poll);
|
||||
device_remove_file(&pdev->dev, &dev_attr_cover_switch);
|
||||
free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
|
||||
omap_free_gpio(host->switch_pin);
|
||||
host->switch_pin = -1;
|
||||
del_timer_sync(&host->switch_timer);
|
||||
flush_scheduled_work();
|
||||
}
|
||||
if (host->iclk && !IS_ERR(host->iclk))
|
||||
clk_put(host->iclk);
|
||||
if (host->fclk && !IS_ERR(host->fclk))
|
||||
clk_put(host->fclk);
|
||||
|
||||
release_mem_region(pdev->resource[0].start,
|
||||
pdev->resource[0].end - pdev->resource[0].start + 1);
|
||||
pdev->resource[0].end - pdev->resource[0].start + 1);
|
||||
|
||||
mmc_free_host(host->mmc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
#ifndef DRIVERS_MEDIA_MMC_OMAP_H
|
||||
#define DRIVERS_MEDIA_MMC_OMAP_H
|
||||
|
||||
#define OMAP_MMC_REG_CMD 0x00
|
||||
#define OMAP_MMC_REG_ARGL 0x04
|
||||
#define OMAP_MMC_REG_ARGH 0x08
|
||||
#define OMAP_MMC_REG_CON 0x0c
|
||||
#define OMAP_MMC_REG_STAT 0x10
|
||||
#define OMAP_MMC_REG_IE 0x14
|
||||
#define OMAP_MMC_REG_CTO 0x18
|
||||
#define OMAP_MMC_REG_DTO 0x1c
|
||||
#define OMAP_MMC_REG_DATA 0x20
|
||||
#define OMAP_MMC_REG_BLEN 0x24
|
||||
#define OMAP_MMC_REG_NBLK 0x28
|
||||
#define OMAP_MMC_REG_BUF 0x2c
|
||||
#define OMAP_MMC_REG_SDIO 0x34
|
||||
#define OMAP_MMC_REG_REV 0x3c
|
||||
#define OMAP_MMC_REG_RSP0 0x40
|
||||
#define OMAP_MMC_REG_RSP1 0x44
|
||||
#define OMAP_MMC_REG_RSP2 0x48
|
||||
#define OMAP_MMC_REG_RSP3 0x4c
|
||||
#define OMAP_MMC_REG_RSP4 0x50
|
||||
#define OMAP_MMC_REG_RSP5 0x54
|
||||
#define OMAP_MMC_REG_RSP6 0x58
|
||||
#define OMAP_MMC_REG_RSP7 0x5c
|
||||
#define OMAP_MMC_REG_IOSR 0x60
|
||||
#define OMAP_MMC_REG_SYSC 0x64
|
||||
#define OMAP_MMC_REG_SYSS 0x68
|
||||
|
||||
#define OMAP_MMC_STAT_CARD_ERR (1 << 14)
|
||||
#define OMAP_MMC_STAT_CARD_IRQ (1 << 13)
|
||||
#define OMAP_MMC_STAT_OCR_BUSY (1 << 12)
|
||||
#define OMAP_MMC_STAT_A_EMPTY (1 << 11)
|
||||
#define OMAP_MMC_STAT_A_FULL (1 << 10)
|
||||
#define OMAP_MMC_STAT_CMD_CRC (1 << 8)
|
||||
#define OMAP_MMC_STAT_CMD_TOUT (1 << 7)
|
||||
#define OMAP_MMC_STAT_DATA_CRC (1 << 6)
|
||||
#define OMAP_MMC_STAT_DATA_TOUT (1 << 5)
|
||||
#define OMAP_MMC_STAT_END_BUSY (1 << 4)
|
||||
#define OMAP_MMC_STAT_END_OF_DATA (1 << 3)
|
||||
#define OMAP_MMC_STAT_CARD_BUSY (1 << 2)
|
||||
#define OMAP_MMC_STAT_END_OF_CMD (1 << 0)
|
||||
|
||||
#define OMAP_MMC_READ(base, reg) __raw_readw((base) + OMAP_MMC_REG_##reg)
|
||||
#define OMAP_MMC_WRITE(base, reg, val) __raw_writew((val), (base) + OMAP_MMC_REG_##reg)
|
||||
|
||||
/*
|
||||
* Command types
|
||||
*/
|
||||
#define OMAP_MMC_CMDTYPE_BC 0
|
||||
#define OMAP_MMC_CMDTYPE_BCR 1
|
||||
#define OMAP_MMC_CMDTYPE_AC 2
|
||||
#define OMAP_MMC_CMDTYPE_ADTC 3
|
||||
|
||||
#endif
|
|
@ -393,7 +393,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
host->clkrt, host->cmdat);
|
||||
}
|
||||
|
||||
static struct mmc_host_ops pxamci_ops = {
|
||||
static const struct mmc_host_ops pxamci_ops = {
|
||||
.request = pxamci_request,
|
||||
.get_ro = pxamci_get_ro,
|
||||
.set_ios = pxamci_set_ios,
|
||||
|
|
|
@ -616,6 +616,7 @@ static void sdhci_finish_command(struct sdhci_host *host)
|
|||
static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
{
|
||||
int div;
|
||||
u8 ctrl;
|
||||
u16 clk;
|
||||
unsigned long timeout;
|
||||
|
||||
|
@ -624,6 +625,13 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
|
|||
|
||||
writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
|
||||
|
||||
ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
|
||||
if (clock > 25000000)
|
||||
ctrl |= SDHCI_CTRL_HISPD;
|
||||
else
|
||||
ctrl &= ~SDHCI_CTRL_HISPD;
|
||||
writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
|
||||
|
||||
if (clock == 0)
|
||||
goto out;
|
||||
|
||||
|
@ -784,7 +792,7 @@ static int sdhci_get_ro(struct mmc_host *mmc)
|
|||
return !(present & SDHCI_WRITE_PROTECT);
|
||||
}
|
||||
|
||||
static struct mmc_host_ops sdhci_ops = {
|
||||
static const struct mmc_host_ops sdhci_ops = {
|
||||
.request = sdhci_request,
|
||||
.set_ios = sdhci_set_ios,
|
||||
.get_ro = sdhci_get_ro,
|
||||
|
@ -1291,6 +1299,13 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
|
|||
else if (caps & SDHCI_CAN_VDD_180)
|
||||
mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
|
||||
|
||||
if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) {
|
||||
printk(KERN_ERR "%s: Controller reports > 25 MHz base clock,"
|
||||
" but no high speed support.\n",
|
||||
host->slot_descr);
|
||||
mmc->f_max = 25000000;
|
||||
}
|
||||
|
||||
if (mmc->ocr_avail == 0) {
|
||||
printk(KERN_ERR "%s: Hardware doesn't report any "
|
||||
"support voltages.\n", host->slot_descr);
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
#define SDHCI_HOST_CONTROL 0x28
|
||||
#define SDHCI_CTRL_LED 0x01
|
||||
#define SDHCI_CTRL_4BITBUS 0x02
|
||||
#define SDHCI_CTRL_HISPD 0x04
|
||||
|
||||
#define SDHCI_POWER_CONTROL 0x29
|
||||
#define SDHCI_POWER_ON 0x01
|
||||
|
@ -138,6 +139,7 @@
|
|||
#define SDHCI_CLOCK_BASE_SHIFT 8
|
||||
#define SDHCI_MAX_BLOCK_MASK 0x00030000
|
||||
#define SDHCI_MAX_BLOCK_SHIFT 16
|
||||
#define SDHCI_CAN_DO_HISPD 0x00200000
|
||||
#define SDHCI_CAN_DO_DMA 0x00400000
|
||||
#define SDHCI_CAN_VDD_330 0x01000000
|
||||
#define SDHCI_CAN_VDD_300 0x02000000
|
||||
|
|
|
@ -1021,7 +1021,7 @@ static int wbsd_get_ro(struct mmc_host *mmc)
|
|||
return csr & WBSD_WRPT;
|
||||
}
|
||||
|
||||
static struct mmc_host_ops wbsd_ops = {
|
||||
static const struct mmc_host_ops wbsd_ops = {
|
||||
.request = wbsd_request,
|
||||
.set_ios = wbsd_set_ios,
|
||||
.get_ro = wbsd_get_ro,
|
||||
|
|
|
@ -39,6 +39,10 @@ struct mmc_csd {
|
|||
write_misalign:1;
|
||||
};
|
||||
|
||||
struct mmc_ext_csd {
|
||||
unsigned int hs_max_dtr;
|
||||
};
|
||||
|
||||
struct sd_scr {
|
||||
unsigned char sda_vsn;
|
||||
unsigned char bus_widths;
|
||||
|
@ -46,6 +50,10 @@ struct sd_scr {
|
|||
#define SD_SCR_BUS_WIDTH_4 (1<<2)
|
||||
};
|
||||
|
||||
struct sd_switch_caps {
|
||||
unsigned int hs_max_dtr;
|
||||
};
|
||||
|
||||
struct mmc_host;
|
||||
|
||||
/*
|
||||
|
@ -62,12 +70,15 @@ struct mmc_card {
|
|||
#define MMC_STATE_BAD (1<<2) /* unrecognised device */
|
||||
#define MMC_STATE_SDCARD (1<<3) /* is an SD card */
|
||||
#define MMC_STATE_READONLY (1<<4) /* card is read-only */
|
||||
#define MMC_STATE_HIGHSPEED (1<<5) /* card is in high speed mode */
|
||||
u32 raw_cid[4]; /* raw card CID */
|
||||
u32 raw_csd[4]; /* raw card CSD */
|
||||
u32 raw_scr[2]; /* raw card SCR */
|
||||
struct mmc_cid cid; /* card identification */
|
||||
struct mmc_csd csd; /* card specific */
|
||||
struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */
|
||||
struct sd_scr scr; /* extra SD information */
|
||||
struct sd_switch_caps sw_caps; /* switch (CMD6) caps */
|
||||
};
|
||||
|
||||
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
|
||||
|
@ -75,12 +86,14 @@ struct mmc_card {
|
|||
#define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD)
|
||||
#define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD)
|
||||
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
|
||||
#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED)
|
||||
|
||||
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
|
||||
#define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD)
|
||||
#define mmc_card_set_bad(c) ((c)->state |= MMC_STATE_BAD)
|
||||
#define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD)
|
||||
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
|
||||
#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
|
||||
|
||||
#define mmc_card_name(c) ((c)->cid.prod_name)
|
||||
#define mmc_card_id(c) ((c)->dev.bus_id)
|
||||
|
|
|
@ -25,14 +25,16 @@
|
|||
#ifndef MMC_MMC_PROTOCOL_H
|
||||
#define MMC_MMC_PROTOCOL_H
|
||||
|
||||
/* Standard MMC commands (3.1) type argument response */
|
||||
/* Standard MMC commands (4.1) type argument response */
|
||||
/* class 1 */
|
||||
#define MMC_GO_IDLE_STATE 0 /* bc */
|
||||
#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
|
||||
#define MMC_ALL_SEND_CID 2 /* bcr R2 */
|
||||
#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
|
||||
#define MMC_SET_DSR 4 /* bc [31:16] RCA */
|
||||
#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
|
||||
#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
|
||||
#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
|
||||
#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */
|
||||
#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */
|
||||
#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
|
||||
|
@ -80,6 +82,7 @@
|
|||
/* class 8 */
|
||||
/* This is basically the same command as for MMC with some quirks. */
|
||||
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
|
||||
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
|
||||
|
||||
/* Application commands */
|
||||
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
|
||||
|
@ -87,6 +90,30 @@
|
|||
#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
|
||||
#define SD_APP_SEND_SCR 51 /* adtc R1 */
|
||||
|
||||
/*
|
||||
* MMC_SWITCH argument format:
|
||||
*
|
||||
* [31:26] Always 0
|
||||
* [25:24] Access Mode
|
||||
* [23:16] Location of target Byte in EXT_CSD
|
||||
* [15:08] Value Byte
|
||||
* [07:03] Always 0
|
||||
* [02:00] Command Set
|
||||
*/
|
||||
|
||||
/*
|
||||
* SD_SWITCH argument format:
|
||||
*
|
||||
* [31] Check (0) or switch (1)
|
||||
* [30:24] Reserved (0)
|
||||
* [23:20] Function group 6
|
||||
* [19:16] Function group 5
|
||||
* [15:12] Function group 4
|
||||
* [11:8] Function group 3
|
||||
* [7:4] Function group 2
|
||||
* [3:0] Function group 1
|
||||
*/
|
||||
|
||||
/*
|
||||
MMC status in R1
|
||||
Type
|
||||
|
@ -230,13 +257,54 @@ struct _mmc_csd {
|
|||
|
||||
#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
|
||||
#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
|
||||
#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */
|
||||
#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
|
||||
#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */
|
||||
|
||||
#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */
|
||||
#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */
|
||||
#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
|
||||
#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */
|
||||
#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */
|
||||
#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */
|
||||
|
||||
/*
|
||||
* EXT_CSD fields
|
||||
*/
|
||||
|
||||
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
|
||||
#define EXT_CSD_HS_TIMING 185 /* R/W */
|
||||
#define EXT_CSD_CARD_TYPE 196 /* RO */
|
||||
|
||||
/*
|
||||
* EXT_CSD field definitions
|
||||
*/
|
||||
|
||||
#define EXT_CSD_CMD_SET_NORMAL (1<<0)
|
||||
#define EXT_CSD_CMD_SET_SECURE (1<<1)
|
||||
#define EXT_CSD_CMD_SET_CPSECURE (1<<2)
|
||||
|
||||
#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */
|
||||
#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */
|
||||
|
||||
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
|
||||
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
|
||||
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
|
||||
|
||||
/*
|
||||
* MMC_SWITCH access modes
|
||||
*/
|
||||
|
||||
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
|
||||
#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */
|
||||
#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
|
||||
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
|
||||
|
||||
/*
|
||||
* SCR field definitions
|
||||
*/
|
||||
|
||||
#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
|
||||
#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
|
||||
#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */
|
||||
|
||||
/*
|
||||
* SD bus widths
|
||||
|
|
Loading…
Reference in a new issue