Commit d941cf5e authored by Linus Torvalds's avatar Linus Torvalds

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:
  drivers/mmc/core/: make 3 functions static
  mmc: add missing printk levels
  mmc: remove redundant debug information from sdhci and wbsd
  mmc: proper debugging output in core
  mmc: be more verbose about card insertions/removal
  mmc: Don't hold lock when releasing an added card
  mmc: add a might_sleep() to mmc_claim_host()
  mmc: update kerneldoc
  mmc: update header file paths
  sdhci: add support to ENE-CB714
  mmc: check error bits before command completion
parents 9f5577d8 39361851
/* /*
* linux/drivers/mmc/queue.c * linux/drivers/mmc/card/queue.c
* *
* Copyright (C) 2003 Russell King, All Rights Reserved. * Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2006-2007 Pierre Ossman * Copyright 2006-2007 Pierre Ossman
......
...@@ -209,10 +209,30 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host) ...@@ -209,10 +209,30 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host)
int mmc_add_card(struct mmc_card *card) int mmc_add_card(struct mmc_card *card)
{ {
int ret; int ret;
const char *type;
snprintf(card->dev.bus_id, sizeof(card->dev.bus_id), snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
"%s:%04x", mmc_hostname(card->host), card->rca); "%s:%04x", mmc_hostname(card->host), card->rca);
switch (card->type) {
case MMC_TYPE_MMC:
type = "MMC";
break;
case MMC_TYPE_SD:
type = "SD";
if (mmc_card_blockaddr(card))
type = "SDHC";
break;
default:
type = "?";
break;
}
printk(KERN_INFO "%s: new %s%s card at address %04x\n",
mmc_hostname(card->host),
mmc_card_highspeed(card) ? "high speed " : "",
type, card->rca);
card->dev.uevent_suppress = 1; card->dev.uevent_suppress = 1;
ret = device_add(&card->dev); ret = device_add(&card->dev);
...@@ -243,6 +263,9 @@ int mmc_add_card(struct mmc_card *card) ...@@ -243,6 +263,9 @@ int mmc_add_card(struct mmc_card *card)
void mmc_remove_card(struct mmc_card *card) void mmc_remove_card(struct mmc_card *card)
{ {
if (mmc_card_present(card)) { if (mmc_card_present(card)) {
printk(KERN_INFO "%s: card %04x removed\n",
mmc_hostname(card->host), card->rca);
if (card->host->bus_ops->sysfs_remove) if (card->host->bus_ops->sysfs_remove)
card->host->bus_ops->sysfs_remove(card->host, card); card->host->bus_ops->sysfs_remove(card->host, card);
device_del(&card->dev); device_del(&card->dev);
......
...@@ -68,32 +68,41 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) ...@@ -68,32 +68,41 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
struct mmc_command *cmd = mrq->cmd; struct mmc_command *cmd = mrq->cmd;
int err = cmd->error; int err = cmd->error;
pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n",
mmc_hostname(host), cmd->opcode, err,
mrq->data ? mrq->data->error : 0,
mrq->stop ? mrq->stop->error : 0,
cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
if (err && cmd->retries) { if (err && cmd->retries) {
pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
mmc_hostname(host), cmd->opcode, err);
cmd->retries--; cmd->retries--;
cmd->error = 0; cmd->error = 0;
host->ops->request(host, mrq); host->ops->request(host, mrq);
} else if (mrq->done) { } else {
pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
mmc_hostname(host), cmd->opcode, err,
cmd->resp[0], cmd->resp[1],
cmd->resp[2], cmd->resp[3]);
if (mrq->data) {
pr_debug("%s: %d bytes transferred: %d\n",
mmc_hostname(host),
mrq->data->bytes_xfered, mrq->data->error);
}
if (mrq->stop) {
pr_debug("%s: (CMD%u): %d: %08x %08x %08x %08x\n",
mmc_hostname(host), mrq->stop->opcode,
mrq->stop->error,
mrq->stop->resp[0], mrq->stop->resp[1],
mrq->stop->resp[2], mrq->stop->resp[3]);
}
if (mrq->done)
mrq->done(mrq); mrq->done(mrq);
} }
} }
EXPORT_SYMBOL(mmc_request_done); EXPORT_SYMBOL(mmc_request_done);
/** static void
* mmc_start_request - start a command on a host
* @host: MMC host to start command on
* @mrq: MMC request to start
*
* Queue a command on the specified host. We expect the
* caller to be holding the host lock with interrupts disabled.
*/
void
mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{ {
#ifdef CONFIG_MMC_DEBUG #ifdef CONFIG_MMC_DEBUG
...@@ -104,6 +113,21 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) ...@@ -104,6 +113,21 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_hostname(host), mrq->cmd->opcode, mmc_hostname(host), mrq->cmd->opcode,
mrq->cmd->arg, mrq->cmd->flags); mrq->cmd->arg, mrq->cmd->flags);
if (mrq->data) {
pr_debug("%s: blksz %d blocks %d flags %08x "
"tsac %d ms nsac %d\n",
mmc_hostname(host), mrq->data->blksz,
mrq->data->blocks, mrq->data->flags,
mrq->data->timeout_ns / 10000000,
mrq->data->timeout_clks);
}
if (mrq->stop) {
pr_debug("%s: CMD%u arg %08x flags %08x\n",
mmc_hostname(host), mrq->stop->opcode,
mrq->stop->arg, mrq->stop->flags);
}
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
mrq->cmd->error = 0; mrq->cmd->error = 0;
...@@ -133,14 +157,21 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) ...@@ -133,14 +157,21 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
host->ops->request(host, mrq); host->ops->request(host, mrq);
} }
EXPORT_SYMBOL(mmc_start_request);
static void mmc_wait_done(struct mmc_request *mrq) static void mmc_wait_done(struct mmc_request *mrq)
{ {
complete(mrq->done_data); complete(mrq->done_data);
} }
int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) /**
* mmc_wait_for_req - start a request and wait for completion
* @host: MMC host to start command
* @mrq: MMC request to start
*
* Start a new MMC custom command request for a host, and wait
* for the command to complete. Does not attempt to parse the
* response.
*/
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{ {
DECLARE_COMPLETION_ONSTACK(complete); DECLARE_COMPLETION_ONSTACK(complete);
...@@ -150,8 +181,6 @@ int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) ...@@ -150,8 +181,6 @@ int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
mmc_start_request(host, mrq); mmc_start_request(host, mrq);
wait_for_completion(&complete); wait_for_completion(&complete);
return 0;
} }
EXPORT_SYMBOL(mmc_wait_for_req); EXPORT_SYMBOL(mmc_wait_for_req);
...@@ -192,6 +221,9 @@ EXPORT_SYMBOL(mmc_wait_for_cmd); ...@@ -192,6 +221,9 @@ EXPORT_SYMBOL(mmc_wait_for_cmd);
* @data: data phase for command * @data: data phase for command
* @card: the MMC card associated with the data transfer * @card: the MMC card associated with the data transfer
* @write: flag to differentiate reads from writes * @write: flag to differentiate reads from writes
*
* Computes the data timeout parameters according to the
* correct algorithm given the card type.
*/ */
void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
int write) int write)
...@@ -240,21 +272,18 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, ...@@ -240,21 +272,18 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
EXPORT_SYMBOL(mmc_set_data_timeout); EXPORT_SYMBOL(mmc_set_data_timeout);
/** /**
* __mmc_claim_host - exclusively claim a host * mmc_claim_host - exclusively claim a host
* @host: mmc host to claim * @host: mmc host to claim
* @card: mmc card to claim host for
*
* Claim a host for a set of operations. If a valid card
* is passed and this wasn't the last card selected, select
* the card before returning.
* *
* Note: you should use mmc_card_claim_host or mmc_claim_host. * Claim a host for a set of operations.
*/ */
void mmc_claim_host(struct mmc_host *host) void mmc_claim_host(struct mmc_host *host)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
unsigned long flags; unsigned long flags;
might_sleep();
add_wait_queue(&host->wq, &wait); add_wait_queue(&host->wq, &wait);
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
while (1) { while (1) {
...@@ -432,6 +461,45 @@ static void mmc_power_off(struct mmc_host *host) ...@@ -432,6 +461,45 @@ static void mmc_power_off(struct mmc_host *host)
mmc_set_ios(host); mmc_set_ios(host);
} }
/*
* Cleanup when the last reference to the bus operator is dropped.
*/
void __mmc_release_bus(struct mmc_host *host)
{
BUG_ON(!host);
BUG_ON(host->bus_refs);
BUG_ON(!host->bus_dead);
host->bus_ops = NULL;
}
/*
* Increase reference count of bus operator
*/
static inline void mmc_bus_get(struct mmc_host *host)
{
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
host->bus_refs++;
spin_unlock_irqrestore(&host->lock, flags);
}
/*
* Decrease reference count of bus operator and free it if
* it is the last reference.
*/
static inline void mmc_bus_put(struct mmc_host *host)
{
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
host->bus_refs--;
if ((host->bus_refs == 0) && host->bus_ops)
__mmc_release_bus(host);
spin_unlock_irqrestore(&host->lock, flags);
}
/* /*
* Assign a mmc bus handler to a host. Only one bus handler may control a * Assign a mmc bus handler to a host. Only one bus handler may control a
* host at any given time. * host at any given time.
...@@ -481,25 +549,15 @@ void mmc_detach_bus(struct mmc_host *host) ...@@ -481,25 +549,15 @@ void mmc_detach_bus(struct mmc_host *host)
mmc_bus_put(host); mmc_bus_put(host);
} }
/*
* Cleanup when the last reference to the bus operator is dropped.
*/
void __mmc_release_bus(struct mmc_host *host)
{
BUG_ON(!host);
BUG_ON(host->bus_refs);
BUG_ON(!host->bus_dead);
host->bus_ops = NULL;
}
/** /**
* mmc_detect_change - process change of state on a MMC socket * mmc_detect_change - process change of state on a MMC socket
* @host: host which changed state. * @host: host which changed state.
* @delay: optional delay to wait before detection (jiffies) * @delay: optional delay to wait before detection (jiffies)
* *
* All we know is that card(s) have been inserted or removed * MMC drivers should call this when they detect a card has been
* from the socket(s). We don't know which socket or cards. * inserted or removed. The MMC layer will confirm that any
* present card is still functional, and initialize any newly
* inserted.
*/ */
void mmc_detect_change(struct mmc_host *host, unsigned long delay) void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{ {
......
...@@ -27,28 +27,6 @@ struct mmc_bus_ops { ...@@ -27,28 +27,6 @@ struct mmc_bus_ops {
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
void mmc_detach_bus(struct mmc_host *host); void mmc_detach_bus(struct mmc_host *host);
void __mmc_release_bus(struct mmc_host *host);
static inline void mmc_bus_get(struct mmc_host *host)
{
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
host->bus_refs++;
spin_unlock_irqrestore(&host->lock, flags);
}
static inline void mmc_bus_put(struct mmc_host *host)
{
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
host->bus_refs--;
if ((host->bus_refs == 0) && host->bus_ops)
__mmc_release_bus(host);
spin_unlock_irqrestore(&host->lock, flags);
}
void mmc_set_chip_select(struct mmc_host *host, int mode); void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz); void mmc_set_clock(struct mmc_host *host, unsigned int hz);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode); void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
......
...@@ -93,6 +93,10 @@ EXPORT_SYMBOL(mmc_alloc_host); ...@@ -93,6 +93,10 @@ EXPORT_SYMBOL(mmc_alloc_host);
/** /**
* mmc_add_host - initialise host hardware * mmc_add_host - initialise host hardware
* @host: mmc host * @host: mmc host
*
* Register the host with the driver model. The host must be
* prepared to start servicing requests before this function
* completes.
*/ */
int mmc_add_host(struct mmc_host *host) int mmc_add_host(struct mmc_host *host)
{ {
...@@ -126,7 +130,8 @@ EXPORT_SYMBOL(mmc_add_host); ...@@ -126,7 +130,8 @@ EXPORT_SYMBOL(mmc_add_host);
* @host: mmc host * @host: mmc host
* *
* Unregister and remove all cards associated with this host, * Unregister and remove all cards associated with this host,
* and power down the MMC bus. * and power down the MMC bus. No new requests will be issued
* after this function has returned.
*/ */
void mmc_remove_host(struct mmc_host *host) void mmc_remove_host(struct mmc_host *host)
{ {
......
/* /*
* linux/drivers/mmc/mmc.c * linux/drivers/mmc/core/mmc.c
* *
* Copyright (C) 2003-2004 Russell King, All Rights Reserved. * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
...@@ -100,7 +100,7 @@ static int mmc_decode_cid(struct mmc_card *card) ...@@ -100,7 +100,7 @@ static int mmc_decode_cid(struct mmc_card *card)
break; break;
default: default:
printk("%s: card has unknown MMCA version %d\n", printk(KERN_ERR "%s: card has unknown MMCA version %d\n",
mmc_hostname(card->host), card->csd.mmca_vsn); mmc_hostname(card->host), card->csd.mmca_vsn);
return -EINVAL; return -EINVAL;
} }
...@@ -123,7 +123,7 @@ static int mmc_decode_csd(struct mmc_card *card) ...@@ -123,7 +123,7 @@ static int mmc_decode_csd(struct mmc_card *card)
*/ */
csd_struct = UNSTUFF_BITS(resp, 126, 2); csd_struct = UNSTUFF_BITS(resp, 126, 2);
if (csd_struct != 1 && csd_struct != 2) { if (csd_struct != 1 && csd_struct != 2) {
printk("%s: unrecognised CSD structure version %d\n", printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
mmc_hostname(card->host), csd_struct); mmc_hostname(card->host), csd_struct);
return -EINVAL; return -EINVAL;
} }
...@@ -499,14 +499,17 @@ static void mmc_resume(struct mmc_host *host) ...@@ -499,14 +499,17 @@ static void mmc_resume(struct mmc_host *host)
BUG_ON(!host->card); BUG_ON(!host->card);
mmc_claim_host(host); mmc_claim_host(host);
err = mmc_init_card(host, host->ocr, host->card); err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
if (err != MMC_ERR_NONE) { if (err != MMC_ERR_NONE) {
mmc_remove(host); mmc_remove(host);
mmc_claim_host(host);
mmc_detach_bus(host); mmc_detach_bus(host);
mmc_release_host(host);
} }
mmc_release_host(host);
} }
#else #else
...@@ -553,8 +556,10 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) ...@@ -553,8 +556,10 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
/* /*
* Can we support the voltage of the card? * Can we support the voltage of the card?
*/ */
if (!host->ocr) if (!host->ocr) {
err = -EINVAL;
goto err; goto err;
}
/* /*
* Detect and init the card. * Detect and init the card.
...@@ -567,18 +572,21 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) ...@@ -567,18 +572,21 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
err = mmc_add_card(host->card); err = mmc_add_card(host->card);
if (err) if (err)
goto reclaim_host; goto remove_card;
return 0; return 0;
reclaim_host: remove_card:
mmc_claim_host(host);
mmc_remove_card(host->card); mmc_remove_card(host->card);
host->card = NULL; host->card = NULL;
mmc_claim_host(host);
err: err:
mmc_detach_bus(host); mmc_detach_bus(host);
mmc_release_host(host); mmc_release_host(host);
printk(KERN_ERR "%s: error %d whilst initialising MMC card\n",
mmc_hostname(host), err);
return 0; return 0;
} }
/* /*
* linux/drivers/mmc/mmc_ops.h * linux/drivers/mmc/core/mmc_ops.h
* *
* Copyright 2006-2007 Pierre Ossman * Copyright 2006-2007 Pierre Ossman
* *
......
/* /*
* linux/drivers/mmc/mmc_ops.h * linux/drivers/mmc/core/mmc_ops.h
* *
* Copyright 2006-2007 Pierre Ossman * Copyright 2006-2007 Pierre Ossman
* *
......
/* /*
* linux/drivers/mmc/sd.c * linux/drivers/mmc/core/sd.c
* *
* Copyright (C) 2003-2004 Russell King, All Rights Reserved. * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
...@@ -149,7 +149,7 @@ static int mmc_decode_csd(struct mmc_card *card) ...@@ -149,7 +149,7 @@ static int mmc_decode_csd(struct mmc_card *card)
csd->write_partial = 0; csd->write_partial = 0;
break; break;
default: default:
printk("%s: unrecognised CSD structure version %d\n", printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
mmc_hostname(card->host), csd_struct); mmc_hostname(card->host), csd_struct);
return -EINVAL; return -EINVAL;
} }
...@@ -173,7 +173,7 @@ static int mmc_decode_scr(struct mmc_card *card) ...@@ -173,7 +173,7 @@ static int mmc_decode_scr(struct mmc_card *card)
scr_struct = UNSTUFF_BITS(resp, 60, 4); scr_struct = UNSTUFF_BITS(resp, 60, 4);
if (scr_struct != 0) { if (scr_struct != 0) {
printk("%s: unrecognised SCR structure version %d\n", printk(KERN_ERR "%s: unrecognised SCR structure version %d\n",
mmc_hostname(card->host), scr_struct); mmc_hostname(card->host), scr_struct);
return -EINVAL; return -EINVAL;
} }
...@@ -206,9 +206,8 @@ static int mmc_read_switch(struct mmc_card *card) ...@@ -206,9 +206,8 @@ static int mmc_read_switch(struct mmc_card *card)
status = kmalloc(64, GFP_KERNEL); status = kmalloc(64, GFP_KERNEL);
if (!status) { if (!status) {
printk("%s: could not allocate a buffer for switch " printk(KERN_ERR "%s: could not allocate a buffer for "
"capabilities.\n", "switch capabilities.\n", mmc_hostname(card->host));
mmc_hostname(card->host));
return err; return err;
} }
...@@ -254,9 +253,8 @@ static int mmc_switch_hs(struct mmc_card *card) ...@@ -254,9 +253,8 @@ static int mmc_switch_hs(struct mmc_card *card)
status = kmalloc(64, GFP_KERNEL); status = kmalloc(64, GFP_KERNEL);
if (!status) { if (!status) {
printk("%s: could not allocate a buffer for switch " printk(KERN_ERR "%s: could not allocate a buffer for "
"capabilities.\n", "switch capabilities.\n", mmc_hostname(card->host));
mmc_hostname(card->host));
return err; return err;
} }
...@@ -573,14 +571,17 @@ static void mmc_sd_resume(struct mmc_host *host) ...@@ -573,14 +571,17 @@ static void mmc_sd_resume(struct mmc_host *host)
BUG_ON(!host->card); BUG_ON(!host->card);
mmc_claim_host(host); mmc_claim_host(host);
err = mmc_sd_init_card(host, host->ocr, host->card); err = mmc_sd_init_card(host, host->ocr, host->card);
mmc_release_host(host);
if (err != MMC_ERR_NONE) { if (err != MMC_ERR_NONE) {
mmc_sd_remove(host); mmc_sd_remove(host);
mmc_claim_host(host);
mmc_detach_bus(host); mmc_detach_bus(host);
mmc_release_host(host);
} }
mmc_release_host(host);
} }
#else #else
...@@ -634,8 +635,10 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) ...@@ -634,8 +635,10 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
/* /*
* Can we support the voltage(s) of the card(s)? * Can we support the voltage(s) of the card(s)?
*/ */
if (!host->ocr) if (!host->ocr) {
err = -EINVAL;
goto err; goto err;
}
/* /*
* Detect and init the card. * Detect and init the card.
...@@ -648,18 +651,21 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) ...@@ -648,18 +651,21 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
err = mmc_add_card(host->card); err = mmc_add_card(host->card);
if (err) if (err)
goto reclaim_host; goto remove_card;
return 0; return 0;
reclaim_host: remove_card:
mmc_claim_host(host);
mmc_remove_card(host->card); mmc_remove_card(host->card);
host->card = NULL; host->card = NULL;
mmc_claim_host(host);
err: err:
mmc_detach_bus(host); mmc_detach_bus(host);
mmc_release_host(host); mmc_release_host(host);
printk(KERN_ERR "%s: error %d whilst initialising SD card\n",
mmc_hostname(host), err);
return 0; return 0;
} }
/* /*
* linux/drivers/mmc/sd_ops.h * linux/drivers/mmc/core/sd_ops.h
* *
* Copyright 2006-2007 Pierre Ossman * Copyright 2006-2007 Pierre Ossman
* *
...@@ -21,11 +21,40 @@ ...@@ -21,11 +21,40 @@
#include "core.h" #include "core.h"
#include "sd_ops.h" #include "sd_ops.h"
static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
{
int err;
struct mmc_command cmd;
BUG_ON(!host);
BUG_ON(card && (card->host != host));
cmd.opcode = MMC_APP_CMD;
if (card) {
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
} else {
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
}
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err != MMC_ERR_NONE)
return err;
/* Check that card supported application commands */
if (!(cmd.resp[0] & R1_APP_CMD))
return MMC_ERR_FAILED;
return MMC_ERR_NONE;
}
/** /**
* mmc_wait_for_app_cmd - start an application command and wait for * mmc_wait_for_app_cmd - start an application command and wait for
completion completion
* @host: MMC host to start command * @host: MMC host to start command
* @rca: RCA to send MMC_APP_CMD to * @card: Card to send MMC_APP_CMD to
* @cmd: MMC command to start * @cmd: MMC command to start
* @retries: maximum number of retries * @retries: maximum number of retries
* *
...@@ -77,35 +106,6 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, ...@@ -77,35 +106,6 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
EXPORT_SYMBOL(mmc_wait_for_app_cmd); EXPORT_SYMBOL(mmc_wait_for_app_cmd);
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
{
int err;
struct mmc_command cmd;
BUG_ON(!host);
BUG_ON(card && (card->host != host));
cmd.opcode = MMC_APP_CMD;
if (card) {
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
} else {
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
}
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err != MMC_ERR_NONE)
return err;
/* Check that card supported application commands */
if (!(cmd.resp[0] & R1_APP_CMD))
return MMC_ERR_FAILED;
return MMC_ERR_NONE;
}
int mmc_app_set_bus_width(struct mmc_card *card, int width) int mmc_app_set_bus_width(struct mmc_card *card, int width)
{ {
int err; int err;
......
/* /*
* linux/drivers/mmc/sd_ops.h * linux/drivers/mmc/core/sd_ops.h
* *
* Copyright 2006-2007 Pierre Ossman * Copyright 2006-2007 Pierre Ossman
* *
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#ifndef _MMC_SD_OPS_H #ifndef _MMC_SD_OPS_H
#define _MMC_SD_OPS_H #define _MMC_SD_OPS_H
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
int mmc_app_set_bus_width(struct mmc_card *card, int width); int mmc_app_set_bus_width(struct mmc_card *card, int width);
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_send_if_cond(struct mmc_host *host, u32 ocr); int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
......
/* /*
* linux/drivers/mmc/at91_mci.c - ATMEL AT91 MCI Driver * linux/drivers/mmc/host/at91_mci.c - ATMEL AT91 MCI Driver
* *
* Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved * Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
* *
......
/* /*
* linux/drivers/mmc/au1xmmc.c - AU1XX0 MMC driver * linux/drivers/mmc/host/au1xmmc.c - AU1XX0 MMC driver
* *
* Copyright (c) 2005, Advanced Micro Devices, Inc. * Copyright (c) 2005, Advanced Micro Devices, Inc.
* *
......
/* /*
* linux/drivers/mmc/imxmmc.c - Motorola i.MX MMCI driver * linux/drivers/mmc/host/imxmmc.c - Motorola i.MX MMCI driver
* *
* Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de> * Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de>
* Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com> * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
......
/* /*
* linux/drivers/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver * linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
* *
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
* *
......
/* /*
* linux/drivers/mmc/mmci.h - ARM PrimeCell MMCI PL180/1 driver * linux/drivers/mmc/host/mmci.h - ARM PrimeCell MMCI PL180/1 driver
* *
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
* *
......
/* /*
* linux/drivers/media/mmc/omap.c * linux/drivers/mmc/host/omap.c
* *
* Copyright (C) 2004 Nokia Corporation * Copyright (C) 2004 Nokia Corporation
* Written by Tuukka Tikkanen and Juha Yrjl<juha.yrjola@nokia.com> * Written by Tuukka Tikkanen and Juha Yrjl<juha.yrjola@nokia.com>
......
/* /*
* linux/drivers/mmc/pxa.c - PXA MMCI driver * linux/drivers/mmc/host/pxa.c - PXA MMCI driver
* *
* Copyright (C) 2003 Russell King, All Rights Reserved. * Copyright (C) 2003 Russell King, All Rights Reserved.
* *
......
/* /*
* linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver * linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
* *
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
* *
...@@ -34,6 +34,7 @@ static unsigned int debug_quirks = 0; ...@@ -34,6 +34,7 @@ static unsigned int debug_quirks = 0;
/* Controller doesn't like some resets when there is no card inserted. */ /* Controller doesn't like some resets when there is no card inserted. */
#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) #define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4)
static const struct pci_device_id pci_ids[] __devinitdata = { static const struct pci_device_id pci_ids[] __devinitdata = {
{ {
...@@ -78,6 +79,24 @@ static const struct pci_device_id pci_ids[] __devinitdata = { ...@@ -78,6 +79,24 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE, .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE,
}, },
{
.vendor = PCI_VENDOR_ID_ENE,
.device = PCI_DEVICE_ID_ENE_CB714_SD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
},
{
.vendor = PCI_VENDOR_ID_ENE,
.device = PCI_DEVICE_ID_ENE_CB714_SD_2,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
},
{ /* Generic SD host controller */ { /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
}, },
...@@ -361,11 +380,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) ...@@ -361,11 +380,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
if (data == NULL) if (data == NULL)
return; return;
DBG("blksz %04x blks %04x flags %08x\n",
data->blksz, data->blocks, data->flags);
DBG("tsac %d ms nsac %d clk\n",
data->timeout_ns / 1000000, data->timeout_clks);
/* Sanity checks */ /* Sanity checks */
BUG_ON(data->blksz * data->blocks > 524288); BUG_ON(data->blksz * data->blocks > 524288);
BUG_ON(data->blksz > host->mmc->max_blk_size); BUG_ON(data->blksz > host->mmc->max_blk_size);
...@@ -476,8 +490,6 @@ static void sdhci_finish_data(struct sdhci_host *host) ...@@ -476,8 +490,6 @@ static void sdhci_finish_data(struct sdhci_host *host)
data->error = MMC_ERR_FAILED; data->error = MMC_ERR_FAILED;
} }
DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered);
if (data->stop) { if (data->stop) {
/* /*
* The controller needs a reset of internal state machines * The controller needs a reset of internal state machines
...@@ -501,8 +513,6 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) ...@@ -501,8 +513,6 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
WARN_ON(host->cmd); WARN_ON(host->cmd);
DBG("Sending cmd (%x)\n", cmd->opcode);
/* Wait max 10 ms */ /* Wait max 10 ms */
timeout = 10; timeout = 10;
...@@ -590,8 +600,6 @@ static void sdhci_finish_command(struct sdhci_host *host) ...@@ -590,8 +600,6 @@ static void sdhci_finish_command(struct sdhci_host *host)
host->cmd->error = MMC_ERR_NONE; host->cmd->error = MMC_ERR_NONE;
DBG("Ending cmd (%x)\n", host->cmd->opcode);
if (host->cmd->data) if (host->cmd->data)
host->data = host->cmd->data; host->data = host->cmd->data;
else else
...@@ -759,6 +767,14 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -759,6 +767,14 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
/*
* Some (ENE) controllers go apeshit on some ios operation,
* signalling timeout and CRC errors even on CMD0. Resetting
* it on each ios seems to solve the problem.
*/
if(host->chip->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
mmiowb(); mmiowb();
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
} }
...@@ -835,8 +851,6 @@ static void sdhci_tasklet_finish(unsigned long param) ...@@ -835,8 +851,6 @@ static void sdhci_tasklet_finish(unsigned long param)
mrq = host->mrq; mrq = host->mrq;
DBG("Ending request, cmd (%x)\n", mrq->cmd->opcode);
/* /*
* The controller needs a reset of internal state machines * The controller needs a reset of internal state machines
* upon error conditions. * upon error conditions.
...@@ -922,20 +936,17 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) ...@@ -922,20 +936,17 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
return; return;
} }
if (intmask & SDHCI_INT_RESPONSE)
sdhci_finish_command(host);
else {
if (intmask & SDHCI_INT_TIMEOUT) if (intmask & SDHCI_INT_TIMEOUT)
host->cmd->error = MMC_ERR_TIMEOUT; host->cmd->error = MMC_ERR_TIMEOUT;
else if (intmask & SDHCI_INT_CRC) else if (intmask & SDHCI_INT_CRC)
host->cmd->error = MMC_ERR_BADCRC; host->cmd->error = MMC_ERR_BADCRC;
else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
host->cmd->error = MMC_ERR_FAILED; host->cmd->error = MMC_ERR_FAILED;
else
host->cmd->error = MMC_ERR_INVALID;
if (host->cmd->error != MMC_ERR_NONE)
tasklet_schedule(&host->finish_tasklet); tasklet_schedule(&host->finish_tasklet);
} else if (intmask & SDHCI_INT_RESPONSE)
sdhci_finish_command(host);
} }
static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
......
/* /*
* linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver * linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver
* *
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
* *
......
/* /*
* linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver * linux/drivers/mmc/host/wbsd.c - Winbond W83L51xD SD/MMC driver
* *
* Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved. * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
* *
...@@ -207,8 +207,6 @@ static void wbsd_request_end(struct wbsd_host *host, struct mmc_request *mrq) ...@@ -207,8 +207,6 @@ static void wbsd_request_end(struct wbsd_host *host, struct mmc_request *mrq)
{ {
unsigned long dmaflags; unsigned long dmaflags;
DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode);
if (host->dma >= 0) { if (host->dma >= 0) {
/* /*
* Release ISA DMA controller. * Release ISA DMA controller.
...@@ -360,8 +358,6 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd) ...@@ -360,8 +358,6 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
int i; int i;
u8 status, isr; u8 status, isr;
DBGF("Sending cmd (%x)\n", cmd->opcode);
/* /*
* Clear accumulated ISR. The interrupt routine * Clear accumulated ISR. The interrupt routine
* will fill this one with events that occur during * will fill this one with events that occur during
...@@ -411,8 +407,6 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd) ...@@ -411,8 +407,6 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
wbsd_get_short_reply(host, cmd); wbsd_get_short_reply(host, cmd);
} }
} }
DBGF("Sent cmd (%x), res %d\n", cmd->opcode, cmd->error);
} }
/* /*
...@@ -550,11 +544,6 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) ...@@ -550,11 +544,6 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
unsigned long dmaflags; unsigned long dmaflags;
unsigned int size; unsigned int size;
DBGF("blksz %04x blks %04x flags %08x\n",
data->blksz, data->blocks, data->flags);
DBGF("tsac %d ms nsac %d clk\n",
data->timeout_ns / 1000000, data->timeout_clks);
/* /*
* Calculate size. * Calculate size.
*/ */
...@@ -752,8 +741,6 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) ...@@ -752,8 +741,6 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
} }
} }
DBGF("Ending data transfer (%d bytes)\n", data->bytes_xfered);
wbsd_request_end(host, host->mrq); wbsd_request_end(host, host->mrq);
} }
......
/* /*
* linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver * linux/drivers/mmc/host/wbsd.h - Winbond W83L51xD SD/MMC driver
* *
* Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved. * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
* *
......
...@@ -99,7 +99,7 @@ struct mmc_request { ...@@ -99,7 +99,7 @@ struct mmc_request {
struct mmc_host; struct mmc_host;
struct mmc_card; struct mmc_card;
extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *); extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
struct mmc_command *, int); struct mmc_command *, int);
......
...@@ -1976,6 +1976,8 @@ ...@@ -1976,6 +1976,8 @@
#define PCI_VENDOR_ID_ENE 0x1524 #define PCI_VENDOR_ID_ENE 0x1524
#define PCI_DEVICE_ID_ENE_CB712_SD 0x0550 #define PCI_DEVICE_ID_ENE_CB712_SD 0x0550
#define PCI_DEVICE_ID_ENE_CB712_SD_2 0x0551 #define PCI_DEVICE_ID_ENE_CB712_SD_2 0x0551
#define PCI_DEVICE_ID_ENE_CB714_SD 0x0750
#define PCI_DEVICE_ID_ENE_CB714_SD_2 0x0751
#define PCI_DEVICE_ID_ENE_1211 0x1211 #define PCI_DEVICE_ID_ENE_1211 0x1211
#define PCI_DEVICE_ID_ENE_1225 0x1225 #define PCI_DEVICE_ID_ENE_1225 0x1225
#define PCI_DEVICE_ID_ENE_1410 0x1410 #define PCI_DEVICE_ID_ENE_1410 0x1410
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment