From: Russell King <rmk+lkml@arm.linux.org.uk>
To: Linux Kernel List <linux-kernel@vger.kernel.org>
Subject: Re: [RFC] 3/4 MMC layer: ARM MMCI driver
Date: Thu, 29 Apr 2004 13:50:41 +0100 [thread overview]
Message-ID: <20040429135041.E16407@flint.arm.linux.org.uk> (raw)
In-Reply-To: <20040429134925.D16407@flint.arm.linux.org.uk>; from rmk+lkml@arm.linux.org.uk on Thu, Apr 29, 2004 at 01:49:25PM +0100
This patch adds initial support for the ARM MMCI Primecell - one of
the drivers for a MMC interface.
diff -urpN orig/drivers/mmc/Kconfig linux/drivers/mmc/Kconfig
--- orig/drivers/mmc/Kconfig Fri Oct 17 17:41:27 2003
+++ linux/drivers/mmc/Kconfig Fri Oct 17 17:41:28 2003
@@ -29,4 +29,14 @@
mount the filesystem. Almost everyone wishing MMC support
should say Y or M here.
+config MMC_ARMMMCI
+ tristate "ARM AMBA Multimedia Card Interface support"
+ depends on ARM_AMBA && MMC
+ help
+ This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
+ Interface (PL180 and PL181) support. If you have an ARM(R)
+ platform with a Multimedia Card slot, say Y or M here.
+
+ If unsure, say N.
+
endmenu
diff -urpN orig/drivers/mmc/Makefile linux/drivers/mmc/Makefile
--- orig/drivers/mmc/Makefile Mon Jul 7 21:52:01 2003
+++ linux/drivers/mmc/Makefile Mon Jul 7 21:52:02 2003
@@ -15,5 +15,6 @@
#
# Host drivers
#
+obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
diff -urpN orig/drivers/mmc/mmci.c linux/drivers/mmc/mmci.c
--- orig/drivers/mmc/mmci.c Thu Jan 1 01:00:00 1970
+++ linux/drivers/mmc/mmci.c Thu Mar 4 23:38:29 2004
@@ -0,0 +1,523 @@
+/*
+ * linux/drivers/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver
+ *
+ * Copyright (C) 2003 Deep Blue Solutions, Ltd, 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
+ * published by the Free Software Foundation.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware/amba.h>
+#include <asm/mach/mmc.h>
+
+#include "mmci.h"
+
+#define DRIVER_NAME "mmci-pl18x"
+
+#ifdef CONFIG_MMC_DEBUG
+#define DBG(x...) pr_debug(x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
+static unsigned int fmax = 515633;
+
+static void
+mmci_request_end(struct mmci_host *host, struct mmc_request *req)
+{
+ writel(0, host->base + MMCICOMMAND);
+ host->req = NULL;
+ host->cmd = NULL;
+ host->data = NULL;
+ host->buffer = NULL;
+
+ if (req->data)
+ req->data->bytes_xfered = host->data_xfered;
+
+ /*
+ * Need to drop the host lock here; mmc_request_done may call
+ * back into the driver...
+ */
+ spin_unlock(&host->lock);
+ mmc_request_done(host->mmc, req);
+ spin_lock(&host->lock);
+}
+
+static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
+{
+ unsigned int datactrl;
+
+ DBG("%s: data: blksz %04x blks %04x flags %08x\n",
+ host->mmc->host_name, 1 << data->blksz_bits, data->blocks,
+ data->flags);
+
+ datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4;
+
+ if (data->flags & MMC_DATA_READ)
+ datactrl |= MCI_DPSM_DIRECTION;
+
+ host->data = data;
+ host->buffer = data->rq->buffer;
+ host->size = data->blocks << data->blksz_bits;
+ host->data_xfered = 0;
+
+ writel(0x800000, host->base + MMCIDATATIMER);
+ writel(host->size, host->base + MMCIDATALENGTH);
+ writel(datactrl, host->base + MMCIDATACTRL);
+}
+
+static void
+mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
+{
+ DBG("%s: cmd: op %02x arg %08x flags %08x\n",
+ host->mmc->host_name, cmd->opcode, cmd->arg, cmd->flags);
+
+ if (readl(host->base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
+ writel(0, host->base + MMCICOMMAND);
+ udelay(1);
+ }
+
+ c |= cmd->opcode | MCI_CPSM_ENABLE;
+ switch (cmd->flags & MMC_RSP_MASK) {
+ case MMC_RSP_NONE:
+ default:
+ break;
+ case MMC_RSP_LONG:
+ c |= MCI_CPSM_LONGRSP;
+ case MMC_RSP_SHORT:
+ c |= MCI_CPSM_RESPONSE;
+ break;
+ }
+ if (/*interrupt*/0)
+ c |= MCI_CPSM_INTERRUPT;
+
+ host->cmd = cmd;
+
+ writel(cmd->arg, host->base + MMCIARGUMENT);
+ writel(c, host->base + MMCICOMMAND);
+}
+
+static void
+mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
+ unsigned int status)
+{
+ if (status & MCI_DATABLOCKEND) {
+ host->data_xfered += 1 << data->blksz_bits;
+ }
+ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+ if (status & MCI_DATACRCFAIL)
+ data->error = MMC_ERR_BADCRC;
+ else if (status & MCI_DATATIMEOUT)
+ data->error = MMC_ERR_TIMEOUT;
+ else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
+ data->error = MMC_ERR_FIFO;
+ status |= MCI_DATAEND;
+ }
+ if (status & MCI_DATAEND) {
+ host->data = NULL;
+ if (!data->stop) {
+ mmci_request_end(host, data->req);
+ } else /*if (readl(host->base + MMCIDATACNT) > 6)*/ {
+ mmci_start_command(host, data->stop, 0);
+ }
+ }
+}
+
+static void
+mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
+ unsigned int status)
+{
+ host->cmd = NULL;
+
+ cmd->resp[0] = readl(host->base + MMCIRESPONSE0);
+ cmd->resp[1] = readl(host->base + MMCIRESPONSE1);
+ cmd->resp[2] = readl(host->base + MMCIRESPONSE2);
+ cmd->resp[3] = readl(host->base + MMCIRESPONSE3);
+
+ if (status & MCI_CMDTIMEOUT) {
+ cmd->error = MMC_ERR_TIMEOUT;
+ } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
+ cmd->error = MMC_ERR_BADCRC;
+ }
+
+ if (!cmd->data || cmd->error != MMC_ERR_NONE) {
+ mmci_request_end(host, cmd->req);
+ } else if (!(cmd->data->flags & MMC_DATA_READ)) {
+ mmci_start_data(host, cmd->data);
+ }
+}
+
+static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct mmci_host *host = dev_id;
+ u32 status;
+ int ret = 0;
+
+ do {
+ status = readl(host->base + MMCISTATUS);
+
+ if (!(status & (MCI_RXDATAAVLBL|MCI_RXFIFOHALFFULL|
+ MCI_TXFIFOEMPTY|MCI_TXFIFOHALFEMPTY)))
+ break;
+
+ DBG("%s: irq1 %08x\n", host->mmc->host_name, status);
+
+ if (status & (MCI_RXDATAAVLBL|MCI_RXFIFOHALFFULL)) {
+ int count = host->size - (readl(host->base + MMCIFIFOCNT) << 2);
+ if (count < 0)
+ count = 0;
+ if (count && host->buffer) {
+ readsl(host->base + MMCIFIFO, host->buffer, count >> 2);
+ host->buffer += count;
+ host->size -= count;
+ if (host->size == 0)
+ host->buffer = NULL;
+ } else {
+ static int first = 1;
+ if (first) {
+ first = 0;
+ printk(KERN_ERR "MMCI: sinking excessive data\n");
+ }
+ readl(host->base + MMCIFIFO);
+ }
+ }
+ if (status & (MCI_TXFIFOEMPTY|MCI_TXFIFOHALFEMPTY)) {
+ int count = host->size;
+ if (count > MCI_FIFOHALFSIZE)
+ count = MCI_FIFOHALFSIZE;
+ if (count && host->buffer) {
+ writesl(host->base + MMCIFIFO, host->buffer, count >> 2);
+ host->buffer += count;
+ host->size -= count;
+ if (host->size == 0)
+ host->buffer = NULL;
+ } else {
+ static int first = 1;
+ if (first) {
+ first = 0;
+ printk(KERN_ERR "MMCI: ran out of source data\n");
+ }
+ }
+ }
+ ret = 1;
+ } while (status);
+
+ return IRQ_RETVAL(ret);
+}
+
+static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct mmci_host *host = dev_id;
+ u32 status;
+ int ret = 0;
+
+ spin_lock(&host->lock);
+
+ do {
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+
+ status = readl(host->base + MMCISTATUS);
+ writel(status, host->base + MMCICLEAR);
+
+ if (!(status & MCI_IRQMASK))
+ break;
+
+ DBG("%s: irq0 %08x\n", host->mmc->host_name, status);
+
+ data = host->data;
+ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
+ MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND))
+ mmci_data_irq(host, data, status);
+
+ cmd = host->cmd;
+ if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
+ mmci_cmd_irq(host, cmd, status);
+
+ ret = 1;
+ } while (status);
+
+ spin_unlock(&host->lock);
+
+ return IRQ_RETVAL(ret);
+}
+
+static void mmci_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+ struct mmci_host *host = mmc_priv(mmc);
+
+ WARN_ON(host->req != NULL);
+
+ spin_lock_irq(&host->lock);
+
+ host->req = req;
+
+ if (req->data && req->data->flags & MMC_DATA_READ)
+ mmci_start_data(host, req->data);
+
+ mmci_start_command(host, req->cmd, 0);
+
+ spin_unlock_irq(&host->lock);
+}
+
+static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct mmci_host *host = mmc_priv(mmc);
+ u32 clk = 0, pwr = 0;
+
+ DBG("%s: set_ios: clock %dHz busmode %d powermode %d Vdd %d.%02d\n",
+ mmc->host_name, ios->clock, ios->bus_mode, ios->power_mode,
+ ios->vdd / 100, ios->vdd % 100);
+
+ if (ios->clock) {
+ clk = host->mclk / (2 * ios->clock) - 1;
+ if (clk > 256)
+ clk = 255;
+ clk |= MCI_CLK_ENABLE;
+ }
+
+ if (host->plat->translate_vdd)
+ pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
+
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ break;
+ case MMC_POWER_UP:
+ pwr |= MCI_PWR_UP;
+ break;
+ case MMC_POWER_ON:
+ pwr |= MCI_PWR_ON;
+ break;
+ }
+
+ if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+ pwr |= MCI_ROD;
+
+ writel(clk, host->base + MMCICLOCK);
+
+ if (host->pwr != pwr) {
+ host->pwr = pwr;
+ writel(pwr, host->base + MMCIPOWER);
+ }
+}
+
+static struct mmc_host_ops mmci_ops = {
+ .request = mmci_request,
+ .set_ios = mmci_set_ios,
+};
+
+static void mmci_check_status(unsigned long data)
+{
+ struct mmci_host *host = (struct mmci_host *)data;
+ unsigned int status;
+
+ status = host->plat->status(mmc_dev(host->mmc));
+ if (status ^ host->oldstat)
+ mmc_detect_change(host->mmc);
+
+ host->oldstat = status;
+ mod_timer(&host->timer, jiffies + HZ);
+}
+
+static int mmci_probe(struct amba_device *dev, void *id)
+{
+ struct mmc_platform_data *plat = dev->dev.platform_data;
+ struct mmci_host *host = NULL;
+ struct mmc_host *mmc;
+ int ret;
+
+ /* must have platform data */
+ if (!plat)
+ return -EINVAL;
+
+ ret = amba_request_regions(dev, DRIVER_NAME);
+ if (ret)
+ return ret;
+
+ mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
+ if (!mmc) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mmc->ops = &mmci_ops;
+ mmc->f_min = (plat->mclk + 511) / 512;
+ mmc->f_max = max(plat->mclk / 2, fmax);
+ mmc->ocr_avail = plat->ocr_mask;
+
+ host = mmc_priv(mmc);
+ host->plat = plat;
+ host->mclk = plat->mclk;
+ host->mmc = mmc;
+ host->base = ioremap(dev->res.start, SZ_4K);
+ if (!host->base) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ spin_lock_init(&host->lock);
+
+ writel(0, host->base + MMCIMASK0);
+ writel(0, host->base + MMCIMASK1);
+ writel(0xfff, host->base + MMCICLEAR);
+
+ ret = request_irq(dev->irq[0], mmci_irq, SA_SHIRQ, DRIVER_NAME " (cmd)", host);
+ if (ret)
+ goto out;
+
+ ret = request_irq(dev->irq[1], mmci_pio_irq, SA_SHIRQ, DRIVER_NAME " (pio)", host);
+ if (ret) {
+ free_irq(dev->irq[0], host);
+ goto out;
+ }
+
+ writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+ writel(MCI_TXFIFOHALFEMPTYMASK|MCI_RXFIFOHALFFULLMASK, host->base + MMCIMASK1);
+
+ amba_set_drvdata(dev, mmc);
+
+ mmc_add_host(mmc);
+
+ printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%08lx irq %d,%d\n",
+ mmc->host_name, amba_rev(dev), amba_config(dev),
+ dev->res.start, dev->irq[0], dev->irq[1]);
+
+ init_timer(&host->timer);
+ host->timer.data = (unsigned long)host;
+ host->timer.function = mmci_check_status;
+ host->timer.expires = jiffies + HZ;
+ add_timer(&host->timer);
+
+ return 0;
+
+ out:
+ if (host && host->base)
+ iounmap(host->base);
+ if (mmc)
+ mmc_free_host(mmc);
+ amba_release_regions(dev);
+ return ret;
+}
+
+static int mmci_remove(struct amba_device *dev)
+{
+ struct mmc_host *mmc = amba_get_drvdata(dev);
+
+ amba_set_drvdata(dev, NULL);
+
+ if (mmc) {
+ struct mmci_host *host = mmc_priv(mmc);
+
+ del_timer_sync(&host->timer);
+
+ mmc_remove_host(mmc);
+
+ writel(0, host->base + MMCIMASK0);
+ writel(0, host->base + MMCIMASK1);
+
+ writel(0, host->base + MMCICOMMAND);
+ writel(0, host->base + MMCIDATACTRL);
+
+ free_irq(dev->irq[0], host);
+ free_irq(dev->irq[1], host);
+
+ iounmap(host->base);
+
+ mmc_free_host(mmc);
+
+ amba_release_regions(dev);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mmci_suspend(struct amba_device *dev, u32 state)
+{
+ struct mmc_host *mmc = amba_get_drvdata(dev);
+ int ret = 0;
+
+ if (mmc) {
+ struct mmci_host *host = mmc_priv(mmc);
+
+ ret = mmc_suspend_host(mmc, state);
+ if (ret == 0)
+ writel(0, host->base + MMCIMASK0);
+ }
+
+ return ret;
+}
+
+static int mmci_resume(struct amba_device *dev)
+{
+ struct mmc_host *mmc = amba_get_drvdata(dev);
+ int ret = 0;
+
+ if (mmc) {
+ struct mmci_host *host = mmc_priv(mmc);
+
+ writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+
+ ret = mmc_resume_host(mmc);
+ }
+
+ return ret;
+}
+#else
+#define mmci_suspend NULL
+#define mmci_resume NULL
+#endif
+
+static struct amba_id mmci_ids[] = {
+ {
+ .id = 0x00041180,
+ .mask = 0x000fffff,
+ },
+ {
+ .id = 0x00041181,
+ .mask = 0x000fffff,
+ },
+ { 0, 0 },
+};
+
+static struct amba_driver mmci_driver = {
+ .drv = {
+ .name = DRIVER_NAME,
+ },
+ .probe = mmci_probe,
+ .remove = mmci_remove,
+ .suspend = mmci_suspend,
+ .resume = mmci_resume,
+ .id_table = mmci_ids,
+};
+
+static int __init mmci_init(void)
+{
+ return amba_driver_register(&mmci_driver);
+}
+
+static void __exit mmci_exit(void)
+{
+ amba_driver_unregister(&mmci_driver);
+}
+
+module_init(mmci_init);
+module_exit(mmci_exit);
+module_param(fmax, uint, 0444);
+
+MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");
+MODULE_LICENSE("GPL");
diff -urpN orig/drivers/mmc/mmci.h linux/drivers/mmc/mmci.h
--- orig/drivers/mmc/mmci.h Thu Jan 1 01:00:00 1970
+++ linux/drivers/mmc/mmci.h Wed Dec 31 22:58:09 2003
@@ -0,0 +1,149 @@
+/*
+ * linux/drivers/mmc/mmci.h - ARM PrimeCell MMCI PL180/1 driver
+ *
+ * Copyright (C) 2003 Deep Blue Solutions, Ltd, 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
+ * published by the Free Software Foundation.
+ */
+#define MMCIPOWER 0x000
+#define MCI_PWR_OFF 0x00
+#define MCI_PWR_UP 0x02
+#define MCI_PWR_ON 0x03
+#define MCI_OD (1 << 6)
+#define MCI_ROD (1 << 7)
+
+#define MMCICLOCK 0x004
+#define MCI_CLK_ENABLE (1 << 8)
+#define MCI_PWRSAVE (1 << 9)
+#define MCI_BYPASS (1 << 10)
+
+#define MMCIARGUMENT 0x008
+#define MMCICOMMAND 0x00c
+#define MCI_CPSM_RESPONSE (1 << 6)
+#define MCI_CPSM_LONGRSP (1 << 7)
+#define MCI_CPSM_INTERRUPT (1 << 8)
+#define MCI_CPSM_PENDING (1 << 9)
+#define MCI_CPSM_ENABLE (1 << 10)
+
+#define MMCIRESPCMD 0x010
+#define MMCIRESPONSE0 0x014
+#define MMCIRESPONSE1 0x018
+#define MMCIRESPONSE2 0x01c
+#define MMCIRESPONSE3 0x020
+#define MMCIDATATIMER 0x024
+#define MMCIDATALENGTH 0x028
+#define MMCIDATACTRL 0x02c
+#define MCI_DPSM_ENABLE (1 << 0)
+#define MCI_DPSM_DIRECTION (1 << 1)
+#define MCI_DPSM_MODE (1 << 2)
+#define MCI_DPSM_DMAENABLE (1 << 3)
+
+#define MMCIDATACNT 0x030
+#define MMCISTATUS 0x034
+#define MCI_CMDCRCFAIL (1 << 0)
+#define MCI_DATACRCFAIL (1 << 1)
+#define MCI_CMDTIMEOUT (1 << 2)
+#define MCI_DATATIMEOUT (1 << 3)
+#define MCI_TXUNDERRUN (1 << 4)
+#define MCI_RXOVERRUN (1 << 5)
+#define MCI_CMDRESPEND (1 << 6)
+#define MCI_CMDSENT (1 << 7)
+#define MCI_DATAEND (1 << 8)
+#define MCI_DATABLOCKEND (1 << 10)
+#define MCI_CMDACTIVE (1 << 11)
+#define MCI_TXACTIVE (1 << 12)
+#define MCI_RXACTIVE (1 << 13)
+#define MCI_TXFIFOHALFEMPTY (1 << 14)
+#define MCI_RXFIFOHALFFULL (1 << 15)
+#define MCI_TXFIFOFULL (1 << 16)
+#define MCI_RXFIFOFULL (1 << 17)
+#define MCI_TXFIFOEMPTY (1 << 18)
+#define MCI_RXFIFOEMPTY (1 << 19)
+#define MCI_TXDATAAVLBL (1 << 20)
+#define MCI_RXDATAAVLBL (1 << 21)
+
+#define MMCICLEAR 0x038
+#define MCI_CMDCRCFAILCLR (1 << 0)
+#define MCI_DATACRCFAILCLR (1 << 1)
+#define MCI_CMDTIMEOUTCLR (1 << 2)
+#define MCI_DATATIMEOUTCLR (1 << 3)
+#define MCI_TXUNDERRUNCLR (1 << 4)
+#define MCI_RXOVERRUNCLR (1 << 5)
+#define MCI_CMDRESPENDCLR (1 << 6)
+#define MCI_CMDSENTCLR (1 << 7)
+#define MCI_DATAENDCLR (1 << 8)
+#define MCI_DATABLOCKENDCLR (1 << 10)
+
+#define MMCIMASK0 0x03c
+#define MCI_CMDCRCFAILMASK (1 << 0)
+#define MCI_DATACRCFAILMASK (1 << 1)
+#define MCI_CMDTIMEOUTMASK (1 << 2)
+#define MCI_DATATIMEOUTMASK (1 << 3)
+#define MCI_TXUNDERRUNMASK (1 << 4)
+#define MCI_RXOVERRUNMASK (1 << 5)
+#define MCI_CMDRESPENDMASK (1 << 6)
+#define MCI_CMDSENTMASK (1 << 7)
+#define MCI_DATAENDMASK (1 << 8)
+#define MCI_DATABLOCKENDMASK (1 << 10)
+#define MCI_CMDACTIVEMASK (1 << 11)
+#define MCI_TXACTIVEMASK (1 << 12)
+#define MCI_RXACTIVEMASK (1 << 13)
+#define MCI_TXFIFOHALFEMPTYMASK (1 << 14)
+#define MCI_RXFIFOHALFFULLMASK (1 << 15)
+#define MCI_TXFIFOFULLMASK (1 << 16)
+#define MCI_RXFIFOFULLMASK (1 << 17)
+#define MCI_TXFIFOEMPTYMASK (1 << 18)
+#define MCI_RXFIFOEMPTYMASK (1 << 19)
+#define MCI_TXDATAAVLBLMASK (1 << 20)
+#define MCI_RXDATAAVLBLMASK (1 << 21)
+
+#define MMCIMASK1 0x040
+#define MMCIFIFOCNT 0x048
+#define MMCIFIFO 0x080 /* to 0x0bc */
+
+#define MCI_IRQMASK \
+ (MCI_CMDCRCFAIL|MCI_DATACRCFAIL|MCI_CMDTIMEOUT|MCI_DATATIMEOUT| \
+ MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_CMDRESPEND|MCI_CMDSENT| \
+ MCI_DATAEND|MCI_DATABLOCKEND)
+
+#define MCI_IRQENABLE \
+ (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \
+ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
+ MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK| \
+ MCI_DATABLOCKENDMASK)
+
+#define MCI_FIFOSIZE 16
+
+#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
+
+struct mmci_host {
+ void *base;
+ struct mmc_request *req;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ struct mmc_host *mmc;
+
+ unsigned int data_xfered;
+
+ spinlock_t lock;
+
+ unsigned int mclk;
+ u32 pwr;
+ struct mmc_platform_data *plat;
+
+ struct timer_list timer;
+ unsigned int oldstat;
+
+ /* pio stuff */
+ void *buffer;
+ unsigned int size;
+
+ /* dma stuff */
+// struct scatterlist *sg_list;
+// int sg_len;
+// int sg_dir;
+};
+
+#define to_mmci_host(mmc) container_of(mmc, struct mmci_host, mmc)
--- orig/include/asm-arm/mach/mmc.h Sat Apr 26 08:56:46 1997
+++ linux/include/asm-arm/mach/mmc.h Mon Dec 29 17:19:00 2003
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/mach/mmc.h
+ */
+#ifndef ASMARM_MACH_MMC_H
+#define ASMARM_MACH_MMC_H
+
+#include <linux/mmc/protocol.h>
+
+struct mmc_platform_data {
+ unsigned int mclk; /* mmc base clock rate */
+ unsigned int ocr_mask; /* available voltages */
+ u32 (*translate_vdd)(struct device *, unsigned int);
+ unsigned int (*status)(struct device *);
+};
+
+#endif
--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of: 2.6 PCMCIA - http://pcmcia.arm.linux.org.uk/
2.6 Serial core
next prev parent reply other threads:[~2004-04-29 12:53 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-04-29 12:48 [RFC] 1/4 MMC layer Russell King
2004-04-29 12:49 ` [RFC] 2/4 MMC layer: configuration + makefiles Russell King
2004-04-29 12:50 ` Russell King [this message]
2004-04-29 12:51 ` [RFC] 4/4 MMC layer: PXA MCI driver Russell King
2004-05-02 14:52 ` [RFC] 1/4 MMC layer Russell King
2004-05-03 13:47 ` Pavel Machek
2004-05-03 22:47 ` Russell King
2004-05-03 23:00 ` Pavel Machek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20040429135041.E16407@flint.arm.linux.org.uk \
--to=rmk+lkml@arm.linux.org.uk \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.