diff options
Diffstat (limited to 'packages/linux/linux-2.6.18/atmel-mmc-host-driver.patch')
-rw-r--r-- | packages/linux/linux-2.6.18/atmel-mmc-host-driver.patch | 986 |
1 files changed, 0 insertions, 986 deletions
diff --git a/packages/linux/linux-2.6.18/atmel-mmc-host-driver.patch b/packages/linux/linux-2.6.18/atmel-mmc-host-driver.patch deleted file mode 100644 index b7d7e8ae3f..0000000000 --- a/packages/linux/linux-2.6.18/atmel-mmc-host-driver.patch +++ /dev/null @@ -1,986 +0,0 @@ -From nobody Mon Sep 17 00:00:00 2001 -From: HÃ¥vard Skinnemoen <hskinnemoen@atmel.com> -Date: Fri Nov 18 17:20:29 2005 +0100 -Subject: [PATCH] AVR32: MMC Host Driver - ---- - - drivers/mmc/Kconfig | 10 - drivers/mmc/Makefile | 1 - drivers/mmc/atmel-mci.c | 738 ++++++++++++++++++++++++++++++++++++++++++++++++ - drivers/mmc/atmel-mci.h | 192 ++++++++++++ - 4 files changed, 941 insertions(+) - -Index: linux-2.6.18-avr32/drivers/mmc/Kconfig -=================================================================== ---- linux-2.6.18-avr32.orig/drivers/mmc/Kconfig 2007-01-15 10:14:40.000000000 +0100 -+++ linux-2.6.18-avr32/drivers/mmc/Kconfig 2007-01-15 10:14:46.000000000 +0100 -@@ -71,6 +71,16 @@ config MMC_OMAP - - If unsure, say N. - -+config MMC_ATMELMCI -+ tristate "Atmel Multimedia Card Interface support" -+ depends on AVR32 && MMC -+ help -+ This selects the Atmel Multimedia Card Interface. If you have -+ a AT91 (ARM) or AT32 (AVR32) platform with a Multimedia Card -+ slot, say Y or M here. -+ -+ If unsure, say N. -+ - config MMC_WBSD - tristate "Winbond W83L51xD SD/MMC Card Interface support" - depends on MMC && ISA_DMA_API -Index: linux-2.6.18-avr32/drivers/mmc/Makefile -=================================================================== ---- linux-2.6.18-avr32.orig/drivers/mmc/Makefile 2007-01-15 10:14:40.000000000 +0100 -+++ linux-2.6.18-avr32/drivers/mmc/Makefile 2007-01-15 10:14:46.000000000 +0100 -@@ -23,6 +23,7 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o - obj-$(CONFIG_MMC_AU1X) += au1xmmc.o - obj-$(CONFIG_MMC_OMAP) += omap.o - obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o -+obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o - - mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o - -Index: linux-2.6.18-avr32/drivers/mmc/atmel-mci.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.18-avr32/drivers/mmc/atmel-mci.c 2007-01-15 10:31:55.000000000 +0100 -@@ -0,0 +1,738 @@ -+/* -+ * Atmel MultiMedia Card Interface driver -+ * -+ * Copyright (C) 2004-2006 Atmel Corporation -+ * -+ * 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/blkdev.h> -+#include <linux/clk.h> -+#include <linux/device.h> -+#include <linux/dma-mapping.h> -+#include <linux/init.h> -+#include <linux/interrupt.h> -+#include <linux/ioport.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+ -+#include <linux/mmc/host.h> -+#include <linux/mmc/protocol.h> -+ -+#include <asm/dma-controller.h> -+#include <asm/io.h> -+ -+#include "atmel-mci.h" -+ -+#define DRIVER_NAME "mmci" -+ -+#define MCI_CMD_ERROR_FLAGS (MCI_BIT(RINDE) | MCI_BIT(RDIRE) | \ -+ MCI_BIT(RCRCE) | MCI_BIT(RENDE) | \ -+ MCI_BIT(RTOE)) -+#define MCI_DATA_ERROR_FLAGS (MCI_BIT(DCRCE) | MCI_BIT(DTOE) | \ -+ MCI_BIT(OVRE) | MCI_BIT(UNRE)) -+ -+enum { -+ EVENT_CMD_COMPLETE = 0, -+ EVENT_CMD_ERROR, -+ EVENT_DATA_COMPLETE, -+ EVENT_DATA_ERROR, -+ EVENT_STOP_SENT, -+ EVENT_STOP_COMPLETE, -+ EVENT_STOP_ERROR, -+ EVENT_DMA_ERROR, -+}; -+ -+struct atmel_mci_dma { -+ struct dma_request_sg req; -+ unsigned short rx_periph_id; -+ unsigned short tx_periph_id; -+ int blocks_left; -+}; -+ -+struct atmel_mci { -+ struct mmc_host *mmc; -+ void __iomem *regs; -+ struct atmel_mci_dma dma; -+ -+ struct mmc_request *mrq; -+ struct mmc_command *cmd; -+ struct mmc_data *data; -+ -+ u32 stop_cmdr; -+ u32 stop_iflags; -+ -+ struct tasklet_struct tasklet; -+ unsigned long pending_events; -+ unsigned long completed_events; -+ u32 error_status; -+ -+ unsigned long bus_hz; -+ unsigned long mapbase; -+ struct clk *mck; -+ struct platform_device *pdev; -+}; -+ -+/* Those printks take an awful lot of time... */ -+#ifndef DEBUG -+static unsigned int fmax = 15000000U; -+#else -+static unsigned int fmax = 1000000U; -+#endif -+module_param(fmax, uint, 0444); -+MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock"); -+ -+static inline unsigned int ns_to_clocks(struct atmel_mci *host, -+ unsigned int ns) -+{ -+ return (ns * (host->bus_hz / 1000000) + 999) / 1000; -+} -+ -+static void atmci_set_timeout(struct atmel_mci *host, -+ struct mmc_data *data) -+{ -+ static unsigned dtomul_to_shift[] = { -+ 0, 4, 7, 8, 10, 12, 16, 20 -+ }; -+ unsigned timeout; -+ unsigned dtocyc, dtomul; -+ -+ timeout = ns_to_clocks(host, data->timeout_ns) + data->timeout_clks; -+ -+ for (dtomul = 0; dtomul < 8; dtomul++) { -+ unsigned shift = dtomul_to_shift[dtomul]; -+ dtocyc = (timeout + (1 << shift) - 1) >> shift; -+ if (dtocyc < 15) -+ break; -+ } -+ -+ if (dtomul >= 8) { -+ dtomul = 7; -+ dtocyc = 15; -+ } -+ -+ pr_debug("%s: setting timeout to %u cycles\n", -+ mmc_hostname(host->mmc), -+ dtocyc << dtomul_to_shift[dtomul]); -+ mci_writel(host, DTOR, (MCI_BF(DTOMUL, dtomul) -+ | MCI_BF(DTOCYC, dtocyc))); -+} -+ -+/* -+ * Return mask with interrupt flags to be handled for this command. -+ */ -+static u32 atmci_prepare_command(struct mmc_host *mmc, -+ struct mmc_command *cmd, -+ u32 *cmd_flags) -+{ -+ u32 cmdr; -+ u32 iflags; -+ -+ cmd->error = MMC_ERR_NONE; -+ -+ cmdr = 0; -+ BUG_ON(MCI_BFEXT(CMDNB, cmdr) != 0); -+ cmdr = MCI_BFINS(CMDNB, cmd->opcode, cmdr); -+ -+ if (cmd->flags & MMC_RSP_PRESENT) { -+ if (cmd->flags & MMC_RSP_136) -+ cmdr |= MCI_BF(RSPTYP, MCI_RSPTYP_136_BIT); -+ else -+ cmdr |= MCI_BF(RSPTYP, MCI_RSPTYP_48_BIT); -+ } -+ -+ /* -+ * This should really be MAXLAT_5 for CMD2 and ACMD41, but -+ * it's too difficult to determine whether this is an ACMD or -+ * not. Better make it 64. -+ */ -+ cmdr |= MCI_BIT(MAXLAT); -+ -+ if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN) -+ cmdr |= MCI_BIT(OPDCMD); -+ -+ iflags = MCI_BIT(CMDRDY) | MCI_CMD_ERROR_FLAGS; -+ if (!(cmd->flags & MMC_RSP_CRC)) -+ iflags &= ~MCI_BIT(RCRCE); -+ -+ pr_debug("%s: cmd: op %02x arg %08x flags %08x, cmdflags %08lx\n", -+ mmc_hostname(mmc), cmd->opcode, cmd->arg, cmd->flags, -+ (unsigned long)cmdr); -+ -+ *cmd_flags = cmdr; -+ return iflags; -+} -+ -+static void atmci_start_command(struct atmel_mci *host, -+ struct mmc_command *cmd, -+ u32 cmd_flags) -+{ -+ WARN_ON(host->cmd); -+ host->cmd = cmd; -+ -+ mci_writel(host, ARGR, cmd->arg); -+ mci_writel(host, CMDR, cmd_flags); -+ -+ if (cmd->data) -+ dma_start_request(host->dma.req.req.dmac, -+ host->dma.req.req.channel); -+} -+ -+/* -+ * Returns a mask of flags to be set in the command register when the -+ * command to start the transfer is to be sent. -+ */ -+static u32 atmci_prepare_data(struct mmc_host *mmc, struct mmc_data *data) -+{ -+ struct atmel_mci *host = mmc_priv(mmc); -+ u32 cmd_flags; -+ -+ WARN_ON(host->data); -+ host->data = data; -+ -+ atmci_set_timeout(host, data); -+ mci_writel(host, BLKR, (MCI_BF(BCNT, data->blocks) -+ | MCI_BF(BLKLEN, data->blksz))); -+ host->dma.req.block_size = data->blksz; -+ -+ cmd_flags = MCI_BF(TRCMD, MCI_TRCMD_START_TRANS); -+ if (data->flags & MMC_DATA_STREAM) -+ cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_STREAM); -+ else if (data->blocks > 1) -+ cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_MULTI_BLOCK); -+ else -+ cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_BLOCK); -+ -+ if (data->flags & MMC_DATA_READ) { -+ cmd_flags |= MCI_BIT(TRDIR); -+ host->dma.req.nr_sg -+ = dma_map_sg(&host->pdev->dev, data->sg, -+ data->sg_len, DMA_FROM_DEVICE); -+ host->dma.req.periph_id = host->dma.rx_periph_id; -+ host->dma.req.direction = DMA_DIR_PERIPH_TO_MEM; -+ host->dma.req.data_reg = host->mapbase + MCI_RDR; -+ } else { -+ host->dma.req.nr_sg -+ = dma_map_sg(&host->pdev->dev, data->sg, -+ data->sg_len, DMA_TO_DEVICE); -+ host->dma.req.periph_id = host->dma.tx_periph_id; -+ host->dma.req.direction = DMA_DIR_MEM_TO_PERIPH; -+ host->dma.req.data_reg = host->mapbase + MCI_TDR; -+ } -+ host->dma.req.sg = data->sg; -+ host->dma.blocks_left = data->blocks; -+ -+ dma_prepare_request_sg(host->dma.req.req.dmac, &host->dma.req); -+ -+ return cmd_flags; -+} -+ -+static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) -+{ -+ struct atmel_mci *host = mmc_priv(mmc); -+ struct mmc_data *data = mrq->data; -+ u32 iflags; -+ u32 cmdflags = 0; -+ -+ iflags = mci_readl(host, IMR); -+ if (iflags) -+ printk("WARNING: IMR=0x%08x\n", mci_readl(host, IMR)); -+ -+ WARN_ON(host->mrq != NULL); -+ host->mrq = mrq; -+ host->pending_events = 0; -+ host->completed_events = 0; -+ -+ iflags = atmci_prepare_command(mmc, mrq->cmd, &cmdflags); -+ -+ if (mrq->stop) { -+ BUG_ON(!data); -+ -+ host->stop_iflags = atmci_prepare_command(mmc, mrq->stop, -+ &host->stop_cmdr); -+ host->stop_cmdr |= MCI_BF(TRCMD, MCI_TRCMD_STOP_TRANS); -+ if (!(data->flags & MMC_DATA_WRITE)) -+ host->stop_cmdr |= MCI_BIT(TRDIR); -+ if (data->flags & MMC_DATA_STREAM) -+ host->stop_cmdr |= MCI_BF(TRTYP, MCI_TRTYP_STREAM); -+ else -+ host->stop_cmdr |= MCI_BF(TRTYP, MCI_TRTYP_MULTI_BLOCK); -+ } -+ if (data) { -+ cmdflags |= atmci_prepare_data(mmc, data); -+ iflags |= MCI_DATA_ERROR_FLAGS; -+ } -+ -+ atmci_start_command(host, mrq->cmd, cmdflags); -+ mci_writel(host, IER, iflags); -+} -+ -+static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -+{ -+ struct atmel_mci *host = mmc_priv(mmc); -+ -+ if (ios->clock) { -+ u32 clkdiv; -+ -+ clkdiv = host->bus_hz / (2 * ios->clock) - 1; -+ if (clkdiv > 255) -+ clkdiv = 255; -+ mci_writel(host, MR, (clkdiv -+ | MCI_BIT(WRPROOF) -+ | MCI_BIT(RDPROOF))); -+ } -+ -+ switch (ios->bus_width) { -+ case MMC_BUS_WIDTH_1: -+ mci_writel(host, SDCR, 0); -+ break; -+ case MMC_BUS_WIDTH_4: -+ mci_writel(host, SDCR, MCI_BIT(SDCBUS)); -+ break; -+ } -+ -+ switch (ios->power_mode) { -+ case MMC_POWER_OFF: -+ mci_writel(host, CR, MCI_BIT(MCIDIS)); -+ break; -+ case MMC_POWER_UP: -+ mci_writel(host, CR, MCI_BIT(SWRST)); -+ break; -+ case MMC_POWER_ON: -+ mci_writel(host, CR, MCI_BIT(MCIEN)); -+ break; -+ } -+} -+ -+static struct mmc_host_ops atmci_ops = { -+ .request = atmci_request, -+ .set_ios = atmci_set_ios, -+}; -+ -+static void atmci_request_end(struct mmc_host *mmc, struct mmc_request *mrq) -+{ -+ struct atmel_mci *host = mmc_priv(mmc); -+ -+ WARN_ON(host->cmd || host->data); -+ host->mrq = NULL; -+ -+ mmc_request_done(mmc, mrq); -+} -+ -+static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data, -+ u32 flags) -+{ -+ struct atmel_mci *host = mmc_priv(mmc); -+ -+ atmci_start_command(host, data->stop, host->stop_cmdr | flags); -+ mci_writel(host, IER, host->stop_iflags); -+} -+ -+static void atmci_data_complete(struct atmel_mci *host, struct mmc_data *data) -+{ -+ host->data = NULL; -+ dma_unmap_sg(&host->pdev->dev, data->sg, host->dma.req.nr_sg, -+ ((data->flags & MMC_DATA_WRITE) -+ ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); -+ -+ /* -+ * Data might complete before command for very short transfers -+ * (like READ_SCR) -+ */ -+ if (test_bit(EVENT_CMD_COMPLETE, &host->completed_events) -+ && (!data->stop -+ || test_bit(EVENT_STOP_COMPLETE, &host->completed_events))) -+ atmci_request_end(host->mmc, data->mrq); -+} -+ -+static void atmci_command_error(struct mmc_host *mmc, -+ struct mmc_command *cmd, -+ u32 status) -+{ -+ pr_debug("%s: command error: status=0x%08x\n", -+ mmc_hostname(mmc), status); -+ -+ if (status & MCI_BIT(RTOE)) -+ cmd->error = MMC_ERR_TIMEOUT; -+ else if (status & MCI_BIT(RCRCE)) -+ cmd->error = MMC_ERR_BADCRC; -+ else -+ cmd->error = MMC_ERR_FAILED; -+} -+ -+static void atmci_tasklet_func(unsigned long priv) -+{ -+ struct mmc_host *mmc = (struct mmc_host *)priv; -+ struct atmel_mci *host = mmc_priv(mmc); -+ struct mmc_request *mrq = host->mrq; -+ struct mmc_data *data = host->data; -+ -+ pr_debug("atmci_tasklet: pending/completed/mask %lx/%lx/%x\n", -+ host->pending_events, host->completed_events, -+ mci_readl(host, IMR)); -+ -+ if (test_and_clear_bit(EVENT_CMD_ERROR, &host->pending_events)) { -+ struct mmc_command *cmd; -+ -+ set_bit(EVENT_CMD_ERROR, &host->completed_events); -+ clear_bit(EVENT_CMD_COMPLETE, &host->pending_events); -+ cmd = host->mrq->cmd; -+ -+ if (cmd->data) { -+ dma_stop_request(host->dma.req.req.dmac, -+ host->dma.req.req.channel); -+ host->data = NULL; -+ } -+ -+ atmci_command_error(mmc, cmd, host->error_status); -+ atmci_request_end(mmc, cmd->mrq); -+ } -+ if (test_and_clear_bit(EVENT_STOP_ERROR, &host->pending_events)) { -+ set_bit(EVENT_STOP_ERROR, &host->completed_events); -+ clear_bit(EVENT_STOP_COMPLETE, &host->pending_events); -+ atmci_command_error(mmc, host->mrq->stop, -+ host->error_status); -+ if (!host->data) -+ atmci_request_end(mmc, host->mrq); -+ } -+ if (test_and_clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)) { -+ set_bit(EVENT_CMD_COMPLETE, &host->completed_events); -+ if (!mrq->data -+ || test_bit(EVENT_DATA_COMPLETE, &host->completed_events)) -+ atmci_request_end(mmc, mrq); -+ } -+ if (test_and_clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)) { -+ set_bit(EVENT_STOP_COMPLETE, &host->completed_events); -+ if (test_bit(EVENT_DATA_COMPLETE, &host->completed_events)) -+ atmci_request_end(mmc, mrq); -+ } -+ if (test_and_clear_bit(EVENT_DMA_ERROR, &host->pending_events)) { -+ set_bit(EVENT_DMA_ERROR, &host->completed_events); -+ clear_bit(EVENT_DATA_COMPLETE, &host->pending_events); -+ -+ /* DMA controller got bus error => invalid address */ -+ data->error = MMC_ERR_INVALID; -+ -+ printk(KERN_DEBUG "%s: dma error after %u bytes xfered\n", -+ mmc_hostname(mmc), host->data->bytes_xfered); -+ -+ if (data->stop -+ && !test_and_set_bit(EVENT_STOP_SENT, -+ &host->completed_events)) -+ /* TODO: Check if card is still present */ -+ send_stop_cmd(host->mmc, data, 0); -+ -+ atmci_data_complete(host, data); -+ } -+ if (test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)) { -+ u32 status = host->error_status; -+ -+ set_bit(EVENT_DATA_ERROR, &host->completed_events); -+ clear_bit(EVENT_DATA_COMPLETE, &host->pending_events); -+ -+ dma_stop_request(host->dma.req.req.dmac, -+ host->dma.req.req.channel); -+ -+ printk(KERN_DEBUG "%s: data error: status=0x%08x\n", -+ mmc_hostname(host->mmc), status); -+ -+ if (status & MCI_BIT(DCRCE)) { -+ printk(KERN_DEBUG "%s: Data CRC error\n", -+ mmc_hostname(host->mmc)); -+ data->error = MMC_ERR_BADCRC; -+ } else if (status & MCI_BIT(DTOE)) { -+ printk(KERN_DEBUG "%s: Data Timeout error\n", -+ mmc_hostname(host->mmc)); -+ data->error = MMC_ERR_TIMEOUT; -+ } else { -+ printk(KERN_DEBUG "%s: Data FIFO error\n", -+ mmc_hostname(host->mmc)); -+ data->error = MMC_ERR_FIFO; -+ } -+ printk(KERN_DEBUG "%s: Bytes xfered: %u\n", -+ mmc_hostname(host->mmc), data->bytes_xfered); -+ -+ if (data->stop -+ && !test_and_set_bit(EVENT_STOP_SENT, &host->completed_events)) -+ /* TODO: Check if card is still present */ -+ send_stop_cmd(host->mmc, data, 0); -+ -+ atmci_data_complete(host, data); -+ } -+ if (test_and_clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)) { -+ set_bit(EVENT_DATA_COMPLETE, &host->completed_events); -+ data->bytes_xfered = data->blocks * data->blksz; -+ atmci_data_complete(host, data); -+ } -+} -+ -+static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status) -+{ -+ struct atmel_mci *host = mmc_priv(mmc); -+ struct mmc_command *cmd = host->cmd; -+ -+ /* -+ * Read the response now so that we're free to send a new -+ * command immediately. -+ */ -+ cmd->resp[0] = mci_readl(host, RSPR); -+ cmd->resp[1] = mci_readl(host, RSPR); -+ cmd->resp[2] = mci_readl(host, RSPR); -+ cmd->resp[3] = mci_readl(host, RSPR); -+ -+ mci_writel(host, IDR, MCI_BIT(CMDRDY) | MCI_CMD_ERROR_FLAGS); -+ host->cmd = NULL; -+ -+ if (test_bit(EVENT_STOP_SENT, &host->completed_events)) -+ set_bit(EVENT_STOP_COMPLETE, &host->pending_events); -+ else -+ set_bit(EVENT_CMD_COMPLETE, &host->pending_events); -+ -+ tasklet_schedule(&host->tasklet); -+} -+ -+static void atmci_xfer_complete(struct dma_request *_req) -+{ -+ struct dma_request_sg *req = to_dma_request_sg(_req); -+ struct atmel_mci_dma *dma; -+ struct atmel_mci *host; -+ struct mmc_data *data; -+ -+ dma = container_of(req, struct atmel_mci_dma, req); -+ host = container_of(dma, struct atmel_mci, dma); -+ data = host->data; -+ -+ if (data->stop && !test_and_set_bit(EVENT_STOP_SENT, -+ &host->completed_events)) -+ send_stop_cmd(host->mmc, data, 0); -+ -+ if (data->flags & MMC_DATA_READ) { -+ mci_writel(host, IDR, MCI_DATA_ERROR_FLAGS); -+ set_bit(EVENT_DATA_COMPLETE, &host->pending_events); -+ tasklet_schedule(&host->tasklet); -+ } else { -+ /* -+ * For the WRITE case, wait for NOTBUSY. This function -+ * is called when everything has been written to the -+ * controller, not when the card is done programming. -+ */ -+ mci_writel(host, IER, MCI_BIT(NOTBUSY)); -+ } -+} -+ -+static void atmci_dma_error(struct dma_request *_req) -+{ -+ struct dma_request_sg *req = to_dma_request_sg(_req); -+ struct atmel_mci_dma *dma; -+ struct atmel_mci *host; -+ -+ dma = container_of(req, struct atmel_mci_dma, req); -+ host = container_of(dma, struct atmel_mci, dma); -+ -+ mci_writel(host, IDR, (MCI_BIT(NOTBUSY) -+ | MCI_DATA_ERROR_FLAGS)); -+ -+ set_bit(EVENT_DMA_ERROR, &host->pending_events); -+ tasklet_schedule(&host->tasklet); -+} -+ -+static irqreturn_t atmci_interrupt(int irq, void *dev_id, -+ struct pt_regs *regs) -+{ -+ struct mmc_host *mmc = dev_id; -+ struct atmel_mci *host = mmc_priv(mmc); -+ u32 status, mask, pending; -+ -+ spin_lock(&mmc->lock); -+ -+ status = mci_readl(host, SR); -+ mask = mci_readl(host, IMR); -+ pending = status & mask; -+ -+ do { -+ if (pending & MCI_CMD_ERROR_FLAGS) { -+ mci_writel(host, IDR, (MCI_BIT(CMDRDY) -+ | MCI_BIT(NOTBUSY) -+ | MCI_CMD_ERROR_FLAGS -+ | MCI_DATA_ERROR_FLAGS)); -+ host->error_status = status; -+ host->cmd = NULL; -+ if (test_bit(EVENT_STOP_SENT, &host->completed_events)) -+ set_bit(EVENT_STOP_ERROR, &host->pending_events); -+ else -+ set_bit(EVENT_CMD_ERROR, &host->pending_events); -+ tasklet_schedule(&host->tasklet); -+ break; -+ } -+ if (pending & MCI_DATA_ERROR_FLAGS) { -+ mci_writel(host, IDR, (MCI_BIT(NOTBUSY) -+ | MCI_DATA_ERROR_FLAGS)); -+ host->error_status = status; -+ set_bit(EVENT_DATA_ERROR, &host->pending_events); -+ tasklet_schedule(&host->tasklet); -+ break; -+ } -+ if (pending & MCI_BIT(CMDRDY)) -+ atmci_cmd_interrupt(mmc, status); -+ if (pending & MCI_BIT(NOTBUSY)) { -+ mci_writel(host, IDR, (MCI_BIT(NOTBUSY) -+ | MCI_DATA_ERROR_FLAGS)); -+ set_bit(EVENT_DATA_COMPLETE, &host->pending_events); -+ tasklet_schedule(&host->tasklet); -+ } -+ -+ status = mci_readl(host, SR); -+ mask = mci_readl(host, IMR); -+ pending = status & mask; -+ } while (pending); -+ -+ spin_unlock(&mmc->lock); -+ -+ return IRQ_HANDLED; -+} -+ -+static int __devinit atmci_probe(struct platform_device *pdev) -+{ -+ struct atmel_mci *host; -+ struct mmc_host *mmc; -+ struct resource *regs; -+ int irq; -+ int ret; -+ -+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!regs) -+ return -ENXIO; -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) -+ return irq; -+ -+ mmc = mmc_alloc_host(sizeof(struct atmel_mci), &pdev->dev); -+ if (!mmc) -+ return -ENOMEM; -+ -+ host = mmc_priv(mmc); -+ host->pdev = pdev; -+ host->mmc = mmc; -+ -+ host->mck = clk_get(&pdev->dev, "mck"); -+ if (IS_ERR(host->mck)) { -+ ret = PTR_ERR(host->mck); -+ goto out_free_host; -+ } -+ clk_enable(host->mck); -+ -+ ret = -ENOMEM; -+ host->regs = ioremap(regs->start, regs->end - regs->start + 1); -+ if (!host->regs) -+ goto out_disable_clk; -+ -+ host->bus_hz = clk_get_rate(host->mck); -+ host->mapbase = regs->start; -+ -+ mmc->ops = &atmci_ops; -+ mmc->f_min = (host->bus_hz + 511) / 512; -+ mmc->f_max = min((unsigned int)(host->bus_hz / 2), fmax); -+ mmc->ocr_avail = 0x00100000; -+ mmc->caps |= MMC_CAP_4_BIT_DATA; -+ -+ tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)mmc); -+ -+ ret = request_irq(irq, atmci_interrupt, 0, "mmci", mmc); -+ if (ret) -+ goto out_unmap; -+ -+ /* TODO: Get this information from platform data */ -+ ret = -ENOMEM; -+ host->dma.req.req.dmac = find_dma_controller(0); -+ if (!host->dma.req.req.dmac) { -+ printk(KERN_ERR -+ "mmci: No DMA controller available, aborting\n"); -+ goto out_free_irq; -+ } -+ ret = dma_alloc_channel(host->dma.req.req.dmac); -+ if (ret < 0) { -+ printk(KERN_ERR -+ "mmci: Unable to allocate DMA channel, aborting\n"); -+ goto out_free_irq; -+ } -+ host->dma.req.req.channel = ret; -+ host->dma.req.width = DMA_WIDTH_32BIT; -+ host->dma.req.req.xfer_complete = atmci_xfer_complete; -+ host->dma.req.req.block_complete = NULL; // atmci_block_complete; -+ host->dma.req.req.error = atmci_dma_error; -+ host->dma.rx_periph_id = 0; -+ host->dma.tx_periph_id = 1; -+ -+ mci_writel(host, CR, MCI_BIT(SWRST)); -+ mci_writel(host, IDR, ~0UL); -+ mci_writel(host, CR, MCI_BIT(MCIEN)); -+ -+ platform_set_drvdata(pdev, host); -+ -+ mmc_add_host(mmc); -+ -+ printk(KERN_INFO "%s: Atmel MCI controller at 0x%08lx irq %d\n", -+ mmc_hostname(mmc), host->mapbase, irq); -+ -+ return 0; -+ -+out_free_irq: -+ free_irq(irq, mmc); -+out_unmap: -+ iounmap(host->regs); -+out_disable_clk: -+ clk_disable(host->mck); -+ clk_put(host->mck); -+out_free_host: -+ mmc_free_host(mmc); -+ return ret; -+} -+ -+static int __devexit atmci_remove(struct platform_device *pdev) -+{ -+ struct atmel_mci *host = platform_get_drvdata(pdev); -+ -+ platform_set_drvdata(pdev, NULL); -+ -+ if (host) { -+ mmc_remove_host(host->mmc); -+ -+ mci_writel(host, IDR, ~0UL); -+ mci_writel(host, CR, MCI_BIT(MCIDIS)); -+ mci_readl(host, SR); -+ -+ free_irq(platform_get_irq(pdev, 0), host->mmc); -+ iounmap(host->regs); -+ -+ clk_disable(host->mck); -+ clk_put(host->mck); -+ -+ mmc_free_host(host->mmc); -+ } -+ return 0; -+} -+ -+static struct platform_driver atmci_driver = { -+ .probe = atmci_probe, -+ .remove = __devexit_p(atmci_remove), -+ .driver = { -+ .name = DRIVER_NAME, -+ }, -+}; -+ -+static int __init atmci_init(void) -+{ -+ return platform_driver_register(&atmci_driver); -+} -+ -+static void __exit atmci_exit(void) -+{ -+ platform_driver_unregister(&atmci_driver); -+} -+ -+module_init(atmci_init); -+module_exit(atmci_exit); -+ -+MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); -+MODULE_LICENSE("GPL"); -Index: linux-2.6.18-avr32/drivers/mmc/atmel-mci.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.18-avr32/drivers/mmc/atmel-mci.h 2007-01-15 10:31:36.000000000 +0100 -@@ -0,0 +1,192 @@ -+/* -+ * Atmel MultiMedia Card Interface driver -+ * -+ * Copyright (C) 2004-2006 Atmel Corporation -+ * -+ * 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. -+ */ -+#ifndef __DRIVERS_MMC_ATMEL_MCI_H__ -+#define __DRIVERS_MMC_ATMEL_MCI_H__ -+ -+/* MCI register offsets */ -+#define MCI_CR 0x0000 -+#define MCI_MR 0x0004 -+#define MCI_DTOR 0x0008 -+#define MCI_SDCR 0x000c -+#define MCI_ARGR 0x0010 -+#define MCI_CMDR 0x0014 -+#define MCI_BLKR 0x0018 -+#define MCI_RSPR 0x0020 -+#define MCI_RSPR1 0x0024 -+#define MCI_RSPR2 0x0028 -+#define MCI_RSPR3 0x002c -+#define MCI_RDR 0x0030 -+#define MCI_TDR 0x0034 -+#define MCI_SR 0x0040 -+#define MCI_IER 0x0044 -+#define MCI_IDR 0x0048 -+#define MCI_IMR 0x004c -+ -+/* Bitfields in CR */ -+#define MCI_MCIEN_OFFSET 0 -+#define MCI_MCIEN_SIZE 1 -+#define MCI_MCIDIS_OFFSET 1 -+#define MCI_MCIDIS_SIZE 1 -+#define MCI_PWSEN_OFFSET 2 -+#define MCI_PWSEN_SIZE 1 -+#define MCI_PWSDIS_OFFSET 3 -+#define MCI_PWSDIS_SIZE 1 -+#define MCI_SWRST_OFFSET 7 -+#define MCI_SWRST_SIZE 1 -+ -+/* Bitfields in MR */ -+#define MCI_CLKDIV_OFFSET 0 -+#define MCI_CLKDIV_SIZE 8 -+#define MCI_PWSDIV_OFFSET 8 -+#define MCI_PWSDIV_SIZE 3 -+#define MCI_RDPROOF_OFFSET 11 -+#define MCI_RDPROOF_SIZE 1 -+#define MCI_WRPROOF_OFFSET 12 -+#define MCI_WRPROOF_SIZE 1 -+#define MCI_DMAPADV_OFFSET 14 -+#define MCI_DMAPADV_SIZE 1 -+#define MCI_BLKLEN_OFFSET 16 -+#define MCI_BLKLEN_SIZE 16 -+ -+/* Bitfields in DTOR */ -+#define MCI_DTOCYC_OFFSET 0 -+#define MCI_DTOCYC_SIZE 4 -+#define MCI_DTOMUL_OFFSET 4 -+#define MCI_DTOMUL_SIZE 3 -+ -+/* Bitfields in SDCR */ -+#define MCI_SDCSEL_OFFSET 0 -+#define MCI_SDCSEL_SIZE 4 -+#define MCI_SDCBUS_OFFSET 7 -+#define MCI_SDCBUS_SIZE 1 -+ -+/* Bitfields in ARGR */ -+#define MCI_ARG_OFFSET 0 -+#define MCI_ARG_SIZE 32 -+ -+/* Bitfields in CMDR */ -+#define MCI_CMDNB_OFFSET 0 -+#define MCI_CMDNB_SIZE 6 -+#define MCI_RSPTYP_OFFSET 6 -+#define MCI_RSPTYP_SIZE 2 -+#define MCI_SPCMD_OFFSET 8 -+#define MCI_SPCMD_SIZE 3 -+#define MCI_OPDCMD_OFFSET 11 -+#define MCI_OPDCMD_SIZE 1 -+#define MCI_MAXLAT_OFFSET 12 -+#define MCI_MAXLAT_SIZE 1 -+#define MCI_TRCMD_OFFSET 16 -+#define MCI_TRCMD_SIZE 2 -+#define MCI_TRDIR_OFFSET 18 -+#define MCI_TRDIR_SIZE 1 -+#define MCI_TRTYP_OFFSET 19 -+#define MCI_TRTYP_SIZE 2 -+ -+/* Bitfields in BLKR */ -+#define MCI_BCNT_OFFSET 0 -+#define MCI_BCNT_SIZE 16 -+ -+/* Bitfields in RSPRn */ -+#define MCI_RSP_OFFSET 0 -+#define MCI_RSP_SIZE 32 -+ -+/* Bitfields in SR/IER/IDR/IMR */ -+#define MCI_CMDRDY_OFFSET 0 -+#define MCI_CMDRDY_SIZE 1 -+#define MCI_RXRDY_OFFSET 1 -+#define MCI_RXRDY_SIZE 1 -+#define MCI_TXRDY_OFFSET 2 -+#define MCI_TXRDY_SIZE 1 -+#define MCI_BLKE_OFFSET 3 -+#define MCI_BLKE_SIZE 1 -+#define MCI_DTIP_OFFSET 4 -+#define MCI_DTIP_SIZE 1 -+#define MCI_NOTBUSY_OFFSET 5 -+#define MCI_NOTBUSY_SIZE 1 -+#define MCI_ENDRX_OFFSET 6 -+#define MCI_ENDRX_SIZE 1 -+#define MCI_ENDTX_OFFSET 7 -+#define MCI_ENDTX_SIZE 1 -+#define MCI_RXBUFF_OFFSET 14 -+#define MCI_RXBUFF_SIZE 1 -+#define MCI_TXBUFE_OFFSET 15 -+#define MCI_TXBUFE_SIZE 1 -+#define MCI_RINDE_OFFSET 16 -+#define MCI_RINDE_SIZE 1 -+#define MCI_RDIRE_OFFSET 17 -+#define MCI_RDIRE_SIZE 1 -+#define MCI_RCRCE_OFFSET 18 -+#define MCI_RCRCE_SIZE 1 -+#define MCI_RENDE_OFFSET 19 -+#define MCI_RENDE_SIZE 1 -+#define MCI_RTOE_OFFSET 20 -+#define MCI_RTOE_SIZE 1 -+#define MCI_DCRCE_OFFSET 21 -+#define MCI_DCRCE_SIZE 1 -+#define MCI_DTOE_OFFSET 22 -+#define MCI_DTOE_SIZE 1 -+#define MCI_OVRE_OFFSET 30 -+#define MCI_OVRE_SIZE 1 -+#define MCI_UNRE_OFFSET 31 -+#define MCI_UNRE_SIZE 1 -+ -+/* Constants for DTOMUL */ -+#define MCI_DTOMUL_1_CYCLE 0 -+#define MCI_DTOMUL_16_CYCLES 1 -+#define MCI_DTOMUL_128_CYCLES 2 -+#define MCI_DTOMUL_256_CYCLES 3 -+#define MCI_DTOMUL_1024_CYCLES 4 -+#define MCI_DTOMUL_4096_CYCLES 5 -+#define MCI_DTOMUL_65536_CYCLES 6 -+#define MCI_DTOMUL_1048576_CYCLES 7 -+ -+/* Constants for RSPTYP */ -+#define MCI_RSPTYP_NO_RESP 0 -+#define MCI_RSPTYP_48_BIT 1 -+#define MCI_RSPTYP_136_BIT 2 -+ -+/* Constants for SPCMD */ -+#define MCI_SPCMD_NO_SPEC_CMD 0 -+#define MCI_SPCMD_INIT_CMD 1 -+#define MCI_SPCMD_SYNC_CMD 2 -+#define MCI_SPCMD_INT_CMD 4 -+#define MCI_SPCMD_INT_RESP 5 -+ -+/* Constants for TRCMD */ -+#define MCI_TRCMD_NO_TRANS 0 -+#define MCI_TRCMD_START_TRANS 1 -+#define MCI_TRCMD_STOP_TRANS 2 -+ -+/* Constants for TRTYP */ -+#define MCI_TRTYP_BLOCK 0 -+#define MCI_TRTYP_MULTI_BLOCK 1 -+#define MCI_TRTYP_STREAM 2 -+ -+/* Bit manipulation macros */ -+#define MCI_BIT(name) \ -+ (1 << MCI_##name##_OFFSET) -+#define MCI_BF(name,value) \ -+ (((value) & ((1 << MCI_##name##_SIZE) - 1)) \ -+ << MCI_##name##_OFFSET) -+#define MCI_BFEXT(name,value) \ -+ (((value) >> MCI_##name##_OFFSET) \ -+ & ((1 << MCI_##name##_SIZE) - 1)) -+#define MCI_BFINS(name,value,old) \ -+ (((old) & ~(((1 << MCI_##name##_SIZE) - 1) \ -+ << MCI_##name##_OFFSET)) \ -+ | MCI_BF(name,value)) -+ -+/* Register access macros */ -+#define mci_readl(port,reg) \ -+ __raw_readl((port)->regs + MCI_##reg) -+#define mci_writel(port,reg,value) \ -+ __raw_writel((value), (port)->regs + MCI_##reg) -+ -+#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */ |