Commit 6abd2c86 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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: (67 commits)
  mmc: don't use weight32()
  pxamci: support arbitrary block size
  sdio: make the IRQ thread more resilient in the presence of bad states
  sdio: fix IRQ diagnostic message
  sdhci: remove old dma module params
  sdhci: add SDHCI_QUIRK_BROKEN_DMA quirk
  sdhci: remove DMA capability check from controller's PCI Class reg
  sdhci: fix a typo
  mmc: Disabler for Ricoh MMC controller
  sdio: adaptive interrupt polling
  mmc: pxamci: add SDIO card interrupt reporting capability
  mmc: pxamci: set proper buswidth capabilities according to PXA flavor
  mmc: pxamci: set proper block capabilities according to PXA flavor
  mmc: pxamci: better pending IRQ determination
  arm: i.MX/MX1 SDHC implements SD cards read-only switch read-back
  mmc: add led trigger
  mmc_spi host driver
  MMC core learns about SPI
  MMC/SD card driver learns SPI
  MMC headers learn about SPI
  ...
parents d2c75f2f 019a5f56
......@@ -2561,12 +2561,18 @@ L: linux-kernel@vger.kernel.org
W: http://www.atnf.csiro.au/~rgooch/linux/kernel-patches.html
S: Maintained
MULTIMEDIA CARD (MMC) AND SECURE DIGITAL (SD) SUBSYSTEM
MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
P: Pierre Ossman
M: drzeus-mmc@drzeus.cx
L: linux-kernel@vger.kernel.org
S: Maintained
MULTIMEDIA CARD (MMC) ETC. OVER SPI
P: David Brownell
M: dbrownell@users.sourceforge.net
L: linux-kernel@vger.kernel.org
S: Odd fixes
MULTISOUND SOUND DRIVER
P: Andrew Veliath
M: andrewtv@usa.net
......
......@@ -116,7 +116,7 @@ static struct platform_device *devices[] __initdata = {
};
#ifdef CONFIG_MMC_IMX
static int mx1ads_mmc_card_present(void)
static int mx1ads_mmc_card_present(struct device *dev)
{
/* MMC/SD Card Detect is PB 20 on MX1ADS V1.0.7 */
return (SSR(1) & (1 << 20) ? 0 : 1);
......
......@@ -32,3 +32,10 @@ config MMC_BLOCK_BOUNCE
If unsure, say Y here.
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.
......@@ -9,3 +9,5 @@ endif
obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
mmc_block-objs := block.o queue.o
obj-$(CONFIG_SDIO_UART) += sdio_uart.o
......@@ -151,17 +151,19 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
cmd.opcode = MMC_APP_CMD;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD))
if (err)
return (u32)-1;
if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
return (u32)-1;
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
memset(&data, 0, sizeof(struct mmc_data));
......@@ -192,7 +194,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
mmc_wait_for_req(card->host, &mrq);
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE)
if (cmd.error || data.error)
return (u32)-1;
blocks = ntohl(blocks);
......@@ -220,17 +222,15 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.cmd.arg = req->sector;
if (!mmc_card_blockaddr(card))
brq.cmd.arg <<= 9;
brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
brq.data.blksz = 1 << md->block_bits;
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
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;
mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
/*
* If the host doesn't support multiple block writes, force
* block writes to single block. SD cards are excepted from
......@@ -243,8 +243,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.data.blocks = 1;
if (brq.data.blocks > 1) {
brq.data.flags |= MMC_DATA_MULTI;
brq.mrq.stop = &brq.stop;
/* SPI multiblock writes terminate using a special
* token, not a STOP_TRANSMISSION request.
*/
if (!mmc_host_is_spi(card->host)
|| rq_data_dir(req) == READ)
brq.mrq.stop = &brq.stop;
readcmd = MMC_READ_MULTIPLE_BLOCK;
writecmd = MMC_WRITE_MULTIPLE_BLOCK;
} else {
......@@ -261,6 +265,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.data.flags |= MMC_DATA_WRITE;
}
mmc_set_data_timeout(&brq.data, card);
brq.data.sg = mq->sg;
brq.data.sg_len = mmc_queue_map_sg(mq);
......@@ -302,7 +308,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
goto cmd_err;
}
if (rq_data_dir(req) != READ) {
if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
do {
int err;
......@@ -510,7 +516,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.flags = MMC_RSP_R1 | MMC_CMD_AC;
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);
......
This diff is collapsed.
......@@ -8,5 +8,7 @@ endif
obj-$(CONFIG_MMC) += mmc_core.o
mmc_core-y := core.o sysfs.o bus.o host.o \
mmc.o mmc_ops.o sd.o sd_ops.o
mmc.o mmc_ops.o sd.o sd_ops.o \
sdio.o sdio_ops.o sdio_bus.o \
sdio_cis.o sdio_io.o sdio_irq.o
......@@ -19,6 +19,7 @@
#include "sysfs.h"
#include "core.h"
#include "sdio_cis.h"
#include "bus.h"
#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
......@@ -34,6 +35,8 @@ static ssize_t mmc_type_show(struct device *dev,
return sprintf(buf, "MMC\n");
case MMC_TYPE_SD:
return sprintf(buf, "SD\n");
case MMC_TYPE_SDIO:
return sprintf(buf, "SDIO\n");
default:
return -EFAULT;
}
......@@ -59,28 +62,34 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
int buf_size)
{
struct mmc_card *card = dev_to_mmc_card(dev);
int retval = 0, i = 0, length = 0;
#define add_env(fmt,val) do { \
retval = add_uevent_var(envp, num_envp, &i, \
buf, buf_size, &length, \
fmt, val); \
if (retval) \
return retval; \
} while (0);
const char *type;
int i = 0, length = 0;
switch (card->type) {
case MMC_TYPE_MMC:
add_env("MMC_TYPE=%s", "MMC");
type = "MMC";
break;
case MMC_TYPE_SD:
add_env("MMC_TYPE=%s", "SD");
type = "SD";
break;
case MMC_TYPE_SDIO:
type = "SDIO";
break;
default:
type = NULL;
}
add_env("MMC_NAME=%s", mmc_card_name(card));
if (type) {
if (add_uevent_var(envp, num_envp, &i,
buf, buf_size, &length,
"MMC_TYPE=%s", type))
return -ENOMEM;
}
#undef add_env
if (add_uevent_var(envp, num_envp, &i,
buf, buf_size, &length,
"MMC_NAME=%s", mmc_card_name(card)))
return -ENOMEM;
envp[i] = NULL;
......@@ -176,6 +185,11 @@ static void mmc_release_card(struct device *dev)
{
struct mmc_card *card = dev_to_mmc_card(dev);
sdio_free_common_cis(card);
if (card->info)
kfree(card->info);
kfree(card);
}
......@@ -221,15 +235,25 @@ int mmc_add_card(struct mmc_card *card)
if (mmc_card_blockaddr(card))
type = "SDHC";
break;
case MMC_TYPE_SDIO:
type = "SDIO";
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);
if (mmc_host_is_spi(card->host)) {
printk(KERN_INFO "%s: new %s%s card on SPI\n",
mmc_hostname(card->host),
mmc_card_highspeed(card) ? "high speed " : "",
type);
} else {
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;
......@@ -261,8 +285,13 @@ int mmc_add_card(struct mmc_card *card)
void mmc_remove_card(struct mmc_card *card)
{
if (mmc_card_present(card)) {
printk(KERN_INFO "%s: card %04x removed\n",
mmc_hostname(card->host), card->rca);
if (mmc_host_is_spi(card->host)) {
printk(KERN_INFO "%s: SPI card removed\n",
mmc_hostname(card->host));
} else {
printk(KERN_INFO "%s: card %04x removed\n",
mmc_hostname(card->host), card->rca);
}
if (card->host->bus_ops->sysfs_remove)
card->host->bus_ops->sysfs_remove(card->host, card);
......
......@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/pagemap.h>
#include <linux/err.h>
#include <linux/leds.h>
#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
......@@ -29,15 +30,26 @@
#include "core.h"
#include "bus.h"
#include "host.h"
#include "sdio_bus.h"
#include "mmc_ops.h"
#include "sd_ops.h"
#include "sdio_ops.h"
extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
extern int mmc_attach_sd(struct mmc_host *host, u32 ocr);
extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
static struct workqueue_struct *workqueue;
/*
* Enabling software CRCs on the data blocks can be a significant (30%)
* performance cost, and for other reasons may not always be desired.
* So we allow it it to be disabled.
*/
int use_spi_crc = 1;
module_param(use_spi_crc, bool, 0);
/*
* Internal function. Schedule delayed work in the MMC work queue.
*/
......@@ -68,6 +80,11 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
struct mmc_command *cmd = mrq->cmd;
int err = cmd->error;
if (err && cmd->retries && mmc_host_is_spi(host)) {
if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
cmd->retries = 0;
}
if (err && cmd->retries) {
pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
mmc_hostname(host), cmd->opcode, err);
......@@ -76,6 +93,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
cmd->error = 0;
host->ops->request(host, mrq);
} else {
led_trigger_event(host->led, LED_OFF);
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],
......@@ -118,7 +137,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
"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_ns / 1000000,
mrq->data->timeout_clks);
}
......@@ -130,6 +149,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
WARN_ON(!host->claimed);
led_trigger_event(host->led, LED_FULL);
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
if (mrq->data) {
......@@ -199,7 +220,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
{
struct mmc_request mrq;
BUG_ON(!host->claimed);
WARN_ON(!host->claimed);
memset(&mrq, 0, sizeof(struct mmc_request));
......@@ -220,16 +241,23 @@ EXPORT_SYMBOL(mmc_wait_for_cmd);
* mmc_set_data_timeout - set the timeout for a data command
* @data: data phase for command
* @card: the MMC card associated with the data transfer
* @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,
int write)
void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
{
unsigned int mult;
/*
* SDIO cards only define an upper 1 s limit on access.
*/
if (mmc_card_sdio(card)) {
data->timeout_ns = 1000000000;
data->timeout_clks = 0;
return;
}
/*
* SD cards use a 100 multiplier rather than 10
*/
......@@ -239,7 +267,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
* Scale up the multiplier (and therefore the timeout) by
* the r2w factor for writes.
*/
if (write)
if (data->flags & MMC_DATA_WRITE)
mult <<= card->csd.r2w_factor;
data->timeout_ns = card->csd.tacc_ns * mult;
......@@ -255,7 +283,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
timeout_us += data->timeout_clks * 1000 /
(card->host->ios.clock / 1000);
if (write)
if (data->flags & MMC_DATA_WRITE)
limit_us = 250000;
else
limit_us = 100000;
......@@ -272,15 +300,20 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
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
* @abort: whether or not the operation should be aborted
*
* Claim a host for a set of operations.
* Claim a host for a set of operations. If @abort is non null and
* dereference a non-zero value then this will return prematurely with
* that non-zero value without acquiring the lock. Returns zero
* with the lock held otherwise.
*/
void mmc_claim_host(struct mmc_host *host)
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
int stop;
might_sleep();
......@@ -288,19 +321,24 @@ void mmc_claim_host(struct mmc_host *host)
spin_lock_irqsave(&host->lock, flags);
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (!host->claimed)
stop = abort ? atomic_read(abort) : 0;
if (stop || !host->claimed)
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING);
host->claimed = 1;
if (!stop)
host->claimed = 1;
else
wake_up(&host->wq);
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
return stop;
}
EXPORT_SYMBOL(mmc_claim_host);
EXPORT_SYMBOL(__mmc_claim_host);
/**
* mmc_release_host - release a host
......@@ -313,7 +351,7 @@ void mmc_release_host(struct mmc_host *host)
{
unsigned long flags;
BUG_ON(!host->claimed);
WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
host->claimed = 0;
......@@ -433,19 +471,32 @@ static void mmc_power_up(struct mmc_host *host)
int bit = fls(host->ocr_avail) - 1;
host->ios.vdd = bit;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.chip_select = MMC_CS_DONTCARE;
if (mmc_host_is_spi(host)) {
host->ios.chip_select = MMC_CS_HIGH;
host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
} else {
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
}
host->ios.power_mode = MMC_POWER_UP;
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
mmc_delay(1);
/*
* This delay should be sufficient to allow the power supply
* to reach the minimum voltage.
*/
mmc_delay(2);
host->ios.clock = host->f_min;
host->ios.power_mode = MMC_POWER_ON;
mmc_set_ios(host);
/*
* This delay must be at least 74 clock sizes, or 1 ms, or the
* time required to reach a stable voltage.
*/
mmc_delay(2);
}
......@@ -453,8 +504,10 @@ static void mmc_power_off(struct mmc_host *host)
{
host->ios.clock = 0;
host->ios.vdd = 0;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.chip_select = MMC_CS_DONTCARE;
if (!mmc_host_is_spi(host)) {
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.chip_select = MMC_CS_DONTCARE;
}
host->ios.power_mode = MMC_POWER_OFF;
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
......@@ -511,7 +564,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
BUG_ON(!host);
BUG_ON(!ops);
BUG_ON(!host->claimed);
WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
......@@ -535,8 +588,8 @@ void mmc_detach_bus(struct mmc_host *host)
BUG_ON(!host);
BUG_ON(!host->claimed);
BUG_ON(!host->bus_ops);
WARN_ON(!host->claimed);
WARN_ON(!host->bus_ops);
spin_lock_irqsave(&host->lock, flags);
......@@ -564,7 +617,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
#ifdef CONFIG_MMC_DEBUG
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
BUG_ON(host->removed);
WARN_ON(host->removed);
spin_unlock_irqrestore(&host->lock, flags);
#endif
......@@ -597,24 +650,38 @@ void mmc_rescan(struct work_struct *work)
mmc_send_if_cond(host, host->ocr_avail);
/*
* First we search for SDIO...
*/
err = mmc_send_io_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_sdio(host, ocr))
mmc_power_off(host);
return;
}
/*
* ...then normal SD...
*/
err = mmc_send_app_op_cond(host, 0, &ocr);
if (err == MMC_ERR_NONE) {
if (!err) {
if (mmc_attach_sd(host, ocr))
mmc_power_off(host);
} else {
/*
* If we fail to detect any SD cards then try
* searching for MMC cards.
*/
err = mmc_send_op_cond(host, 0, &ocr);
if (err == MMC_ERR_NONE) {
if (mmc_attach_mmc(host, ocr))
mmc_power_off(host);
} else {
return;
}
/*
* ...and finally MMC.
*/
err = mmc_send_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_mmc(host, ocr))
mmc_power_off(host);
mmc_release_host(host);
}
return;
}
mmc_release_host(host);
mmc_power_off(host);
} else {
if (host->bus_ops->detect && !host->bus_dead)
host->bus_ops->detect(host);
......@@ -725,22 +792,38 @@ static int __init mmc_init(void)
return -ENOMEM;
ret = mmc_register_bus();
if (ret == 0) {
ret = mmc_register_host_class();
if (ret)
mmc_unregister_bus();
}
if (ret)
goto destroy_workqueue;
ret = mmc_register_host_class();
if (ret)
goto unregister_bus;
ret = sdio_register_bus();
if (ret)
goto unregister_host_class;
return 0;
unregister_host_class:
mmc_unregister_host_class();
unregister_bus:
mmc_unregister_bus();
destroy_workqueue:
destroy_workqueue(workqueue);
return ret;
}
static void __exit mmc_exit(void)
{
sdio_unregister_bus();
mmc_unregister_host_class();
mmc_unregister_bus();
destroy_workqueue(workqueue);
}
module_init(mmc_init);
subsys_initcall(mmc_init);
module_exit(mmc_exit);
MODULE_LICENSE("GPL");
......@@ -48,5 +48,7 @@ void mmc_rescan(struct work_struct *work);