summaryrefslogtreecommitdiff
path: root/drivers/mmc/host
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-07-26 20:27:31 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-26 20:27:31 -0700
commitbdee6ac7d1c9a4a9b65db1753b0bfa0b61361dde (patch)
treed2d260a3aa7e0902be023c0fbdb52ec26dbd6609 /drivers/mmc/host
parent4836e3007882984279ca63d3c42bf0b14616eb78 (diff)
parentdeec9ae31e6079551ce9260d29a4cf83e5b19a83 (diff)
downloadlinux-3.10-bdee6ac7d1c9a4a9b65db1753b0bfa0b61361dde.tar.gz
linux-3.10-bdee6ac7d1c9a4a9b65db1753b0bfa0b61361dde.tar.bz2
linux-3.10-bdee6ac7d1c9a4a9b65db1753b0bfa0b61361dde.zip
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: atmel-mci: debugfs support mmc: Add per-card debugfs support mmc: Export internal host state through debugfs imxmmc: fix crash when no platform data is provided imxmmc: fix platform resources imxmmc: remove DEBUG definition mmc_spi: put signals to low power off fix
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r--drivers/mmc/host/atmel-mci-regs.h2
-rw-r--r--drivers/mmc/host/atmel-mci.c189
-rw-r--r--drivers/mmc/host/imxmmc.c50
-rw-r--r--drivers/mmc/host/mmc_spi.c3
4 files changed, 208 insertions, 36 deletions
diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h
index a9a5657706c..26bd80e6503 100644
--- a/drivers/mmc/host/atmel-mci-regs.h
+++ b/drivers/mmc/host/atmel-mci-regs.h
@@ -82,6 +82,8 @@
# define MCI_OVRE ( 1 << 30) /* RX Overrun Error */
# define MCI_UNRE ( 1 << 31) /* TX Underrun Error */
+#define MCI_REGS_SIZE 0x100
+
/* Register access macros */
#define mci_readl(port,reg) \
__raw_readl((port)->regs + MCI_##reg)
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index cce873c5a14..b68381f7bfd 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -9,6 +9,7 @@
*/
#include <linux/blkdev.h>
#include <linux/clk.h>
+#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -16,6 +17,8 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
+#include <linux/seq_file.h>
+#include <linux/stat.h>
#include <linux/mmc/host.h>
@@ -88,6 +91,188 @@ struct atmel_mci {
#define atmci_clear_pending(host, event) \
clear_bit(event, &host->pending_events)
+/*
+ * The debugfs stuff below is mostly optimized away when
+ * CONFIG_DEBUG_FS is not set.
+ */
+static int atmci_req_show(struct seq_file *s, void *v)
+{
+ struct atmel_mci *host = s->private;
+ struct mmc_request *mrq = host->mrq;
+ struct mmc_command *cmd;
+ struct mmc_command *stop;
+ struct mmc_data *data;
+
+ /* Make sure we get a consistent snapshot */
+ spin_lock_irq(&host->mmc->lock);
+
+ if (mrq) {
+ cmd = mrq->cmd;
+ data = mrq->data;
+ stop = mrq->stop;
+
+ if (cmd)
+ seq_printf(s,
+ "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
+ cmd->opcode, cmd->arg, cmd->flags,
+ cmd->resp[0], cmd->resp[1], cmd->resp[2],
+ cmd->resp[2], cmd->error);
+ if (data)
+ seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
+ data->bytes_xfered, data->blocks,
+ data->blksz, data->flags, data->error);
+ if (stop)
+ seq_printf(s,
+ "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
+ stop->opcode, stop->arg, stop->flags,
+ stop->resp[0], stop->resp[1], stop->resp[2],
+ stop->resp[2], stop->error);
+ }
+
+ spin_unlock_irq(&host->mmc->lock);
+
+ return 0;
+}
+
+static int atmci_req_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, atmci_req_show, inode->i_private);
+}
+
+static const struct file_operations atmci_req_fops = {
+ .owner = THIS_MODULE,
+ .open = atmci_req_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void atmci_show_status_reg(struct seq_file *s,
+ const char *regname, u32 value)
+{
+ static const char *sr_bit[] = {
+ [0] = "CMDRDY",
+ [1] = "RXRDY",
+ [2] = "TXRDY",
+ [3] = "BLKE",
+ [4] = "DTIP",
+ [5] = "NOTBUSY",
+ [8] = "SDIOIRQA",
+ [9] = "SDIOIRQB",
+ [16] = "RINDE",
+ [17] = "RDIRE",
+ [18] = "RCRCE",
+ [19] = "RENDE",
+ [20] = "RTOE",
+ [21] = "DCRCE",
+ [22] = "DTOE",
+ [30] = "OVRE",
+ [31] = "UNRE",
+ };
+ unsigned int i;
+
+ seq_printf(s, "%s:\t0x%08x", regname, value);
+ for (i = 0; i < ARRAY_SIZE(sr_bit); i++) {
+ if (value & (1 << i)) {
+ if (sr_bit[i])
+ seq_printf(s, " %s", sr_bit[i]);
+ else
+ seq_puts(s, " UNKNOWN");
+ }
+ }
+ seq_putc(s, '\n');
+}
+
+static int atmci_regs_show(struct seq_file *s, void *v)
+{
+ struct atmel_mci *host = s->private;
+ u32 *buf;
+
+ buf = kmalloc(MCI_REGS_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* Grab a more or less consistent snapshot */
+ spin_lock_irq(&host->mmc->lock);
+ memcpy_fromio(buf, host->regs, MCI_REGS_SIZE);
+ spin_unlock_irq(&host->mmc->lock);
+
+ seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
+ buf[MCI_MR / 4],
+ buf[MCI_MR / 4] & MCI_MR_RDPROOF ? " RDPROOF" : "",
+ buf[MCI_MR / 4] & MCI_MR_WRPROOF ? " WRPROOF" : "",
+ buf[MCI_MR / 4] & 0xff);
+ seq_printf(s, "DTOR:\t0x%08x\n", buf[MCI_DTOR / 4]);
+ seq_printf(s, "SDCR:\t0x%08x\n", buf[MCI_SDCR / 4]);
+ seq_printf(s, "ARGR:\t0x%08x\n", buf[MCI_ARGR / 4]);
+ seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n",
+ buf[MCI_BLKR / 4],
+ buf[MCI_BLKR / 4] & 0xffff,
+ (buf[MCI_BLKR / 4] >> 16) & 0xffff);
+
+ /* Don't read RSPR and RDR; it will consume the data there */
+
+ atmci_show_status_reg(s, "SR", buf[MCI_SR / 4]);
+ atmci_show_status_reg(s, "IMR", buf[MCI_IMR / 4]);
+
+ return 0;
+}
+
+static int atmci_regs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, atmci_regs_show, inode->i_private);
+}
+
+static const struct file_operations atmci_regs_fops = {
+ .owner = THIS_MODULE,
+ .open = atmci_regs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void atmci_init_debugfs(struct atmel_mci *host)
+{
+ struct mmc_host *mmc;
+ struct dentry *root;
+ struct dentry *node;
+ struct resource *res;
+
+ mmc = host->mmc;
+ root = mmc->debugfs_root;
+ if (!root)
+ return;
+
+ node = debugfs_create_file("regs", S_IRUSR, root, host,
+ &atmci_regs_fops);
+ if (IS_ERR(node))
+ return;
+ if (!node)
+ goto err;
+
+ res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0);
+ node->d_inode->i_size = res->end - res->start + 1;
+
+ node = debugfs_create_file("req", S_IRUSR, root, host, &atmci_req_fops);
+ if (!node)
+ goto err;
+
+ node = debugfs_create_x32("pending_events", S_IRUSR, root,
+ (u32 *)&host->pending_events);
+ if (!node)
+ goto err;
+
+ node = debugfs_create_x32("completed_events", S_IRUSR, root,
+ (u32 *)&host->completed_events);
+ if (!node)
+ goto err;
+
+ return;
+
+err:
+ dev_err(&host->pdev->dev,
+ "failed to initialize debugfs for controller\n");
+}
static void atmci_enable(struct atmel_mci *host)
{
@@ -905,6 +1090,8 @@ static int __init atmci_probe(struct platform_device *pdev)
"Atmel MCI controller at 0x%08lx irq %d\n",
host->mapbase, irq);
+ atmci_init_debugfs(host);
+
return 0;
err_request_irq:
@@ -923,6 +1110,8 @@ static int __exit atmci_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
if (host) {
+ /* Debugfs stuff is cleaned up by mmc core */
+
if (host->detect_pin >= 0) {
int pin = host->detect_pin;
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c
index 5e880c0f134..f61406da65d 100644
--- a/drivers/mmc/host/imxmmc.c
+++ b/drivers/mmc/host/imxmmc.c
@@ -26,12 +26,6 @@
*
*/
-#ifdef CONFIG_MMC_DEBUG
-#define DEBUG
-#else
-#undef DEBUG
-#endif
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
@@ -907,31 +901,12 @@ static const struct mmc_host_ops imxmci_ops = {
.get_ro = imxmci_get_ro,
};
-static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr)
-{
- int i;
-
- for (i = 0; i < dev->num_resources; i++)
- if (dev->resource[i].flags == mask && nr-- == 0)
- return &dev->resource[i];
- return NULL;
-}
-
-static int platform_device_irq(struct platform_device *dev, int nr)
-{
- int i;
-
- for (i = 0; i < dev->num_resources; i++)
- if (dev->resource[i].flags == IORESOURCE_IRQ && nr-- == 0)
- return dev->resource[i].start;
- return NO_IRQ;
-}
-
static void imxmci_check_status(unsigned long data)
{
struct imxmci_host *host = (struct imxmci_host *)data;
- if( host->pdata->card_present(mmc_dev(host->mmc)) != host->present ) {
+ if (host->pdata && host->pdata->card_present &&
+ host->pdata->card_present(mmc_dev(host->mmc)) != host->present) {
host->present ^= 1;
dev_info(mmc_dev(host->mmc), "card %s\n",
host->present ? "inserted" : "removed");
@@ -962,13 +937,12 @@ static int imxmci_probe(struct platform_device *pdev)
printk(KERN_INFO "i.MX mmc driver\n");
- r = platform_device_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_device_irq(pdev, 0);
- if (!r || irq == NO_IRQ)
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!r || irq < 0)
return -ENXIO;
- r = request_mem_region(r->start, 0x100, "IMXMCI");
- if (!r)
+ if (!request_mem_region(r->start, 0x100, pdev->name))
return -EBUSY;
mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev);
@@ -995,6 +969,8 @@ static int imxmci_probe(struct platform_device *pdev)
host->mmc = mmc;
host->dma_allocated = 0;
host->pdata = pdev->dev.platform_data;
+ if (!host->pdata)
+ dev_warn(&pdev->dev, "No platform data provided!\n");
spin_lock_init(&host->lock);
host->res = r;
@@ -1047,7 +1023,11 @@ static int imxmci_probe(struct platform_device *pdev)
if (ret)
goto out;
- host->present = host->pdata->card_present(mmc_dev(mmc));
+ if (host->pdata && host->pdata->card_present)
+ host->present = host->pdata->card_present(mmc_dev(mmc));
+ else /* if there is no way to detect assume that card is present */
+ host->present = 1;
+
init_timer(&host->timer);
host->timer.data = (unsigned long)host;
host->timer.function = imxmci_check_status;
@@ -1073,7 +1053,7 @@ out:
}
if (mmc)
mmc_free_host(mmc);
- release_resource(r);
+ release_mem_region(r->start, 0x100);
return ret;
}
@@ -1102,7 +1082,7 @@ static int imxmci_remove(struct platform_device *pdev)
clk_disable(host->clk);
clk_put(host->clk);
- release_resource(host->res);
+ release_mem_region(host->res->start, 0x100);
mmc_free_host(mmc);
}
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 41cc63360e4..7503b81374e 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -1076,6 +1076,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
*/
if (canpower && ios->power_mode == MMC_POWER_OFF) {
int mres;
+ u8 nullbyte = 0;
host->spi->mode &= ~(SPI_CPOL|SPI_CPHA);
mres = spi_setup(host->spi);
@@ -1083,7 +1084,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
dev_dbg(&host->spi->dev,
"switch to SPI mode 0 failed\n");
- if (spi_w8r8(host->spi, 0x00) < 0)
+ if (spi_write(host->spi, &nullbyte, 1) < 0)
dev_dbg(&host->spi->dev,
"put spi signals to low failed\n");