mmc: Move host and card drivers to subdirs
authorPierre Ossman <drzeus@drzeus.cx>
Sun, 11 Feb 2007 18:57:36 +0000 (19:57 +0100)
committerPierre Ossman <drzeus@drzeus.cx>
Tue, 1 May 2007 11:04:17 +0000 (13:04 +0200)
Clean up the drivers/mmc directory by moving card and host drivers
into subdirectories.

Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
42 files changed:
drivers/mmc/Kconfig
drivers/mmc/Makefile
drivers/mmc/at91_mci.c [deleted file]
drivers/mmc/au1xmmc.c [deleted file]
drivers/mmc/au1xmmc.h [deleted file]
drivers/mmc/block.c [deleted file]
drivers/mmc/card/Kconfig [new file with mode: 0644]
drivers/mmc/card/Makefile [new file with mode: 0644]
drivers/mmc/card/block.c [new file with mode: 0644]
drivers/mmc/card/queue.c [new file with mode: 0644]
drivers/mmc/card/queue.h [new file with mode: 0644]
drivers/mmc/host/Kconfig [new file with mode: 0644]
drivers/mmc/host/Makefile [new file with mode: 0644]
drivers/mmc/host/at91_mci.c [new file with mode: 0644]
drivers/mmc/host/au1xmmc.c [new file with mode: 0644]
drivers/mmc/host/au1xmmc.h [new file with mode: 0644]
drivers/mmc/host/imxmmc.c [new file with mode: 0644]
drivers/mmc/host/imxmmc.h [new file with mode: 0644]
drivers/mmc/host/mmci.c [new file with mode: 0644]
drivers/mmc/host/mmci.h [new file with mode: 0644]
drivers/mmc/host/omap.c [new file with mode: 0644]
drivers/mmc/host/pxamci.c [new file with mode: 0644]
drivers/mmc/host/pxamci.h [new file with mode: 0644]
drivers/mmc/host/sdhci.c [new file with mode: 0644]
drivers/mmc/host/sdhci.h [new file with mode: 0644]
drivers/mmc/host/tifm_sd.c [new file with mode: 0644]
drivers/mmc/host/wbsd.c [new file with mode: 0644]
drivers/mmc/host/wbsd.h [new file with mode: 0644]
drivers/mmc/imxmmc.c [deleted file]
drivers/mmc/imxmmc.h [deleted file]
drivers/mmc/mmci.c [deleted file]
drivers/mmc/mmci.h [deleted file]
drivers/mmc/omap.c [deleted file]
drivers/mmc/pxamci.c [deleted file]
drivers/mmc/pxamci.h [deleted file]
drivers/mmc/queue.c [deleted file]
drivers/mmc/queue.h [deleted file]
drivers/mmc/sdhci.c [deleted file]
drivers/mmc/sdhci.h [deleted file]
drivers/mmc/tifm_sd.c [deleted file]
drivers/mmc/wbsd.c [deleted file]
drivers/mmc/wbsd.h [deleted file]

index 12af9c718764e36fcbad74fa37c01aa9d37544c4..c7d64c0187fb8c9501cdf864b2c0314bf2b30725 100644 (file)
@@ -19,110 +19,8 @@ config MMC_DEBUG
          This is an option for use by developers; most people should
          say N here.  This enables MMC core and driver debugging.
 
-config MMC_BLOCK
-       tristate "MMC block device driver"
-       depends on MMC && BLOCK
-       default y
-       help
-         Say Y here to enable the MMC block device driver support.
-         This provides a block device driver, which you can use to
-         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.
-
-config MMC_PXA
-       tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
-       depends on ARCH_PXA && MMC
-       help
-         This selects the Intel(R) PXA(R) Multimedia card Interface.
-         If you have a PXA(R) platform with a Multimedia Card slot,
-         say Y or M here.
-
-         If unsure, say N.
-
-config MMC_SDHCI
-       tristate "Secure Digital Host Controller Interface support  (EXPERIMENTAL)"
-       depends on PCI && MMC && EXPERIMENTAL
-       help
-         This select the generic Secure Digital Host Controller Interface.
-         It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
-         and Toshiba(R). Most controllers found in laptops are of this type.
-         If you have a controller with this interface, say Y or M here.
-
-         If unsure, say N.
-
-config MMC_OMAP
-       tristate "TI OMAP Multimedia Card Interface support"
-       depends on ARCH_OMAP && MMC
-       select TPS65010 if MACH_OMAP_H2
-       help
-         This selects the TI OMAP Multimedia card Interface.
-         If you have an OMAP board 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
-       help
-         This selects the Winbond(R) W83L51xD Secure digital and
-          Multimedia card Interface.
-         If you have a machine with a integrated W83L518D or W83L519D
-         SD/MMC card reader, say Y or M here.
-
-         If unsure, say N.
-
-config MMC_AU1X
-       tristate "Alchemy AU1XX0 MMC Card Interface support"
-       depends on MMC && SOC_AU1200
-       help
-         This selects the AMD Alchemy(R) Multimedia card interface.
-         If you have a Alchemy platform with a MMC slot, say Y or M here.
-
-         If unsure, say N.
-
-config MMC_AT91
-       tristate "AT91 SD/MMC Card Interface support"
-       depends on ARCH_AT91 && MMC
-       help
-         This selects the AT91 MCI controller.
-
-         If unsure, say N.
-
-config MMC_IMX
-       tristate "Motorola i.MX Multimedia Card Interface support"
-       depends on ARCH_IMX && MMC
-       help
-         This selects the Motorola i.MX Multimedia card Interface.
-         If you have a i.MX platform with a Multimedia Card slot,
-         say Y or M here.
-
-         If unsure, say N.
-
-config MMC_TIFM_SD
-       tristate "TI Flash Media MMC/SD Interface support  (EXPERIMENTAL)"
-       depends on MMC && EXPERIMENTAL && PCI
-       select TIFM_CORE
-       help
-         Say Y here if you want to be able to access MMC/SD cards with
-         the Texas Instruments(R) Flash Media card reader, found in many
-         laptops.
-         This option 'selects' (turns on, enables) 'TIFM_CORE', but you
-         probably also need appropriate card reader host adapter, such as
-         'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support
-         (TIFM_7XX1)'.
+source "drivers/mmc/card/Kconfig"
 
-          To compile this driver as a module, choose M here: the
-         module will be called tifm_sd.
+source "drivers/mmc/host/Kconfig"
 
 endmenu
index 9ef010a516084cf41937049c3009037e38fbd159..4d2bdfeb8d7616b3528cedfcf4ff469ca66ba4fc 100644 (file)
@@ -2,32 +2,16 @@
 # Makefile for the kernel mmc device drivers.
 #
 
+ifeq ($(CONFIG_MMC_DEBUG),y)
+       EXTRA_CFLAGS            += -DDEBUG
+endif
+
 #
 # Core
 #
 obj-$(CONFIG_MMC)              += mmc_core.o
+mmc_core-y                     := mmc.o mmc_sysfs.o
 
-#
-# Media drivers
-#
-obj-$(CONFIG_MMC_BLOCK)                += mmc_block.o
-mmc_block-objs                 := block.o queue.o
+obj-$(CONFIG_MMC)              += card/
+obj-$(CONFIG_MMC)              += host/
 
-#
-# Host drivers
-#
-obj-$(CONFIG_MMC_ARMMMCI)      += mmci.o
-obj-$(CONFIG_MMC_PXA)          += pxamci.o
-obj-$(CONFIG_MMC_IMX)          += imxmmc.o
-obj-$(CONFIG_MMC_SDHCI)                += sdhci.o
-obj-$(CONFIG_MMC_WBSD)         += wbsd.o
-obj-$(CONFIG_MMC_AU1X)         += au1xmmc.o
-obj-$(CONFIG_MMC_OMAP)         += omap.o
-obj-$(CONFIG_MMC_AT91)         += at91_mci.o
-obj-$(CONFIG_MMC_TIFM_SD)      += tifm_sd.o
-
-mmc_core-y := mmc.o mmc_sysfs.o
-
-ifeq ($(CONFIG_MMC_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
deleted file mode 100644 (file)
index e37943c..0000000
+++ /dev/null
@@ -1,1001 +0,0 @@
-/*
- *  linux/drivers/mmc/at91_mci.c - ATMEL AT91 MCI Driver
- *
- *  Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
- *
- *  Copyright (C) 2006 Malcolm Noyes
- *
- * 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.
- */
-
-/*
-   This is the AT91 MCI driver that has been tested with both MMC cards
-   and SD-cards.  Boards that support write protect are now supported.
-   The CCAT91SBC001 board does not support SD cards.
-
-   The three entry points are at91_mci_request, at91_mci_set_ios
-   and at91_mci_get_ro.
-
-   SET IOS
-     This configures the device to put it into the correct mode and clock speed
-     required.
-
-   MCI REQUEST
-     MCI request processes the commands sent in the mmc_request structure. This
-     can consist of a processing command and a stop command in the case of
-     multiple block transfers.
-
-     There are three main types of request, commands, reads and writes.
-
-     Commands are straight forward. The command is submitted to the controller and
-     the request function returns. When the controller generates an interrupt to indicate
-     the command is finished, the response to the command are read and the mmc_request_done
-     function called to end the request.
-
-     Reads and writes work in a similar manner to normal commands but involve the PDC (DMA)
-     controller to manage the transfers.
-
-     A read is done from the controller directly to the scatterlist passed in from the request.
-     Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte
-     swapped in the scatterlist buffers.  AT91SAM926x are not affected by this bug.
-
-     The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
-
-     A write is slightly different in that the bytes to write are read from the scatterlist
-     into a dma memory buffer (this is in case the source buffer should be read only). The
-     entire write buffer is then done from this single dma memory buffer.
-
-     The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY
-
-   GET RO
-     Gets the status of the write protect pin, if available.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/atmel_pdc.h>
-
-#include <linux/mmc/host.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mach/mmc.h>
-#include <asm/arch/board.h>
-#include <asm/arch/cpu.h>
-#include <asm/arch/gpio.h>
-#include <asm/arch/at91_mci.h>
-
-#define DRIVER_NAME "at91_mci"
-
-#undef SUPPORT_4WIRE
-
-#define FL_SENT_COMMAND        (1 << 0)
-#define FL_SENT_STOP   (1 << 1)
-
-#define AT91_MCI_ERRORS        (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE       \
-               | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE               \
-               | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)                        
-
-#define at91_mci_read(host, reg)       __raw_readl((host)->baseaddr + (reg))
-#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg))
-
-
-/*
- * Low level type for this driver
- */
-struct at91mci_host
-{
-       struct mmc_host *mmc;
-       struct mmc_command *cmd;
-       struct mmc_request *request;
-
-       void __iomem *baseaddr;
-       int irq;
-
-       struct at91_mmc_data *board;
-       int present;
-
-       struct clk *mci_clk;
-
-       /*
-        * Flag indicating when the command has been sent. This is used to
-        * work out whether or not to send the stop
-        */
-       unsigned int flags;
-       /* flag for current bus settings */
-       u32 bus_mode;
-
-       /* DMA buffer used for transmitting */
-       unsigned int* buffer;
-       dma_addr_t physical_address;
-       unsigned int total_length;
-
-       /* Latest in the scatterlist that has been enabled for transfer, but not freed */
-       int in_use_index;
-
-       /* Latest in the scatterlist that has been enabled for transfer */
-       int transfer_index;
-};
-
-/*
- * Copy from sg to a dma block - used for transfers
- */
-static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)
-{
-       unsigned int len, i, size;
-       unsigned *dmabuf = host->buffer;
-
-       size = host->total_length;
-       len = data->sg_len;
-
-       /*
-        * Just loop through all entries. Size might not
-        * be the entire list though so make sure that
-        * we do not transfer too much.
-        */
-       for (i = 0; i < len; i++) {
-               struct scatterlist *sg;
-               int amount;
-               unsigned int *sgbuffer;
-
-               sg = &data->sg[i];
-
-               sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
-               amount = min(size, sg->length);
-               size -= amount;
-
-               if (cpu_is_at91rm9200()) {      /* AT91RM9200 errata */
-                       int index;
-
-                       for (index = 0; index < (amount / 4); index++)
-                               *dmabuf++ = swab32(sgbuffer[index]);
-               }
-               else
-                       memcpy(dmabuf, sgbuffer, amount);
-
-               kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
-
-               if (size == 0)
-                       break;
-       }
-
-       /*
-        * Check that we didn't get a request to transfer
-        * more data than can fit into the SG list.
-        */
-       BUG_ON(size != 0);
-}
-
-/*
- * Prepare a dma read
- */
-static void at91mci_pre_dma_read(struct at91mci_host *host)
-{
-       int i;
-       struct scatterlist *sg;
-       struct mmc_command *cmd;
-       struct mmc_data *data;
-
-       pr_debug("pre dma read\n");
-
-       cmd = host->cmd;
-       if (!cmd) {
-               pr_debug("no command\n");
-               return;
-       }
-
-       data = cmd->data;
-       if (!data) {
-               pr_debug("no data\n");
-               return;
-       }
-
-       for (i = 0; i < 2; i++) {
-               /* nothing left to transfer */
-               if (host->transfer_index >= data->sg_len) {
-                       pr_debug("Nothing left to transfer (index = %d)\n", host->transfer_index);
-                       break;
-               }
-
-               /* Check to see if this needs filling */
-               if (i == 0) {
-                       if (at91_mci_read(host, ATMEL_PDC_RCR) != 0) {
-                               pr_debug("Transfer active in current\n");
-                               continue;
-                       }
-               }
-               else {
-                       if (at91_mci_read(host, ATMEL_PDC_RNCR) != 0) {
-                               pr_debug("Transfer active in next\n");
-                               continue;
-                       }
-               }
-
-               /* Setup the next transfer */
-               pr_debug("Using transfer index %d\n", host->transfer_index);
-
-               sg = &data->sg[host->transfer_index++];
-               pr_debug("sg = %p\n", sg);
-
-               sg->dma_address = dma_map_page(NULL, sg->page, sg->offset, sg->length, DMA_FROM_DEVICE);
-
-               pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
-
-               if (i == 0) {
-                       at91_mci_write(host, ATMEL_PDC_RPR, sg->dma_address);
-                       at91_mci_write(host, ATMEL_PDC_RCR, sg->length / 4);
-               }
-               else {
-                       at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address);
-                       at91_mci_write(host, ATMEL_PDC_RNCR, sg->length / 4);
-               }
-       }
-
-       pr_debug("pre dma read done\n");
-}
-
-/*
- * Handle after a dma read
- */
-static void at91mci_post_dma_read(struct at91mci_host *host)
-{
-       struct mmc_command *cmd;
-       struct mmc_data *data;
-
-       pr_debug("post dma read\n");
-
-       cmd = host->cmd;
-       if (!cmd) {
-               pr_debug("no command\n");
-               return;
-       }
-
-       data = cmd->data;
-       if (!data) {
-               pr_debug("no data\n");
-               return;
-       }
-
-       while (host->in_use_index < host->transfer_index) {
-               unsigned int *buffer;
-
-               struct scatterlist *sg;
-
-               pr_debug("finishing index %d\n", host->in_use_index);
-
-               sg = &data->sg[host->in_use_index++];
-
-               pr_debug("Unmapping page %08X\n", sg->dma_address);
-
-               dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE);
-
-               /* Swap the contents of the buffer */
-               buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
-               pr_debug("buffer = %p, length = %d\n", buffer, sg->length);
-
-               data->bytes_xfered += sg->length;
-
-               if (cpu_is_at91rm9200()) {      /* AT91RM9200 errata */
-                       int index;
-
-                       for (index = 0; index < (sg->length / 4); index++)
-                               buffer[index] = swab32(buffer[index]);
-               }
-
-               kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
-               flush_dcache_page(sg->page);
-       }
-
-       /* Is there another transfer to trigger? */
-       if (host->transfer_index < data->sg_len)
-               at91mci_pre_dma_read(host);
-       else {
-               at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
-               at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-       }
-
-       pr_debug("post dma read done\n");
-}
-
-/*
- * Handle transmitted data
- */
-static void at91_mci_handle_transmitted(struct at91mci_host *host)
-{
-       struct mmc_command *cmd;
-       struct mmc_data *data;
-
-       pr_debug("Handling the transmit\n");
-
-       /* Disable the transfer */
-       at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
-       /* Now wait for cmd ready */
-       at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
-       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
-
-       cmd = host->cmd;
-       if (!cmd) return;
-
-       data = cmd->data;
-       if (!data) return;
-
-       data->bytes_xfered = host->total_length;
-}
-
-/*
- * Enable the controller
- */
-static void at91_mci_enable(struct at91mci_host *host)
-{
-       at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
-       at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-       at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
-       at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a);
-
-       /* use Slot A or B (only one at same time) */
-       at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
-}
-
-/*
- * Disable the controller
- */
-static void at91_mci_disable(struct at91mci_host *host)
-{
-       at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
-}
-
-/*
- * Send a command
- * return the interrupts to enable
- */
-static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)
-{
-       unsigned int cmdr, mr;
-       unsigned int block_length;
-       struct mmc_data *data = cmd->data;
-
-       unsigned int blocks;
-       unsigned int ier = 0;
-
-       host->cmd = cmd;
-
-       /* Not sure if this is needed */
-#if 0
-       if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
-               pr_debug("Clearing timeout\n");
-               at91_mci_write(host, AT91_MCI_ARGR, 0);
-               at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
-               while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
-                       /* spin */
-                       pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
-               }
-       }
-#endif
-       cmdr = cmd->opcode;
-
-       if (mmc_resp_type(cmd) == MMC_RSP_NONE)
-               cmdr |= AT91_MCI_RSPTYP_NONE;
-       else {
-               /* if a response is expected then allow maximum response latancy */
-               cmdr |= AT91_MCI_MAXLAT;
-               /* set 136 bit response for R2, 48 bit response otherwise */
-               if (mmc_resp_type(cmd) == MMC_RSP_R2)
-                       cmdr |= AT91_MCI_RSPTYP_136;
-               else
-                       cmdr |= AT91_MCI_RSPTYP_48;
-       }
-
-       if (data) {
-               block_length = data->blksz;
-               blocks = data->blocks;
-
-               /* always set data start - also set direction flag for read */
-               if (data->flags & MMC_DATA_READ)
-                       cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START);
-               else if (data->flags & MMC_DATA_WRITE)
-                       cmdr |= AT91_MCI_TRCMD_START;
-
-               if (data->flags & MMC_DATA_STREAM)
-                       cmdr |= AT91_MCI_TRTYP_STREAM;
-               if (data->flags & MMC_DATA_MULTI)
-                       cmdr |= AT91_MCI_TRTYP_MULTIPLE;
-       }
-       else {
-               block_length = 0;
-               blocks = 0;
-       }
-
-       if (cmd->opcode == MMC_STOP_TRANSMISSION)
-               cmdr |= AT91_MCI_TRCMD_STOP;
-
-       if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
-               cmdr |= AT91_MCI_OPDCMD;
-
-       /*
-        * Set the arguments and send the command
-        */
-       pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
-               cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
-
-       if (!data) {
-               at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS);
-               at91_mci_write(host, ATMEL_PDC_RPR, 0);
-               at91_mci_write(host, ATMEL_PDC_RCR, 0);
-               at91_mci_write(host, ATMEL_PDC_RNPR, 0);
-               at91_mci_write(host, ATMEL_PDC_RNCR, 0);
-               at91_mci_write(host, ATMEL_PDC_TPR, 0);
-               at91_mci_write(host, ATMEL_PDC_TCR, 0);
-               at91_mci_write(host, ATMEL_PDC_TNPR, 0);
-               at91_mci_write(host, ATMEL_PDC_TNCR, 0);
-
-               at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
-               at91_mci_write(host, AT91_MCI_CMDR, cmdr);
-               return AT91_MCI_CMDRDY;
-       }
-
-       mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */
-       at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
-
-       /*
-        * Disable the PDC controller
-        */
-       at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
-       if (cmdr & AT91_MCI_TRCMD_START) {
-               data->bytes_xfered = 0;
-               host->transfer_index = 0;
-               host->in_use_index = 0;
-               if (cmdr & AT91_MCI_TRDIR) {
-                       /*
-                        * Handle a read
-                        */
-                       host->buffer = NULL;
-                       host->total_length = 0;
-
-                       at91mci_pre_dma_read(host);
-                       ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;
-               }
-               else {
-                       /*
-                        * Handle a write
-                        */
-                       host->total_length = block_length * blocks;
-                       host->buffer = dma_alloc_coherent(NULL,
-                                                 host->total_length,
-                                                 &host->physical_address, GFP_KERNEL);
-
-                       at91mci_sg_to_dma(host, data);
-
-                       pr_debug("Transmitting %d bytes\n", host->total_length);
-
-                       at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
-                       at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4);
-                       ier = AT91_MCI_TXBUFE;
-               }
-       }
-
-       /*
-        * Send the command and then enable the PDC - not the other way round as
-        * the data sheet says
-        */
-
-       at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
-       at91_mci_write(host, AT91_MCI_CMDR, cmdr);
-
-       if (cmdr & AT91_MCI_TRCMD_START) {
-               if (cmdr & AT91_MCI_TRDIR)
-                       at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
-               else
-                       at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
-       }
-       return ier;
-}
-
-/*
- * Wait for a command to complete
- */
-static void at91mci_process_command(struct at91mci_host *host, struct mmc_command *cmd)
-{
-       unsigned int ier;
-
-       ier = at91_mci_send_command(host, cmd);
-
-       pr_debug("setting ier to %08X\n", ier);
-
-       /* Stop on errors or the required value */
-       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
-}
-
-/*
- * Process the next step in the request
- */
-static void at91mci_process_next(struct at91mci_host *host)
-{
-       if (!(host->flags & FL_SENT_COMMAND)) {
-               host->flags |= FL_SENT_COMMAND;
-               at91mci_process_command(host, host->request->cmd);
-       }
-       else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {
-               host->flags |= FL_SENT_STOP;
-               at91mci_process_command(host, host->request->stop);
-       }
-       else
-               mmc_request_done(host->mmc, host->request);
-}
-
-/*
- * Handle a command that has been completed
- */
-static void at91mci_completed_command(struct at91mci_host *host)
-{
-       struct mmc_command *cmd = host->cmd;
-       unsigned int status;
-
-       at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-
-       cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
-       cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
-       cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
-       cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
-
-       if (host->buffer) {
-               dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address);
-               host->buffer = NULL;
-       }
-
-       status = at91_mci_read(host, AT91_MCI_SR);
-
-       pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
-                status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
-
-       if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE |
-                       AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
-                       AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
-               if ((status & AT91_MCI_RCRCE) &&
-                       ((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) {
-                       cmd->error = MMC_ERR_NONE;
-               }
-               else {
-                       if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE))
-                               cmd->error = MMC_ERR_TIMEOUT;
-                       else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE))
-                               cmd->error = MMC_ERR_BADCRC;
-                       else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE))
-                               cmd->error = MMC_ERR_FIFO;
-                       else
-                               cmd->error = MMC_ERR_FAILED;
-
-                       pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n",
-                                cmd->error, cmd->opcode, cmd->retries);
-               }
-       }
-       else
-               cmd->error = MMC_ERR_NONE;
-
-       at91mci_process_next(host);
-}
-
-/*
- * Handle an MMC request
- */
-static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-       struct at91mci_host *host = mmc_priv(mmc);
-       host->request = mrq;
-       host->flags = 0;
-
-       at91mci_process_next(host);
-}
-
-/*
- * Set the IOS
- */
-static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-       int clkdiv;
-       struct at91mci_host *host = mmc_priv(mmc);
-       unsigned long at91_master_clock = clk_get_rate(host->mci_clk);
-
-       host->bus_mode = ios->bus_mode;
-
-       if (ios->clock == 0) {
-               /* Disable the MCI controller */
-               at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS);
-               clkdiv = 0;
-       }
-       else {
-               /* Enable the MCI controller */
-               at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
-
-               if ((at91_master_clock % (ios->clock * 2)) == 0)
-                       clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
-               else
-                       clkdiv = (at91_master_clock / ios->clock) / 2;
-
-               pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv,
-                       at91_master_clock / (2 * (clkdiv + 1)));
-       }
-       if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
-               pr_debug("MMC: Setting controller bus width to 4\n");
-               at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
-       }
-       else {
-               pr_debug("MMC: Setting controller bus width to 1\n");
-               at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
-       }
-
-       /* Set the clock divider */
-       at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
-
-       /* maybe switch power to the card */
-       if (host->board->vcc_pin) {
-               switch (ios->power_mode) {
-                       case MMC_POWER_OFF:
-                               at91_set_gpio_value(host->board->vcc_pin, 0);
-                               break;
-                       case MMC_POWER_UP:
-                       case MMC_POWER_ON:
-                               at91_set_gpio_value(host->board->vcc_pin, 1);
-                               break;
-               }
-       }
-}
-
-/*
- * Handle an interrupt
- */
-static irqreturn_t at91_mci_irq(int irq, void *devid)
-{
-       struct at91mci_host *host = devid;
-       int completed = 0;
-       unsigned int int_status, int_mask;
-
-       int_status = at91_mci_read(host, AT91_MCI_SR);
-       int_mask = at91_mci_read(host, AT91_MCI_IMR);
-       
-       pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
-               int_status & int_mask);
-       
-       int_status = int_status & int_mask;
-
-       if (int_status & AT91_MCI_ERRORS) {
-               completed = 1;
-               
-               if (int_status & AT91_MCI_UNRE)
-                       pr_debug("MMC: Underrun error\n");
-               if (int_status & AT91_MCI_OVRE)
-                       pr_debug("MMC: Overrun error\n");
-               if (int_status & AT91_MCI_DTOE)
-                       pr_debug("MMC: Data timeout\n");
-               if (int_status & AT91_MCI_DCRCE)
-                       pr_debug("MMC: CRC error in data\n");
-               if (int_status & AT91_MCI_RTOE)
-                       pr_debug("MMC: Response timeout\n");
-               if (int_status & AT91_MCI_RENDE)
-                       pr_debug("MMC: Response end bit error\n");
-               if (int_status & AT91_MCI_RCRCE)
-                       pr_debug("MMC: Response CRC error\n");
-               if (int_status & AT91_MCI_RDIRE)
-                       pr_debug("MMC: Response direction error\n");
-               if (int_status & AT91_MCI_RINDE)
-                       pr_debug("MMC: Response index error\n");
-       } else {
-               /* Only continue processing if no errors */
-
-               if (int_status & AT91_MCI_TXBUFE) {
-                       pr_debug("TX buffer empty\n");
-                       at91_mci_handle_transmitted(host);
-               }
-
-               if (int_status & AT91_MCI_RXBUFF) {
-                       pr_debug("RX buffer full\n");
-                       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
-               }
-
-               if (int_status & AT91_MCI_ENDTX)
-                       pr_debug("Transmit has ended\n");
-
-               if (int_status & AT91_MCI_ENDRX) {
-                       pr_debug("Receive has ended\n");
-                       at91mci_post_dma_read(host);
-               }
-
-               if (int_status & AT91_MCI_NOTBUSY) {
-                       pr_debug("Card is ready\n");
-                       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
-               }
-
-               if (int_status & AT91_MCI_DTIP)
-                       pr_debug("Data transfer in progress\n");
-
-               if (int_status & AT91_MCI_BLKE)
-                       pr_debug("Block transfer has ended\n");
-
-               if (int_status & AT91_MCI_TXRDY)
-                       pr_debug("Ready to transmit\n");
-
-               if (int_status & AT91_MCI_RXRDY)
-                       pr_debug("Ready to receive\n");
-
-               if (int_status & AT91_MCI_CMDRDY) {
-                       pr_debug("Command ready\n");
-                       completed = 1;
-               }
-       }
-
-       if (completed) {
-               pr_debug("Completed command\n");
-               at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-               at91mci_completed_command(host);
-       } else
-               at91_mci_write(host, AT91_MCI_IDR, int_status);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
-{
-       struct at91mci_host *host = _host;
-       int present = !at91_get_gpio_value(irq);
-
-       /*
-        * we expect this irq on both insert and remove,
-        * and use a short delay to debounce.
-        */
-       if (present != host->present) {
-               host->present = present;
-               pr_debug("%s: card %s\n", mmc_hostname(host->mmc),
-                       present ? "insert" : "remove");
-               if (!present) {
-                       pr_debug("****** Resetting SD-card bus width ******\n");
-                       at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
-               }
-               mmc_detect_change(host->mmc, msecs_to_jiffies(100));
-       }
-       return IRQ_HANDLED;
-}
-
-static int at91_mci_get_ro(struct mmc_host *mmc)
-{
-       int read_only = 0;
-       struct at91mci_host *host = mmc_priv(mmc);
-
-       if (host->board->wp_pin) {
-               read_only = at91_get_gpio_value(host->board->wp_pin);
-               printk(KERN_WARNING "%s: card is %s\n", mmc_hostname(mmc),
-                               (read_only ? "read-only" : "read-write") );
-       }
-       else {
-               printk(KERN_WARNING "%s: host does not support reading read-only "
-                               "switch.  Assuming write-enable.\n", mmc_hostname(mmc));
-       }
-       return read_only;
-}
-
-static const struct mmc_host_ops at91_mci_ops = {
-       .request        = at91_mci_request,
-       .set_ios        = at91_mci_set_ios,
-       .get_ro         = at91_mci_get_ro,
-};
-
-/*
- * Probe for the device
- */
-static int __init at91_mci_probe(struct platform_device *pdev)
-{
-       struct mmc_host *mmc;
-       struct at91mci_host *host;
-       struct resource *res;
-       int ret;
-
-       pr_debug("Probe MCI devices\n");
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENXIO;
-
-       if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))
-               return -EBUSY;
-
-       mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
-       if (!mmc) {
-               pr_debug("Failed to allocate mmc host\n");
-               release_mem_region(res->start, res->end - res->start + 1);
-               return -ENOMEM;
-       }
-
-       mmc->ops = &at91_mci_ops;
-       mmc->f_min = 375000;
-       mmc->f_max = 25000000;
-       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->caps = MMC_CAP_BYTEBLOCK;
-
-       mmc->max_blk_size = 4095;
-       mmc->max_blk_count = mmc->max_req_size;
-
-       host = mmc_priv(mmc);
-       host->mmc = mmc;
-       host->buffer = NULL;
-       host->bus_mode = 0;
-       host->board = pdev->dev.platform_data;
-       if (host->board->wire4) {
-#ifdef SUPPORT_4WIRE
-               mmc->caps |= MMC_CAP_4_BIT_DATA;
-#else
-               printk("AT91 MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");
-#endif
-       }
-
-       /*
-        * Get Clock
-        */
-       host->mci_clk = clk_get(&pdev->dev, "mci_clk");
-       if (IS_ERR(host->mci_clk)) {
-               printk(KERN_ERR "AT91 MMC: no clock defined.\n");
-               mmc_free_host(mmc);
-               release_mem_region(res->start, res->end - res->start + 1);
-               return -ENODEV;
-       }
-
-       /*
-        * Map I/O region
-        */
-       host->baseaddr = ioremap(res->start, res->end - res->start + 1);
-       if (!host->baseaddr) {
-               clk_put(host->mci_clk);
-               mmc_free_host(mmc);
-               release_mem_region(res->start, res->end - res->start + 1);
-               return -ENOMEM;
-       }
-
-       /*
-        * Reset hardware
-        */
-       clk_enable(host->mci_clk);              /* Enable the peripheral clock */
-       at91_mci_disable(host);
-       at91_mci_enable(host);
-
-       /*
-        * Allocate the MCI interrupt
-        */
-       host->irq = platform_get_irq(pdev, 0);
-       ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
-       if (ret) {
-               printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n");
-               clk_disable(host->mci_clk);
-               clk_put(host->mci_clk);
-               mmc_free_host(mmc);
-               iounmap(host->baseaddr);
-               release_mem_region(res->start, res->end - res->start + 1);
-               return ret;
-       }
-
-       platform_set_drvdata(pdev, mmc);
-
-       /*
-        * Add host to MMC layer
-        */
-       if (host->board->det_pin)
-               host->present = !at91_get_gpio_value(host->board->det_pin);
-       else
-               host->present = -1;
-
-       mmc_add_host(mmc);
-
-       /*
-        * monitor card insertion/removal if we can
-        */
-       if (host->board->det_pin) {
-               ret = request_irq(host->board->det_pin, at91_mmc_det_irq,
-                               0, DRIVER_NAME, host);
-               if (ret)
-                       printk(KERN_ERR "AT91 MMC: Couldn't allocate MMC detect irq\n");
-       }
-
-       pr_debug("Added MCI driver\n");
-
-       return 0;
-}
-
-/*
- * Remove a device
- */
-static int __exit at91_mci_remove(struct platform_device *pdev)
-{
-       struct mmc_host *mmc = platform_get_drvdata(pdev);
-       struct at91mci_host *host;
-       struct resource *res;
-
-       if (!mmc)
-               return -1;
-
-       host = mmc_priv(mmc);
-
-       if (host->present != -1) {
-               free_irq(host->board->det_pin, host);
-               cancel_delayed_work(&host->mmc->detect);
-       }
-
-       at91_mci_disable(host);
-       mmc_remove_host(mmc);
-       free_irq(host->irq, host);
-
-       clk_disable(host->mci_clk);                     /* Disable the peripheral clock */
-       clk_put(host->mci_clk);
-
-       iounmap(host->baseaddr);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, res->end - res->start + 1);
-
-       mmc_free_host(mmc);
-       platform_set_drvdata(pdev, NULL);
-       pr_debug("MCI Removed\n");
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct mmc_host *mmc = platform_get_drvdata(pdev);
-       int ret = 0;
-
-       if (mmc)
-               ret = mmc_suspend_host(mmc, state);
-
-       return ret;
-}
-
-static int at91_mci_resume(struct platform_device *pdev)
-{
-       struct mmc_host *mmc = platform_get_drvdata(pdev);
-       int ret = 0;
-
-       if (mmc)
-               ret = mmc_resume_host(mmc);
-
-       return ret;
-}
-#else
-#define at91_mci_suspend       NULL
-#define at91_mci_resume                NULL
-#endif
-
-static struct platform_driver at91_mci_driver = {
-       .remove         = __exit_p(at91_mci_remove),
-       .suspend        = at91_mci_suspend,
-       .resume         = at91_mci_resume,
-       .driver         = {
-               .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init at91_mci_init(void)
-{
-       return platform_driver_probe(&at91_mci_driver, at91_mci_probe);
-}
-
-static void __exit at91_mci_exit(void)
-{
-       platform_driver_unregister(&at91_mci_driver);
-}
-
-module_init(at91_mci_init);
-module_exit(at91_mci_exit);
-
-MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver");
-MODULE_AUTHOR("Nick Randell");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
deleted file mode 100644 (file)
index b7156a4..0000000
+++ /dev/null
@@ -1,1031 +0,0 @@
-/*
- * linux/drivers/mmc/au1xmmc.c - AU1XX0 MMC driver
- *
- *  Copyright (c) 2005, Advanced Micro Devices, Inc.
- *
- *  Developed with help from the 2.4.30 MMC AU1XXX controller including
- *  the following copyright notices:
- *     Copyright (c) 2003-2004 Embedded Edge, LLC.
- *     Portions Copyright (C) 2002 Embedix, Inc
- *     Copyright 2002 Hewlett-Packard Company
-
- *  2.6 version of this driver inspired by:
- *     (drivers/mmc/wbsd.c) Copyright (C) 2004-2005 Pierre Ossman,
- *     All Rights Reserved.
- *     (drivers/mmc/pxa.c) Copyright (C) 2003 Russell King,
- *     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.
- */
-
-/* Why is a timer used to detect insert events?
- *
- * From the AU1100 MMC application guide:
- * If the Au1100-based design is intended to support both MultiMediaCards
- * and 1- or 4-data bit SecureDigital cards, then the solution is to
- * connect a weak (560KOhm) pull-up resistor to connector pin 1.
- * In doing so, a MMC card never enters SPI-mode communications,
- * but now the SecureDigital card-detect feature of CD/DAT3 is ineffective
- * (the low to high transition will not occur).
- *
- * So we use the timer to check the status manually.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-
-#include <linux/mmc/host.h>
-#include <asm/io.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1xxx_dbdma.h>
-#include <asm/mach-au1x00/au1100_mmc.h>
-#include <asm/scatterlist.h>
-
-#include <au1xxx.h>
-#include "au1xmmc.h"
-
-#define DRIVER_NAME "au1xxx-mmc"
-
-/* Set this to enable special debugging macros */
-
-#ifdef DEBUG
-#define DBG(fmt, idx, args...) printk("au1xx(%d): DEBUG: " fmt, idx, ##args)
-#else
-#define DBG(fmt, idx, args...)
-#endif
-
-const struct {
-       u32 iobase;
-       u32 tx_devid, rx_devid;
-       u16 bcsrpwr;
-       u16 bcsrstatus;
-       u16 wpstatus;
-} au1xmmc_card_table[] = {
-       { SD0_BASE, DSCR_CMD0_SDMS_TX0, DSCR_CMD0_SDMS_RX0,
-         BCSR_BOARD_SD0PWR, BCSR_INT_SD0INSERT, BCSR_STATUS_SD0WP },
-#ifndef CONFIG_MIPS_DB1200
-       { SD1_BASE, DSCR_CMD0_SDMS_TX1, DSCR_CMD0_SDMS_RX1,
-         BCSR_BOARD_DS1PWR, BCSR_INT_SD1INSERT, BCSR_STATUS_SD1WP }
-#endif
-};
-
-#define AU1XMMC_CONTROLLER_COUNT \
-       (sizeof(au1xmmc_card_table) / sizeof(au1xmmc_card_table[0]))
-
-/* This array stores pointers for the hosts (used by the IRQ handler) */
-struct au1xmmc_host *au1xmmc_hosts[AU1XMMC_CONTROLLER_COUNT];
-static int dma = 1;
-
-#ifdef MODULE
-module_param(dma, bool, 0);
-MODULE_PARM_DESC(dma, "Use DMA engine for data transfers (0 = disabled)");
-#endif
-
-static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask)
-{
-       u32 val = au_readl(HOST_CONFIG(host));
-       val |= mask;
-       au_writel(val, HOST_CONFIG(host));
-       au_sync();
-}
-
-static inline void FLUSH_FIFO(struct au1xmmc_host *host)
-{
-       u32 val = au_readl(HOST_CONFIG2(host));
-
-       au_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host));
-       au_sync_delay(1);
-
-       /* SEND_STOP will turn off clock control - this re-enables it */
-       val &= ~SD_CONFIG2_DF;
-
-       au_writel(val, HOST_CONFIG2(host));
-       au_sync();
-}
-
-static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask)
-{
-       u32 val = au_readl(HOST_CONFIG(host));
-       val &= ~mask;
-       au_writel(val, HOST_CONFIG(host));
-       au_sync();
-}
-
-static inline void SEND_STOP(struct au1xmmc_host *host)
-{
-
-       /* We know the value of CONFIG2, so avoid a read we don't need */
-       u32 mask = SD_CONFIG2_EN;
-
-       WARN_ON(host->status != HOST_S_DATA);
-       host->status = HOST_S_STOP;
-
-       au_writel(mask | SD_CONFIG2_DF, HOST_CONFIG2(host));
-       au_sync();
-
-       /* Send the stop commmand */
-       au_writel(STOP_CMD, HOST_CMD(host));
-}
-
-static void au1xmmc_set_power(struct au1xmmc_host *host, int state)
-{
-
-       u32 val = au1xmmc_card_table[host->id].bcsrpwr;
-
-       bcsr->board &= ~val;
-       if (state) bcsr->board |= val;
-
-       au_sync_delay(1);
-}
-
-static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
-{
-       return (bcsr->sig_status & au1xmmc_card_table[host->id].bcsrstatus)
-               ? 1 : 0;
-}
-
-static int au1xmmc_card_readonly(struct mmc_host *mmc)
-{
-       struct au1xmmc_host *host = mmc_priv(mmc);
-       return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
-               ? 1 : 0;
-}
-
-static void au1xmmc_finish_request(struct au1xmmc_host *host)
-{
-
-       struct mmc_request *mrq = host->mrq;
-
-       host->mrq = NULL;
-       host->flags &= HOST_F_ACTIVE;
-
-       host->dma.len = 0;
-       host->dma.dir = 0;
-
-       host->pio.index  = 0;
-       host->pio.offset = 0;
-       host->pio.len = 0;
-
-       host->status = HOST_S_IDLE;
-
-       bcsr->disk_leds |= (1 << 8);
-
-       mmc_request_done(host->mmc, mrq);
-}
-
-static void au1xmmc_tasklet_finish(unsigned long param)
-{
-       struct au1xmmc_host *host = (struct au1xmmc_host *) param;
-       au1xmmc_finish_request(host);
-}
-
-static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
-                               struct mmc_command *cmd)
-{
-
-       u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
-
-       switch (mmc_resp_type(cmd)) {
-       case MMC_RSP_NONE:
-               break;
-       case MMC_RSP_R1:
-               mmccmd |= SD_CMD_RT_1;
-               break;
-       case MMC_RSP_R1B:
-               mmccmd |= SD_CMD_RT_1B;
-               break;
-       case MMC_RSP_R2:
-               mmccmd |= SD_CMD_RT_2;
-               break;
-       case MMC_RSP_R3:
-               mmccmd |= SD_CMD_RT_3;
-               break;
-       default:
-               printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
-                       mmc_resp_type(cmd));
-               return MMC_ERR_INVALID;
-       }
-
-       switch(cmd->opcode) {
-       case MMC_READ_SINGLE_BLOCK:
-       case SD_APP_SEND_SCR:
-               mmccmd |= SD_CMD_CT_2;
-               break;
-       case MMC_READ_MULTIPLE_BLOCK:
-               mmccmd |= SD_CMD_CT_4;
-               break;
-       case MMC_WRITE_BLOCK:
-               mmccmd |= SD_CMD_CT_1;
-               break;
-
-       case MMC_WRITE_MULTIPLE_BLOCK:
-               mmccmd |= SD_CMD_CT_3;
-               break;
-       case MMC_STOP_TRANSMISSION:
-               mmccmd |= SD_CMD_CT_7;
-               break;
-       }
-
-       au_writel(cmd->arg, HOST_CMDARG(host));
-       au_sync();
-
-       if (wait)
-               IRQ_OFF(host, SD_CONFIG_CR);
-
-       au_writel((mmccmd | SD_CMD_GO), HOST_CMD(host));
-       au_sync();
-
-       /* Wait for the command to go on the line */
-
-       while(1) {
-               if (!(au_readl(HOST_CMD(host)) & SD_CMD_GO))
-                       break;
-       }
-
-       /* Wait for the command to come back */
-
-       if (wait) {
-               u32 status = au_readl(HOST_STATUS(host));
-
-               while(!(status & SD_STATUS_CR))
-                       status = au_readl(HOST_STATUS(host));
-
-               /* Clear the CR status */
-               au_writel(SD_STATUS_CR, HOST_STATUS(host));
-
-               IRQ_ON(host, SD_CONFIG_CR);
-       }
-
-       return MMC_ERR_NONE;
-}
-
-static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
-{
-
-       struct mmc_request *mrq = host->mrq;
-       struct mmc_data *data;
-       u32 crc;
-
-       WARN_ON(host->status != HOST_S_DATA && host->status != HOST_S_STOP);
-
-       if (host->mrq == NULL)
-               return;
-
-       data = mrq->cmd->data;
-
-       if (status == 0)
-               status = au_readl(HOST_STATUS(host));
-
-       /* The transaction is really over when the SD_STATUS_DB bit is clear */
-
-       while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
-               status = au_readl(HOST_STATUS(host));
-
-       data->error = MMC_ERR_NONE;
-       dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir);
-
-        /* Process any errors */
-
-       crc = (status & (SD_STATUS_WC | SD_STATUS_RC));
-       if (host->flags & HOST_F_XMIT)
-               crc |= ((status & 0x07) == 0x02) ? 0 : 1;
-
-       if (crc)
-               data->error = MMC_ERR_BADCRC;
-
-       /* Clear the CRC bits */
-       au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host));
-
-       data->bytes_xfered = 0;
-
-       if (data->error == MMC_ERR_NONE) {
-               if (host->flags & HOST_F_DMA) {
-                       u32 chan = DMA_CHANNEL(host);
-
-                       chan_tab_t *c = *((chan_tab_t **) chan);
-                       au1x_dma_chan_t *cp = c->chan_ptr;
-                       data->bytes_xfered = cp->ddma_bytecnt;
-               }
-               else
-                       data->bytes_xfered =
-                               (data->blocks * data->blksz) -
-                               host->pio.len;
-       }
-
-       au1xmmc_finish_request(host);
-}
-
-static void au1xmmc_tasklet_data(unsigned long param)
-{
-       struct au1xmmc_host *host = (struct au1xmmc_host *) param;
-
-       u32 status = au_readl(HOST_STATUS(host));
-       au1xmmc_data_complete(host, status);
-}
-
-#define AU1XMMC_MAX_TRANSFER 8
-
-static void au1xmmc_send_pio(struct au1xmmc_host *host)
-{
-
-       struct mmc_data *data = 0;
-       int sg_len, max, count = 0;
-       unsigned char *sg_ptr;
-       u32 status = 0;
-       struct scatterlist *sg;
-
-       data = host->mrq->data;
-
-       if (!(host->flags & HOST_F_XMIT))
-               return;
-
-       /* This is the pointer to the data buffer */
-       sg = &data->sg[host->pio.index];
-       sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
-
-       /* This is the space left inside the buffer */
-       sg_len = data->sg[host->pio.index].length - host->pio.offset;
-
-       /* Check to if we need less then the size of the sg_buffer */
-
-       max = (sg_len > host->pio.len) ? host->pio.len : sg_len;
-       if (max > AU1XMMC_MAX_TRANSFER) max = AU1XMMC_MAX_TRANSFER;
-
-       for(count = 0; count < max; count++ ) {
-               unsigned char val;
-
-               status = au_readl(HOST_STATUS(host));
-
-               if (!(status & SD_STATUS_TH))
-                       break;
-
-               val = *sg_ptr++;
-
-               au_writel((unsigned long) val, HOST_TXPORT(host));
-               au_sync();
-       }
-
-       host->pio.len -= count;
-       host->pio.offset += count;
-
-       if (count == sg_len) {
-               host->pio.index++;
-               host->pio.offset = 0;
-       }
-
-       if (host->pio.len == 0) {
-               IRQ_OFF(host, SD_CONFIG_TH);
-
-               if (host->flags & HOST_F_STOP)
-                       SEND_STOP(host);
-
-               tasklet_schedule(&host->data_task);
-       }
-}
-
-static void au1xmmc_receive_pio(struct au1xmmc_host *host)
-{
-
-       struct mmc_data *data = 0;
-       int sg_len = 0, max = 0, count = 0;
-       unsigned char *sg_ptr = 0;
-       u32 status = 0;
-       struct scatterlist *sg;
-
-       data = host->mrq->data;
-
-       if (!(host->flags & HOST_F_RECV))
-               return;
-
-       max = host->pio.len;
-
-       if (host->pio.index < host->dma.len) {
-               sg = &data->sg[host->pio.index];
-               sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
-
-               /* This is the space left inside the buffer */
-               sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
-
-               /* Check to if we need less then the size of the sg_buffer */
-               if (sg_len < max) max = sg_len;
-       }
-
-       if (max > AU1XMMC_MAX_TRANSFER)
-               max = AU1XMMC_MAX_TRANSFER;
-
-       for(count = 0; count < max; count++ ) {
-               u32 val;
-               status = au_readl(HOST_STATUS(host));
-
-               if (!(status & SD_STATUS_NE))
-                       break;
-
-               if (status & SD_STATUS_RC) {
-                       DBG("RX CRC Error [%d + %d].\n", host->id,
-                                       host->pio.len, count);
-                       break;
-               }
-
-               if (status & SD_STATUS_RO) {
-                       DBG("RX Overrun [%d + %d]\n", host->id,
-                                       host->pio.len, count);
-                       break;
-               }
-               else if (status & SD_STATUS_RU) {
-                       DBG("RX Underrun [%d + %d]\n", host->id,
-                                       host->pio.len,  count);
-                       break;
-               }
-
-               val = au_readl(HOST_RXPORT(host));
-
-               if (sg_ptr)
-                       *sg_ptr++ = (unsigned char) (val & 0xFF);
-       }
-
-       host->pio.len -= count;
-       host->pio.offset += count;
-
-       if (sg_len && count == sg_len) {
-               host->pio.index++;
-               host->pio.offset = 0;
-       }
-
-       if (host->pio.len == 0) {
-               //IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF);
-               IRQ_OFF(host, SD_CONFIG_NE);
-
-               if (host->flags & HOST_F_STOP)
-                       SEND_STOP(host);
-
-               tasklet_schedule(&host->data_task);
-       }
-}
-
-/* static void au1xmmc_cmd_complete
-   This is called when a command has been completed - grab the response
-   and check for errors.  Then start the data transfer if it is indicated.
-*/
-
-static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
-{
-
-       struct mmc_request *mrq = host->mrq;
-       struct mmc_command *cmd;
-       int trans;
-
-       if (!host->mrq)
-               return;
-
-       cmd = mrq->cmd;
-       cmd->error = MMC_ERR_NONE;
-
-       if (cmd->flags & MMC_RSP_PRESENT) {
-               if (cmd->flags & MMC_RSP_136) {
-                       u32 r[4];
-                       int i;
-
-                       r[0] = au_readl(host->iobase + SD_RESP3);
-                       r[1] = au_readl(host->iobase + SD_RESP2);
-                       r[2] = au_readl(host->iobase + SD_RESP1);
-                       r[3] = au_readl(host->iobase + SD_RESP0);
-
-                       /* The CRC is omitted from the response, so really
-                        * we only got 120 bytes, but the engine expects
-                        * 128 bits, so we have to shift things up
-                        */
-
-                       for(i = 0; i < 4; i++) {
-                               cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
-                               if (i != 3)
-                                       cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
-                       }
-               } else {
-                       /* Techincally, we should be getting all 48 bits of
-                        * the response (SD_RESP1 + SD_RESP2), but because
-                        * our response omits the CRC, our data ends up
-                        * being shifted 8 bits to the right.  In this case,
-                        * that means that the OSR data starts at bit 31,
-                        * so we can just read RESP0 and return that
-                        */
-                       cmd->resp[0] = au_readl(host->iobase + SD_RESP0);
-               }
-       }
-
-        /* Figure out errors */
-
-       if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC))
-               cmd->error = MMC_ERR_BADCRC;
-
-       trans = host->flags & (HOST_F_XMIT | HOST_F_RECV);
-
-       if (!trans || cmd->error != MMC_ERR_NONE) {
-
-               IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF);
-               tasklet_schedule(&host->finish_task);
-               return;
-       }
-
-       host->status = HOST_S_DATA;
-
-       if (host->flags & HOST_F_DMA) {
-               u32 channel = DMA_CHANNEL(host);
-
-               /* Start the DMA as soon as the buffer gets something in it */
-
-               if (host->flags & HOST_F_RECV) {
-                       u32 mask = SD_STATUS_DB | SD_STATUS_NE;
-
-                       while((status & mask) != mask)
-                               status = au_readl(HOST_STATUS(host));
-               }
-
-               au1xxx_dbdma_start(channel);
-       }
-}
-
-static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate)
-{
-
-       unsigned int pbus = get_au1x00_speed();
-       unsigned int divisor;
-       u32 config;
-
-       /* From databook:
-          divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1
-       */
-
-       pbus /= ((au_readl(SYS_POWERCTRL) & 0x3) + 2);
-       pbus /= 2;
-
-       divisor = ((pbus / rate) / 2) - 1;
-
-       config = au_readl(HOST_CONFIG(host));
-
-       config &= ~(SD_CONFIG_DIV);
-       config |= (divisor & SD_CONFIG_DIV) | SD_CONFIG_DE;
-
-       au_writel(config, HOST_CONFIG(host));
-       au_sync();
-}
-
-static int
-au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
-{
-
-       int datalen = data->blocks * data->blksz;
-
-       if (dma != 0)
-               host->flags |= HOST_F_DMA;
-
-       if (data->flags & MMC_DATA_READ)
-               host->flags |= HOST_F_RECV;
-       else
-               host->flags |= HOST_F_XMIT;
-
-       if (host->mrq->stop)
-               host->flags |= HOST_F_STOP;
-
-       host->dma.dir = DMA_BIDIRECTIONAL;
-
-       host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg,
-                                  data->sg_len, host->dma.dir);
-
-       if (host->dma.len == 0)
-               return MMC_ERR_TIMEOUT;
-
-       au_writel(data->blksz - 1, HOST_BLKSIZE(host));
-
-       if (host->flags & HOST_F_DMA) {
-               int i;
-               u32 channel = DMA_CHANNEL(host);
-
-               au1xxx_dbdma_stop(channel);
-
-               for(i = 0; i < host->dma.len; i++) {
-                       u32 ret = 0, flags = DDMA_FLAGS_NOIE;
-                       struct scatterlist *sg = &data->sg[i];
-                       int sg_len = sg->length;
-
-                       int len = (datalen > sg_len) ? sg_len : datalen;
-
-                       if (i == host->dma.len - 1)
-                               flags = DDMA_FLAGS_IE;
-
-                       if (host->flags & HOST_F_XMIT){
-                               ret = au1xxx_dbdma_put_source_flags(channel,
-                                       (void *) (page_address(sg->page) +
-                                                 sg->offset),
-                                       len, flags);
-                       }
-                       else {
-                               ret = au1xxx_dbdma_put_dest_flags(channel,
-                                       (void *) (page_address(sg->page) +
-                                                 sg->offset),
-                                       len, flags);
-                       }
-
-                       if (!ret)
-                               goto dataerr;
-
-                       datalen -= len;
-               }
-       }
-       else {
-               host->pio.index = 0;
-               host->pio.offset = 0;
-               host->pio.len = datalen;
-
-               if (host->flags & HOST_F_XMIT)
-                       IRQ_ON(host, SD_CONFIG_TH);
-               else
-                       IRQ_ON(host, SD_CONFIG_NE);
-                       //IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF);
-       }
-
-       return MMC_ERR_NONE;
-
- dataerr:
-       dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir);
-       return MMC_ERR_TIMEOUT;
-}
-
-/* static void au1xmmc_request
-   This actually starts a command or data transaction
-*/
-
-static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
-{
-
-       struct au1xmmc_host *host = mmc_priv(mmc);
-       int ret = MMC_ERR_NONE;
-
-       WARN_ON(irqs_disabled());
-       WARN_ON(host->status != HOST_S_IDLE);
-
-       host->mrq = mrq;
-       host->status = HOST_S_CMD;
-
-       bcsr->disk_leds &= ~(1 << 8);
-
-       if (mrq->data) {
-               FLUSH_FIFO(host);
-               ret = au1xmmc_prepare_data(host, mrq->data);
-       }
-
-       if (ret == MMC_ERR_NONE)
-               ret = au1xmmc_send_command(host, 0, mrq->cmd);
-
-       if (ret != MMC_ERR_NONE) {
-               mrq->cmd->error = ret;
-               au1xmmc_finish_request(host);
-       }
-}
-
-static void au1xmmc_reset_controller(struct au1xmmc_host *host)
-{
-
-       /* Apply the clock */
-       au_writel(SD_ENABLE_CE, HOST_ENABLE(host));
-        au_sync_delay(1);
-
-       au_writel(SD_ENABLE_R | SD_ENABLE_CE, HOST_ENABLE(host));
-       au_sync_delay(5);
-
-       au_writel(~0, HOST_STATUS(host));
-       au_sync();
-
-       au_writel(0, HOST_BLKSIZE(host));
-       au_writel(0x001fffff, HOST_TIMEOUT(host));
-       au_sync();
-
-       au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
-        au_sync();
-
-       au_writel(SD_CONFIG2_EN | SD_CONFIG2_FF, HOST_CONFIG2(host));
-       au_sync_delay(1);
-
-       au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
-       au_sync();
-
-       /* Configure interrupts */
-       au_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host));
-       au_sync();
-}
-
-
-static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
-{
-       struct au1xmmc_host *host = mmc_priv(mmc);
-
-       if (ios->power_mode == MMC_POWER_OFF)
-               au1xmmc_set_power(host, 0);
-       else if (ios->power_mode == MMC_POWER_ON) {
-               au1xmmc_set_power(host, 1);
-       }
-
-       if (ios->clock && ios->clock != host->clock) {
-               au1xmmc_set_clock(host, ios->clock);
-               host->clock = ios->clock;
-       }
-}
-
-static void au1xmmc_dma_callback(int irq, void *dev_id)
-{
-       struct au1xmmc_host *host = (struct au1xmmc_host *) dev_id;
-
-       /* Avoid spurious interrupts */
-
-       if (!host->mrq)
-               return;
-
-       if (host->flags & HOST_F_STOP)
-               SEND_STOP(host);
-
-       tasklet_schedule(&host->data_task);
-}
-
-#define STATUS_TIMEOUT (SD_STATUS_RAT | SD_STATUS_DT)
-#define STATUS_DATA_IN  (SD_STATUS_NE)
-#define STATUS_DATA_OUT (SD_STATUS_TH)
-
-static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
-{
-
-       u32 status;
-       int i, ret = 0;
-
-       disable_irq(AU1100_SD_IRQ);
-
-       for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
-               struct au1xmmc_host * host = au1xmmc_hosts[i];
-               u32 handled = 1;
-
-               status = au_readl(HOST_STATUS(host));
-
-               if (host->mrq && (status & STATUS_TIMEOUT)) {
-                       if (status & SD_STATUS_RAT)
-                               host->mrq->cmd->error = MMC_ERR_TIMEOUT;
-
-                       else if (status & SD_STATUS_DT)
-                               host->mrq->data->error = MMC_ERR_TIMEOUT;
-
-                       /* In PIO mode, interrupts might still be enabled */
-                       IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
-
-                       //IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF);
-                       tasklet_schedule(&host->finish_task);
-               }
-#if 0
-               else if (status & SD_STATUS_DD) {
-
-                       /* Sometimes we get a DD before a NE in PIO mode */
-
-                       if (!(host->flags & HOST_F_DMA) &&
-                                       (status & SD_STATUS_NE))
-                               au1xmmc_receive_pio(host);
-                       else {
-                               au1xmmc_data_complete(host, status);
-                               //tasklet_schedule(&host->data_task);
-                       }
-               }
-#endif
-               else if (status & (SD_STATUS_CR)) {
-                       if (host->status == HOST_S_CMD)
-                               au1xmmc_cmd_complete(host,status);
-               }
-               else if (!(host->flags & HOST_F_DMA)) {
-                       if ((host->flags & HOST_F_XMIT) &&
-                           (status & STATUS_DATA_OUT))
-                               au1xmmc_send_pio(host);
-                       else if ((host->flags & HOST_F_RECV) &&
-                           (status & STATUS_DATA_IN))
-                               au1xmmc_receive_pio(host);
-               }
-               else if (status & 0x203FBC70) {
-                       DBG("Unhandled status %8.8x\n", host->id, status);
-                       handled = 0;
-               }
-
-               au_writel(status, HOST_STATUS(host));
-               au_sync();
-
-               ret |= handled;
-       }
-
-       enable_irq(AU1100_SD_IRQ);
-       return ret;
-}
-
-static void au1xmmc_poll_event(unsigned long arg)
-{
-       struct au1xmmc_host *host = (struct au1xmmc_host *) arg;
-
-       int card = au1xmmc_card_inserted(host);
-        int controller = (host->flags & HOST_F_ACTIVE) ? 1 : 0;
-
-       if (card != controller) {
-               host->flags &= ~HOST_F_ACTIVE;
-               if (card) host->flags |= HOST_F_ACTIVE;
-               mmc_detect_change(host->mmc, 0);
-       }
-
-       if (host->mrq != NULL) {
-               u32 status = au_readl(HOST_STATUS(host));
-               DBG("PENDING - %8.8x\n", host->id, status);
-       }
-
-       mod_timer(&host->timer, jiffies + AU1XMMC_DETECT_TIMEOUT);
-}
-
-static dbdev_tab_t au1xmmc_mem_dbdev =
-{
-       DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 8, 0x00000000, 0, 0
-};
-
-static void au1xmmc_init_dma(struct au1xmmc_host *host)
-{
-
-       u32 rxchan, txchan;
-
-       int txid = au1xmmc_card_table[host->id].tx_devid;
-       int rxid = au1xmmc_card_table[host->id].rx_devid;
-
-       /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
-          of 8 bits.  And since devices are shared, we need to create
-          our own to avoid freaking out other devices
-       */
-
-       int memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);
-
-       txchan = au1xxx_dbdma_chan_alloc(memid, txid,
-                                        au1xmmc_dma_callback, (void *) host);
-
-       rxchan = au1xxx_dbdma_chan_alloc(rxid, memid,
-                                        au1xmmc_dma_callback, (void *) host);
-
-       au1xxx_dbdma_set_devwidth(txchan, 8);
-       au1xxx_dbdma_set_devwidth(rxchan, 8);
-
-       au1xxx_dbdma_ring_alloc(txchan, AU1XMMC_DESCRIPTOR_COUNT);
-       au1xxx_dbdma_ring_alloc(rxchan, AU1XMMC_DESCRIPTOR_COUNT);
-
-       host->tx_chan = txchan;
-       host->rx_chan = rxchan;
-}
-
-static const struct mmc_host_ops au1xmmc_ops = {
-       .request        = au1xmmc_request,
-       .set_ios        = au1xmmc_set_ios,
-       .get_ro         = au1xmmc_card_readonly,
-};
-
-static int __devinit au1xmmc_probe(struct platform_device *pdev)
-{
-
-       int i, ret = 0;
-
-       /* THe interrupt is shared among all controllers */
-       ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, IRQF_DISABLED, "MMC", 0);
-
-       if (ret) {
-               printk(DRIVER_NAME "ERROR: Couldn't get int %d: %d\n",
-                               AU1100_SD_IRQ, ret);
-               return -ENXIO;
-       }
-
-       disable_irq(AU1100_SD_IRQ);
-
-       for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
-               struct mmc_host *mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
-               struct au1xmmc_host *host = 0;
-
-               if (!mmc) {
-                       printk(DRIVER_NAME "ERROR: no mem for host %d\n", i);
-                       au1xmmc_hosts[i] = 0;
-                       continue;
-               }
-
-               mmc->ops = &au1xmmc_ops;
-
-               mmc->f_min =   450000;
-               mmc->f_max = 24000000;
-
-               mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
-               mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
-
-               mmc->max_blk_size = 2048;
-               mmc->max_blk_count = 512;
-
-               mmc->ocr_avail = AU1XMMC_OCR;
-
-               host = mmc_priv(mmc);
-               host->mmc = mmc;
-
-               host->id = i;
-               host->iobase = au1xmmc_card_table[host->id].iobase;
-               host->clock = 0;
-               host->power_mode = MMC_POWER_OFF;
-
-               host->flags = au1xmmc_card_inserted(host) ? HOST_F_ACTIVE : 0;
-               host->status = HOST_S_IDLE;
-
-               init_timer(&host->timer);
-
-               host->timer.function = au1xmmc_poll_event;
-               host->timer.data = (unsigned long) host;
-               host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT;
-
-               tasklet_init(&host->data_task, au1xmmc_tasklet_data,
-                               (unsigned long) host);
-
-               tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
-                               (unsigned long) host);
-
-               spin_lock_init(&host->lock);
-
-               if (dma != 0)
-                       au1xmmc_init_dma(host);
-
-               au1xmmc_reset_controller(host);
-
-               mmc_add_host(mmc);
-               au1xmmc_hosts[i] = host;
-
-               add_timer(&host->timer);
-
-               printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X (mode=%s)\n",
-                      host->id, host->iobase, dma ? "dma" : "pio");
-       }
-
-       enable_irq(AU1100_SD_IRQ);
-
-       return 0;
-}
-
-static int __devexit au1xmmc_remove(struct platform_device *pdev)
-{
-
-       int i;
-
-       disable_irq(AU1100_SD_IRQ);
-
-       for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
-               struct au1xmmc_host *host = au1xmmc_hosts[i];
-               if (!host) continue;
-
-               tasklet_kill(&host->data_task);
-               tasklet_kill(&host->finish_task);
-
-               del_timer_sync(&host->timer);
-               au1xmmc_set_power(host, 0);
-
-               mmc_remove_host(host->mmc);
-
-               au1xxx_dbdma_chan_free(host->tx_chan);
-               au1xxx_dbdma_chan_free(host->rx_chan);
-
-               au_writel(0x0, HOST_ENABLE(host));
-               au_sync();
-       }
-
-       free_irq(AU1100_SD_IRQ, 0);
-       return 0;
-}
-
-static struct platform_driver au1xmmc_driver = {
-       .probe         = au1xmmc_probe,
-       .remove        = au1xmmc_remove,
-       .suspend       = NULL,
-       .resume        = NULL,
-       .driver        = {
-               .name  = DRIVER_NAME,
-       },
-};
-
-static int __init au1xmmc_init(void)
-{
-       return platform_driver_register(&au1xmmc_driver);
-}
-
-static void __exit au1xmmc_exit(void)
-{
-       platform_driver_unregister(&au1xmmc_driver);
-}
-
-module_init(au1xmmc_init);
-module_exit(au1xmmc_exit);
-
-#ifdef MODULE
-MODULE_AUTHOR("Advanced Micro Devices, Inc");
-MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX");
-MODULE_LICENSE("GPL");
-#endif
-
diff --git a/drivers/mmc/au1xmmc.h b/drivers/mmc/au1xmmc.h
deleted file mode 100644 (file)
index 341cbdf..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifndef _AU1XMMC_H_
-#define _AU1XMMC_H_
-
-/* Hardware definitions */
-
-#define AU1XMMC_DESCRIPTOR_COUNT 1
-#define AU1XMMC_DESCRIPTOR_SIZE  2048
-
-#define AU1XMMC_OCR ( MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30  | \
-                     MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33  | \
-                     MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36)
-
-/* Easy access macros */
-
-#define HOST_STATUS(h) ((h)->iobase + SD_STATUS)
-#define HOST_CONFIG(h) ((h)->iobase + SD_CONFIG)
-#define HOST_ENABLE(h) ((h)->iobase + SD_ENABLE)
-#define HOST_TXPORT(h) ((h)->iobase + SD_TXPORT)
-#define HOST_RXPORT(h) ((h)->iobase + SD_RXPORT)
-#define HOST_CMDARG(h) ((h)->iobase + SD_CMDARG)
-#define HOST_BLKSIZE(h)        ((h)->iobase + SD_BLKSIZE)
-#define HOST_CMD(h)    ((h)->iobase + SD_CMD)
-#define HOST_CONFIG2(h)        ((h)->iobase + SD_CONFIG2)
-#define HOST_TIMEOUT(h)        ((h)->iobase + SD_TIMEOUT)
-#define HOST_DEBUG(h)  ((h)->iobase + SD_DEBUG)
-
-#define DMA_CHANNEL(h) \
-       ( ((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan)
-
-/* This gives us a hard value for the stop command that we can write directly
- * to the command register
- */
-
-#define STOP_CMD (SD_CMD_RT_1B|SD_CMD_CT_7|(0xC << SD_CMD_CI_SHIFT)|SD_CMD_GO)
-
-/* This is the set of interrupts that we configure by default */
-
-#if 0
-#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | SD_CONFIG_DD | \
-               SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
-#endif
-
-#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | \
-               SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
-/* The poll event (looking for insert/remove events runs twice a second */
-#define AU1XMMC_DETECT_TIMEOUT (HZ/2)
-
-struct au1xmmc_host {
-  struct mmc_host *mmc;
-  struct mmc_request *mrq;
-
-  u32 id;
-
-  u32 flags;
-  u32 iobase;
-  u32 clock;
-  u32 bus_width;
-  u32 power_mode;
-
-  int status;
-
-   struct {
-          int len;
-          int dir;
-  } dma;
-
-   struct {
-          int index;
-          int offset;
-          int len;
-  } pio;
-
-  u32 tx_chan;
-  u32 rx_chan;
-
-  struct timer_list timer;
-  struct tasklet_struct finish_task;
-  struct tasklet_struct data_task;
-
-  spinlock_t lock;
-};
-
-/* Status flags used by the host structure */
-
-#define HOST_F_XMIT   0x0001
-#define HOST_F_RECV   0x0002
-#define HOST_F_DMA    0x0010
-#define HOST_F_ACTIVE 0x0100
-#define HOST_F_STOP   0x1000
-
-#define HOST_S_IDLE   0x0001
-#define HOST_S_CMD    0x0002
-#define HOST_S_DATA   0x0003
-#define HOST_S_STOP   0x0004
-
-#endif
diff --git a/drivers/mmc/block.c b/drivers/mmc/block.c
deleted file mode 100644 (file)
index 8eba037..0000000
+++ /dev/null
@@ -1,668 +0,0 @@
-/*
- * Block driver for media (i.e., flash cards)
- *
- * Copyright 2002 Hewlett-Packard Company
- * Copyright 2005-2007 Pierre Ossman
- *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- * Many thanks to Alessandro Rubini and Jonathan Corbet!
- *
- * Author:  Andrew Christian
- *          28 May 2002
- */
-#include <linux/moduleparam.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/kdev_t.h>
-#include <linux/blkdev.h>
-#include <linux/mutex.h>
-#include <linux/scatterlist.h>
-
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
-#include <linux/mmc/host.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include "queue.h"
-
-/*
- * max 8 partitions per card
- */
-#define MMC_SHIFT      3
-
-static int major;
-
-/*
- * There is one mmc_blk_data per slot.
- */
-struct mmc_blk_data {
-       spinlock_t      lock;
-       struct gendisk  *disk;
-       struct mmc_queue queue;
-
-       unsigned int    usage;
-       unsigned int    block_bits;
-       unsigned int    read_only;
-};
-
-static DEFINE_MUTEX(open_lock);
-
-static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
-{
-       struct mmc_blk_data *md;
-
-       mutex_lock(&open_lock);
-       md = disk->private_data;
-       if (md && md->usage == 0)
-               md = NULL;
-       if (md)
-               md->usage++;
-       mutex_unlock(&open_lock);
-
-       return md;
-}
-
-static void mmc_blk_put(struct mmc_blk_data *md)
-{
-       mutex_lock(&open_lock);
-       md->usage--;
-       if (md->usage == 0) {
-               put_disk(md->disk);
-               kfree(md);
-       }
-       mutex_unlock(&open_lock);
-}
-
-static int mmc_blk_open(struct inode *inode, struct file *filp)
-{
-       struct mmc_blk_data *md;
-       int ret = -ENXIO;
-
-       md = mmc_blk_get(inode->i_bdev->bd_disk);
-       if (md) {
-               if (md->usage == 2)
-                       check_disk_change(inode->i_bdev);
-               ret = 0;
-
-               if ((filp->f_mode & FMODE_WRITE) && md->read_only)
-                       ret = -EROFS;
-       }
-
-       return ret;
-}
-
-static int mmc_blk_release(struct inode *inode, struct file *filp)
-{
-       struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data;
-
-       mmc_blk_put(md);
-       return 0;
-}
-
-static int
-mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
-       geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
-       geo->heads = 4;
-       geo->sectors = 16;
-       return 0;
-}
-
-static struct block_device_operations mmc_bdops = {
-       .open                   = mmc_blk_open,
-       .release                = mmc_blk_release,
-       .getgeo                 = mmc_blk_getgeo,
-       .owner                  = THIS_MODULE,
-};
-
-struct mmc_blk_request {
-       struct mmc_request      mrq;
-       struct mmc_command      cmd;
-       struct mmc_command      stop;
-       struct mmc_data         data;
-};
-
-static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req)
-{
-       struct mmc_blk_data *md = mq->data;
-       int stat = BLKPREP_OK;
-
-       /*
-        * If we have no device, we haven't finished initialising.
-        */
-       if (!md || !mq->card) {
-               printk(KERN_ERR "%s: killing request - no device/host\n",
-                      req->rq_disk->disk_name);
-               stat = BLKPREP_KILL;
-       }
-
-       return stat;
-}
-
-static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
-{
-       int err;
-       u32 blocks;
-
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
-       unsigned int timeout_us;
-
-       struct scatterlist sg;
-
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
-       cmd.opcode = MMC_APP_CMD;
-       cmd.arg = card->rca << 16;
-       cmd.flags = 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))
-               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;
-
-       memset(&data, 0, sizeof(struct mmc_data));
-
-       data.timeout_ns = card->csd.tacc_ns * 100;
-       data.timeout_clks = card->csd.tacc_clks * 100;
-
-       timeout_us = data.timeout_ns / 1000;
-       timeout_us += data.timeout_clks * 1000 /
-               (card->host->ios.clock / 1000);
-
-       if (timeout_us > 100000) {
-               data.timeout_ns = 100000000;
-               data.timeout_clks = 0;
-       }
-
-       data.blksz = 4;
-       data.blocks = 1;
-       data.flags = MMC_DATA_READ;
-       data.sg = &sg;
-       data.sg_len = 1;
-
-       memset(&mrq, 0, sizeof(struct mmc_request));
-
-       mrq.cmd = &cmd;
-       mrq.data = &data;
-
-       sg_init_one(&sg, &blocks, 4);
-
-       mmc_wait_for_req(card->host, &mrq);
-
-       if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE)
-               return (u32)-1;
-
-       blocks = ntohl(blocks);
-
-       return blocks;
-}
-
-static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
-{
-       struct mmc_blk_data *md = mq->data;
-       struct mmc_card *card = md->queue.card;
-       struct mmc_blk_request brq;
-       int ret = 1, sg_pos, data_size;
-
-       if (mmc_card_claim_host(card))
-               goto flush_queue;
-
-       do {
-               struct mmc_command cmd;
-               u32 readcmd, writecmd;
-
-               memset(&brq, 0, sizeof(struct mmc_blk_request));
-               brq.mrq.cmd = &brq.cmd;
-               brq.mrq.data = &brq.data;
-
-               brq.cmd.arg = req->sector;
-               if (!mmc_card_blockaddr(card))
-                       brq.cmd.arg <<= 9;
-               brq.cmd.flags = 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.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
-                * this rule as they support querying the number of
-                * successfully written sectors.
-                */
-               if (rq_data_dir(req) != READ &&
-                   !(card->host->caps & MMC_CAP_MULTIWRITE) &&
-                   !mmc_card_sd(card))
-                       brq.data.blocks = 1;
-
-               if (brq.data.blocks > 1) {
-                       brq.data.flags |= MMC_DATA_MULTI;
-                       brq.mrq.stop = &brq.stop;
-                       readcmd = MMC_READ_MULTIPLE_BLOCK;
-                       writecmd = MMC_WRITE_MULTIPLE_BLOCK;
-               } else {
-                       brq.mrq.stop = NULL;
-                       readcmd = MMC_READ_SINGLE_BLOCK;
-                       writecmd = MMC_WRITE_BLOCK;
-               }
-
-               if (rq_data_dir(req) == READ) {
-                       brq.cmd.opcode = readcmd;
-                       brq.data.flags |= MMC_DATA_READ;
-               } else {
-                       brq.cmd.opcode = writecmd;
-                       brq.data.flags |= MMC_DATA_WRITE;
-               }
-
-               brq.data.sg = mq->sg;
-               brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg);
-
-               if (brq.data.blocks !=
-                   (req->nr_sectors >> (md->block_bits - 9))) {
-                       data_size = brq.data.blocks * brq.data.blksz;
-                       for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) {
-                               data_size -= mq->sg[sg_pos].length;
-                               if (data_size <= 0) {
-                                       mq->sg[sg_pos].length += data_size;
-                                       sg_pos++;
-                                       break;
-                               }
-                       }
-                       brq.data.sg_len = sg_pos;
-               }
-
-               mmc_wait_for_req(card->host, &brq.mrq);
-               if (brq.cmd.error) {
-                       printk(KERN_ERR "%s: error %d sending read/write command\n",
-                              req->rq_disk->disk_name, brq.cmd.error);
-                       goto cmd_err;
-               }
-
-               if (brq.data.error) {
-                       printk(KERN_ERR "%s: error %d transferring data\n",
-                              req->rq_disk->disk_name, brq.data.error);
-                       goto cmd_err;
-               }
-
-               if (brq.stop.error) {
-                       printk(KERN_ERR "%s: error %d sending stop command\n",
-                              req->rq_disk->disk_name, brq.stop.error);
-                       goto cmd_err;
-               }
-
-               if (rq_data_dir(req) != READ) {
-                       do {
-                               int err;
-
-                               cmd.opcode = MMC_SEND_STATUS;
-                               cmd.arg = card->rca << 16;
-                               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-                               err = mmc_wait_for_cmd(card->host, &cmd, 5);
-                               if (err) {
-                                       printk(KERN_ERR "%s: error %d requesting status\n",
-                                              req->rq_disk->disk_name, err);
-                                       goto cmd_err;
-                               }
-                       } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
-
-#if 0
-                       if (cmd.resp[0] & ~0x00000900)
-                               printk(KERN_ERR "%s: status = %08x\n",
-                                      req->rq_disk->disk_name, cmd.resp[0]);
-                       if (mmc_decode_status(cmd.resp))
-                               goto cmd_err;
-#endif
-               }
-
-               /*
-                * A block was successfully transferred.
-                */
-               spin_lock_irq(&md->lock);
-               ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
-               if (!ret) {
-                       /*
-                        * The whole request completed successfully.
-                        */
-                       add_disk_randomness(req->rq_disk);
-                       blkdev_dequeue_request(req);
-                       end_that_request_last(req, 1);
-               }
-               spin_unlock_irq(&md->lock);
-       } while (ret);
-
-       mmc_card_release_host(card);
-
-       return 1;
-
- cmd_err:
-       /*
-        * If this is an SD card and we're writing, we can first
-        * mark the known good sectors as ok.
-        *
-        * If the card is not SD, we can still ok written sectors
-        * if the controller can do proper error reporting.
-        *
-        * For reads we just fail the entire chunk as that should
-        * be safe in all cases.
-        */
-       if (rq_data_dir(req) != READ && mmc_card_sd(card)) {
-               u32 blocks;
-               unsigned int bytes;
-
-               blocks = mmc_sd_num_wr_blocks(card);
-               if (blocks != (u32)-1) {
-                       if (card->csd.write_partial)
-                               bytes = blocks << md->block_bits;
-                       else
-                               bytes = blocks << 9;
-                       spin_lock_irq(&md->lock);
-                       ret = end_that_request_chunk(req, 1, bytes);
-                       spin_unlock_irq(&md->lock);
-               }
-       } else if (rq_data_dir(req) != READ &&
-                  (card->host->caps & MMC_CAP_MULTIWRITE)) {
-               spin_lock_irq(&md->lock);
-               ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
-               spin_unlock_irq(&md->lock);
-       }
-
-flush_queue:
-
-       mmc_card_release_host(card);
-
-       spin_lock_irq(&md->lock);
-       while (ret) {
-               ret = end_that_request_chunk(req, 0,
-                               req->current_nr_sectors << 9);
-       }
-
-       add_disk_randomness(req->rq_disk);
-       blkdev_dequeue_request(req);
-       end_that_request_last(req, 0);
-       spin_unlock_irq(&md->lock);
-
-       return 0;
-}
-
-#define MMC_NUM_MINORS (256 >> MMC_SHIFT)
-
-static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))];
-
-static inline int mmc_blk_readonly(struct mmc_card *card)
-{
-       return mmc_card_readonly(card) ||
-              !(card->csd.cmdclass & CCC_BLOCK_WRITE);
-}
-
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
-{
-       struct mmc_blk_data *md;
-       int devidx, ret;
-
-       devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
-       if (devidx >= MMC_NUM_MINORS)
-               return ERR_PTR(-ENOSPC);
-       __set_bit(devidx, dev_use);
-
-       md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
-       if (!md) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       memset(md, 0, sizeof(struct mmc_blk_data));
-
-       /*
-        * Set the read-only status based on the supported commands
-        * and the write protect switch.
-        */
-       md->read_only = mmc_blk_readonly(card);
-
-       /*
-        * Both SD and MMC specifications state (although a bit
-        * unclearly in the MMC case) that a block size of 512
-        * bytes must always be supported by the card.
-        */
-       md->block_bits = 9;
-
-       md->disk = alloc_disk(1 << MMC_SHIFT);
-       if (md->disk == NULL) {
-               ret = -ENOMEM;
-               goto err_kfree;
-       }
-
-       spin_lock_init(&md->lock);
-       md->usage = 1;
-
-       ret = mmc_init_queue(&md->queue, card, &md->lock);
-       if (ret)
-               goto err_putdisk;
-
-       md->queue.prep_fn = mmc_blk_prep_rq;
-       md->queue.issue_fn = mmc_blk_issue_rq;
-       md->queue.data = md;
-
-       md->disk->major = major;
-       md->disk->first_minor = devidx << MMC_SHIFT;
-       md->disk->fops = &mmc_bdops;
-       md->disk->private_data = md;
-       md->disk->queue = md->queue.queue;
-       md->disk->driverfs_dev = &card->dev;
-
-       /*
-        * As discussed on lkml, GENHD_FL_REMOVABLE should:
-        *
-        * - be set for removable media with permanent block devices
-        * - be unset for removable block devices with permanent media
-        *
-        * Since MMC block devices clearly fall under the second
-        * case, we do not set GENHD_FL_REMOVABLE.  Userspace
-        * should use the block device creation/destruction hotplug
-        * messages to tell when the card is present.
-        */
-
-       sprintf(md->disk->disk_name, "mmcblk%d", devidx);
-
-       blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
-
-       if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
-               /*
-                * The EXT_CSD sector count is in number or 512 byte
-                * sectors.
-                */
-               set_capacity(md->disk, card->ext_csd.sectors);
-       } else {
-               /*
-                * The CSD capacity field is in units of read_blkbits.
-                * set_capacity takes units of 512 bytes.
-                */
-               set_capacity(md->disk,
-                       card->csd.capacity << (card->csd.read_blkbits - 9));
-       }
-       return md;
-
- err_putdisk:
-       put_disk(md->disk);
- err_kfree:
-       kfree(md);
- out:
-       return ERR_PTR(ret);
-}
-
-static int
-mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
-{
-       struct mmc_command cmd;
-       int err;
-
-       /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
-       if (mmc_card_blockaddr(card))
-               return 0;
-
-       mmc_card_claim_host(card);
-       cmd.opcode = MMC_SET_BLOCKLEN;
-       cmd.arg = 1 << md->block_bits;
-       cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-       err = mmc_wait_for_cmd(card->host, &cmd, 5);
-       mmc_card_release_host(card);
-
-       if (err) {
-               printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
-                       md->disk->disk_name, cmd.arg, err);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int mmc_blk_probe(struct mmc_card *card)
-{
-       struct mmc_blk_data *md;
-       int err;
-
-       /*
-        * Check that the card supports the command class(es) we need.
-        */
-       if (!(card->csd.cmdclass & CCC_BLOCK_READ))
-               return -ENODEV;
-
-       md = mmc_blk_alloc(card);
-       if (IS_ERR(md))
-               return PTR_ERR(md);
-
-       err = mmc_blk_set_blksize(md, card);
-       if (err)
-               goto out;
-
-       printk(KERN_INFO "%s: %s %s %lluKiB %s\n",
-               md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
-               (unsigned long long)(get_capacity(md->disk) >> 1),
-               md->read_only ? "(ro)" : "");
-
-       mmc_set_drvdata(card, md);
-       add_disk(md->disk);
-       return 0;
-
- out:
-       mmc_blk_put(md);
-
-       return err;
-}
-
-static void mmc_blk_remove(struct mmc_card *card)
-{
-       struct mmc_blk_data *md = mmc_get_drvdata(card);
-
-       if (md) {
-               int devidx;
-
-               /* Stop new requests from getting into the queue */
-               del_gendisk(md->disk);
-
-               /* Then flush out any already in there */
-               mmc_cleanup_queue(&md->queue);
-
-               devidx = md->disk->first_minor >> MMC_SHIFT;
-               __clear_bit(devidx, dev_use);
-
-               mmc_blk_put(md);
-       }
-       mmc_set_drvdata(card, NULL);
-}
-
-#ifdef CONFIG_PM
-static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
-{
-       struct mmc_blk_data *md = mmc_get_drvdata(card);
-
-       if (md) {
-               mmc_queue_suspend(&md->queue);
-       }
-       return 0;
-}
-
-static int mmc_blk_resume(struct mmc_card *card)
-{
-       struct mmc_blk_data *md = mmc_get_drvdata(card);
-
-       if (md) {
-               mmc_blk_set_blksize(md, card);
-               mmc_queue_resume(&md->queue);
-       }
-       return 0;
-}
-#else
-#define        mmc_blk_suspend NULL
-#define mmc_blk_resume NULL
-#endif
-
-static struct mmc_driver mmc_driver = {
-       .drv            = {
-               .name   = "mmcblk",
-       },
-       .probe          = mmc_blk_probe,
-       .remove         = mmc_blk_remove,
-       .suspend        = mmc_blk_suspend,
-       .resume         = mmc_blk_resume,
-};
-
-static int __init mmc_blk_init(void)
-{
-       int res = -ENOMEM;
-
-       res = register_blkdev(major, "mmc");
-       if (res < 0) {
-               printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n",
-                      major, res);
-               goto out;
-       }
-       if (major == 0)
-               major = res;
-
-       return mmc_register_driver(&mmc_driver);
-
- out:
-       return res;
-}
-
-static void __exit mmc_blk_exit(void)
-{
-       mmc_unregister_driver(&mmc_driver);
-       unregister_blkdev(major, "mmc");
-}
-
-module_init(mmc_blk_init);
-module_exit(mmc_blk_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
-
-module_param(major, int, 0444);
-MODULE_PARM_DESC(major, "specify the major device number for MMC block driver");
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
new file mode 100644 (file)
index 0000000..01a9fd3
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# MMC/SD card drivers
+#
+
+comment "MMC/SD Card Drivers"
+       depends MMC
+
+config MMC_BLOCK
+       tristate "MMC block device driver"
+       depends on MMC && BLOCK
+       default y
+       help
+         Say Y here to enable the MMC block device driver support.
+         This provides a block device driver, which you can use to
+         mount the filesystem. Almost everyone wishing MMC support
+         should say Y or M here.
+
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile
new file mode 100644 (file)
index 0000000..cf8c939
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for MMC/SD card drivers
+#
+
+ifeq ($(CONFIG_MMC_DEBUG),y)
+       EXTRA_CFLAGS            += -DDEBUG
+endif
+
+obj-$(CONFIG_MMC_BLOCK)                += mmc_block.o
+mmc_block-objs                 := block.o queue.o
+
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
new file mode 100644 (file)
index 0000000..8eba037
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * Block driver for media (i.e., flash cards)
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ * Copyright 2005-2007 Pierre Ossman
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Author:  Andrew Christian
+ *          28 May 2002
+ */
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/mutex.h>
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "queue.h"
+
+/*
+ * max 8 partitions per card
+ */
+#define MMC_SHIFT      3
+
+static int major;
+
+/*
+ * There is one mmc_blk_data per slot.
+ */
+struct mmc_blk_data {
+       spinlock_t      lock;
+       struct gendisk  *disk;
+       struct mmc_queue queue;
+
+       unsigned int    usage;
+       unsigned int    block_bits;
+       unsigned int    read_only;
+};
+
+static DEFINE_MUTEX(open_lock);
+
+static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
+{
+       struct mmc_blk_data *md;
+
+       mutex_lock(&open_lock);
+       md = disk->private_data;
+       if (md && md->usage == 0)
+               md = NULL;
+       if (md)
+               md->usage++;
+       mutex_unlock(&open_lock);
+
+       return md;
+}
+
+static void mmc_blk_put(struct mmc_blk_data *md)
+{
+       mutex_lock(&open_lock);
+       md->usage--;
+       if (md->usage == 0) {
+               put_disk(md->disk);
+               kfree(md);
+       }
+       mutex_unlock(&open_lock);
+}
+
+static int mmc_blk_open(struct inode *inode, struct file *filp)
+{
+       struct mmc_blk_data *md;
+       int ret = -ENXIO;
+
+       md = mmc_blk_get(inode->i_bdev->bd_disk);
+       if (md) {
+               if (md->usage == 2)
+                       check_disk_change(inode->i_bdev);
+               ret = 0;
+
+               if ((filp->f_mode & FMODE_WRITE) && md->read_only)
+                       ret = -EROFS;
+       }
+
+       return ret;
+}
+
+static int mmc_blk_release(struct inode *inode, struct file *filp)
+{
+       struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data;
+
+       mmc_blk_put(md);
+       return 0;
+}
+
+static int
+mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
+       geo->heads = 4;
+       geo->sectors = 16;
+       return 0;
+}
+
+static struct block_device_operations mmc_bdops = {
+       .open                   = mmc_blk_open,
+       .release                = mmc_blk_release,
+       .getgeo                 = mmc_blk_getgeo,
+       .owner                  = THIS_MODULE,
+};
+
+struct mmc_blk_request {
+       struct mmc_request      mrq;
+       struct mmc_command      cmd;
+       struct mmc_command      stop;
+       struct mmc_data         data;
+};
+
+static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req)
+{
+       struct mmc_blk_data *md = mq->data;
+       int stat = BLKPREP_OK;
+
+       /*
+        * If we have no device, we haven't finished initialising.
+        */
+       if (!md || !mq->card) {
+               printk(KERN_ERR "%s: killing request - no device/host\n",
+                      req->rq_disk->disk_name);
+               stat = BLKPREP_KILL;
+       }
+
+       return stat;
+}
+
+static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+{
+       int err;
+       u32 blocks;
+
+       struct mmc_request mrq;
+       struct mmc_command cmd;
+       struct mmc_data data;
+       unsigned int timeout_us;
+
+       struct scatterlist sg;
+
+       memset(&cmd, 0, sizeof(struct mmc_command));
+
+       cmd.opcode = MMC_APP_CMD;
+       cmd.arg = card->rca << 16;
+       cmd.flags = 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))
+               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;
+
+       memset(&data, 0, sizeof(struct mmc_data));
+
+       data.timeout_ns = card->csd.tacc_ns * 100;
+       data.timeout_clks = card->csd.tacc_clks * 100;
+
+       timeout_us = data.timeout_ns / 1000;
+       timeout_us += data.timeout_clks * 1000 /
+               (card->host->ios.clock / 1000);
+
+       if (timeout_us > 100000) {
+               data.timeout_ns = 100000000;
+               data.timeout_clks = 0;
+       }
+
+       data.blksz = 4;
+       data.blocks = 1;
+       data.flags = MMC_DATA_READ;
+       data.sg = &sg;
+       data.sg_len = 1;
+
+       memset(&mrq, 0, sizeof(struct mmc_request));
+
+       mrq.cmd = &cmd;
+       mrq.data = &data;
+
+       sg_init_one(&sg, &blocks, 4);
+
+       mmc_wait_for_req(card->host, &mrq);
+
+       if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE)
+               return (u32)-1;
+
+       blocks = ntohl(blocks);
+
+       return blocks;
+}
+
+static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+{
+       struct mmc_blk_data *md = mq->data;
+       struct mmc_card *card = md->queue.card;
+       struct mmc_blk_request brq;
+       int ret = 1, sg_pos, data_size;
+
+       if (mmc_card_claim_host(card))
+               goto flush_queue;
+
+       do {
+               struct mmc_command cmd;
+               u32 readcmd, writecmd;
+
+               memset(&brq, 0, sizeof(struct mmc_blk_request));
+               brq.mrq.cmd = &brq.cmd;
+               brq.mrq.data = &brq.data;
+
+               brq.cmd.arg = req->sector;
+               if (!mmc_card_blockaddr(card))
+                       brq.cmd.arg <<= 9;
+               brq.cmd.flags = 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.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
+                * this rule as they support querying the number of
+                * successfully written sectors.
+                */
+               if (rq_data_dir(req) != READ &&
+                   !(card->host->caps & MMC_CAP_MULTIWRITE) &&
+                   !mmc_card_sd(card))
+                       brq.data.blocks = 1;
+
+               if (brq.data.blocks > 1) {
+                       brq.data.flags |= MMC_DATA_MULTI;
+                       brq.mrq.stop = &brq.stop;
+                       readcmd = MMC_READ_MULTIPLE_BLOCK;
+                       writecmd = MMC_WRITE_MULTIPLE_BLOCK;
+               } else {
+                       brq.mrq.stop = NULL;
+                       readcmd = MMC_READ_SINGLE_BLOCK;
+                       writecmd = MMC_WRITE_BLOCK;
+               }
+
+               if (rq_data_dir(req) == READ) {
+                       brq.cmd.opcode = readcmd;
+                       brq.data.flags |= MMC_DATA_READ;
+               } else {
+                       brq.cmd.opcode = writecmd;
+                       brq.data.flags |= MMC_DATA_WRITE;
+               }
+
+               brq.data.sg = mq->sg;
+               brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg);
+
+               if (brq.data.blocks !=
+                   (req->nr_sectors >> (md->block_bits - 9))) {
+                       data_size = brq.data.blocks * brq.data.blksz;
+                       for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) {
+                               data_size -= mq->sg[sg_pos].length;
+                               if (data_size <= 0) {
+                                       mq->sg[sg_pos].length += data_size;
+                                       sg_pos++;
+                                       break;
+                               }
+                       }
+                       brq.data.sg_len = sg_pos;
+               }
+
+               mmc_wait_for_req(card->host, &brq.mrq);
+               if (brq.cmd.error) {
+                       printk(KERN_ERR "%s: error %d sending read/write command\n",
+                              req->rq_disk->disk_name, brq.cmd.error);
+                       goto cmd_err;
+               }
+
+               if (brq.data.error) {
+                       printk(KERN_ERR "%s: error %d transferring data\n",
+                              req->rq_disk->disk_name, brq.data.error);
+                       goto cmd_err;
+               }
+
+               if (brq.stop.error) {
+                       printk(KERN_ERR "%s: error %d sending stop command\n",
+                              req->rq_disk->disk_name, brq.stop.error);
+                       goto cmd_err;
+               }
+
+               if (rq_data_dir(req) != READ) {
+                       do {
+                               int err;
+
+                               cmd.opcode = MMC_SEND_STATUS;
+                               cmd.arg = card->rca << 16;
+                               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+                               err = mmc_wait_for_cmd(card->host, &cmd, 5);
+                               if (err) {
+                                       printk(KERN_ERR "%s: error %d requesting status\n",
+                                              req->rq_disk->disk_name, err);
+                                       goto cmd_err;
+                               }
+                       } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
+
+#if 0
+                       if (cmd.resp[0] & ~0x00000900)
+                               printk(KERN_ERR "%s: status = %08x\n",
+                                      req->rq_disk->disk_name, cmd.resp[0]);
+                       if (mmc_decode_status(cmd.resp))
+                               goto cmd_err;
+#endif
+               }
+
+               /*
+                * A block was successfully transferred.
+                */
+               spin_lock_irq(&md->lock);
+               ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
+               if (!ret) {
+                       /*
+                        * The whole request completed successfully.
+                        */
+                       add_disk_randomness(req->rq_disk);
+                       blkdev_dequeue_request(req);
+                       end_that_request_last(req, 1);
+               }
+               spin_unlock_irq(&md->lock);
+       } while (ret);
+
+       mmc_card_release_host(card);
+
+       return 1;
+
+ cmd_err:
+       /*
+        * If this is an SD card and we're writing, we can first
+        * mark the known good sectors as ok.
+        *
+        * If the card is not SD, we can still ok written sectors
+        * if the controller can do proper error reporting.
+        *
+        * For reads we just fail the entire chunk as that should
+        * be safe in all cases.
+        */
+       if (rq_data_dir(req) != READ && mmc_card_sd(card)) {
+               u32 blocks;
+               unsigned int bytes;
+
+               blocks = mmc_sd_num_wr_blocks(card);
+               if (blocks != (u32)-1) {
+                       if (card->csd.write_partial)
+                               bytes = blocks << md->block_bits;
+                       else
+                               bytes = blocks << 9;
+                       spin_lock_irq(&md->lock);
+                       ret = end_that_request_chunk(req, 1, bytes);
+                       spin_unlock_irq(&md->lock);
+               }
+       } else if (rq_data_dir(req) != READ &&
+                  (card->host->caps & MMC_CAP_MULTIWRITE)) {
+               spin_lock_irq(&md->lock);
+               ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
+               spin_unlock_irq(&md->lock);
+       }
+
+flush_queue:
+
+       mmc_card_release_host(card);
+
+       spin_lock_irq(&md->lock);
+       while (ret) {
+               ret = end_that_request_chunk(req, 0,
+                               req->current_nr_sectors << 9);
+       }
+
+       add_disk_randomness(req->rq_disk);
+       blkdev_dequeue_request(req);
+       end_that_request_last(req, 0);
+       spin_unlock_irq(&md->lock);
+
+       return 0;
+}
+
+#define MMC_NUM_MINORS (256 >> MMC_SHIFT)
+
+static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))];
+
+static inline int mmc_blk_readonly(struct mmc_card *card)
+{
+       return mmc_card_readonly(card) ||
+              !(card->csd.cmdclass & CCC_BLOCK_WRITE);
+}
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+       struct mmc_blk_data *md;
+       int devidx, ret;
+
+       devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
+       if (devidx >= MMC_NUM_MINORS)
+               return ERR_PTR(-ENOSPC);
+       __set_bit(devidx, dev_use);
+
+       md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
+       if (!md) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       memset(md, 0, sizeof(struct mmc_blk_data));
+
+       /*
+        * Set the read-only status based on the supported commands
+        * and the write protect switch.
+        */
+       md->read_only = mmc_blk_readonly(card);
+
+       /*
+        * Both SD and MMC specifications state (although a bit
+        * unclearly in the MMC case) that a block size of 512
+        * bytes must always be supported by the card.
+        */
+       md->block_bits = 9;
+
+       md->disk = alloc_disk(1 << MMC_SHIFT);
+       if (md->disk == NULL) {
+               ret = -ENOMEM;
+               goto err_kfree;
+       }
+
+       spin_lock_init(&md->lock);
+       md->usage = 1;
+
+       ret = mmc_init_queue(&md->queue, card, &md->lock);
+       if (ret)
+               goto err_putdisk;
+
+       md->queue.prep_fn = mmc_blk_prep_rq;
+       md->queue.issue_fn = mmc_blk_issue_rq;
+       md->queue.data = md;
+
+       md->disk->major = major;
+       md->disk->first_minor = devidx << MMC_SHIFT;
+       md->disk->fops = &mmc_bdops;
+       md->disk->private_data = md;
+       md->disk->queue = md->queue.queue;
+       md->disk->driverfs_dev = &card->dev;
+
+       /*
+        * As discussed on lkml, GENHD_FL_REMOVABLE should:
+        *
+        * - be set for removable media with permanent block devices
+        * - be unset for removable block devices with permanent media
+        *
+        * Since MMC block devices clearly fall under the second
+        * case, we do not set GENHD_FL_REMOVABLE.  Userspace
+        * should use the block device creation/destruction hotplug
+        * messages to tell when the card is present.
+        */
+
+       sprintf(md->disk->disk_name, "mmcblk%d", devidx);
+
+       blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
+
+       if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
+               /*
+                * The EXT_CSD sector count is in number or 512 byte
+                * sectors.
+                */
+               set_capacity(md->disk, card->ext_csd.sectors);
+       } else {
+               /*
+                * The CSD capacity field is in units of read_blkbits.
+                * set_capacity takes units of 512 bytes.
+                */
+               set_capacity(md->disk,
+                       card->csd.capacity << (card->csd.read_blkbits - 9));
+       }
+       return md;
+
+ err_putdisk:
+       put_disk(md->disk);
+ err_kfree:
+       kfree(md);
+ out:
+       return ERR_PTR(ret);
+}
+
+static int
+mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
+{
+       struct mmc_command cmd;
+       int err;
+
+       /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
+       if (mmc_card_blockaddr(card))
+               return 0;
+
+       mmc_card_claim_host(card);
+       cmd.opcode = MMC_SET_BLOCKLEN;
+       cmd.arg = 1 << md->block_bits;
+       cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+       err = mmc_wait_for_cmd(card->host, &cmd, 5);
+       mmc_card_release_host(card);
+
+       if (err) {
+               printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
+                       md->disk->disk_name, cmd.arg, err);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int mmc_blk_probe(struct mmc_card *card)
+{
+       struct mmc_blk_data *md;
+       int err;
+
+       /*
+        * Check that the card supports the command class(es) we need.
+        */
+       if (!(card->csd.cmdclass & CCC_BLOCK_READ))
+               return -ENODEV;
+
+       md = mmc_blk_alloc(card);
+       if (IS_ERR(md))
+               return PTR_ERR(md);
+
+       err = mmc_blk_set_blksize(md, card);
+       if (err)
+               goto out;
+
+       printk(KERN_INFO "%s: %s %s %lluKiB %s\n",
+               md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
+               (unsigned long long)(get_capacity(md->disk) >> 1),
+               md->read_only ? "(ro)" : "");
+
+       mmc_set_drvdata(card, md);
+       add_disk(md->disk);
+       return 0;
+
+ out:
+       mmc_blk_put(md);
+
+       return err;
+}
+
+static void mmc_blk_remove(struct mmc_card *card)
+{
+       struct mmc_blk_data *md = mmc_get_drvdata(card);
+
+       if (md) {
+               int devidx;
+
+               /* Stop new requests from getting into the queue */
+               del_gendisk(md->disk);
+
+               /* Then flush out any already in there */
+               mmc_cleanup_queue(&md->queue);
+
+               devidx = md->disk->first_minor >> MMC_SHIFT;
+               __clear_bit(devidx, dev_use);
+
+               mmc_blk_put(md);
+       }
+       mmc_set_drvdata(card, NULL);
+}
+
+#ifdef CONFIG_PM
+static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
+{
+       struct mmc_blk_data *md = mmc_get_drvdata(card);
+
+       if (md) {
+               mmc_queue_suspend(&md->queue);
+       }
+       return 0;
+}
+
+static int mmc_blk_resume(struct mmc_card *card)
+{
+       struct mmc_blk_data *md = mmc_get_drvdata(card);
+
+       if (md) {
+               mmc_blk_set_blksize(md, card);
+               mmc_queue_resume(&md->queue);
+       }
+       return 0;
+}
+#else
+#define        mmc_blk_suspend NULL
+#define mmc_blk_resume NULL
+#endif
+
+static struct mmc_driver mmc_driver = {
+       .drv            = {
+               .name   = "mmcblk",
+       },
+       .probe          = mmc_blk_probe,
+       .remove         = mmc_blk_remove,
+       .suspend        = mmc_blk_suspend,
+       .resume         = mmc_blk_resume,
+};
+
+static int __init mmc_blk_init(void)
+{
+       int res = -ENOMEM;
+
+       res = register_blkdev(major, "mmc");
+       if (res < 0) {
+               printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n",
+                      major, res);
+               goto out;
+       }
+       if (major == 0)
+               major = res;
+
+       return mmc_register_driver(&mmc_driver);
+
+ out:
+       return res;
+}
+
+static void __exit mmc_blk_exit(void)
+{
+       mmc_unregister_driver(&mmc_driver);
+       unregister_blkdev(major, "mmc");
+}
+
+module_init(mmc_blk_init);
+module_exit(mmc_blk_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
+
+module_param(major, int, 0444);
+MODULE_PARM_DESC(major, "specify the major device number for MMC block driver");
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
new file mode 100644 (file)
index 0000000..aa75ac1
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ *  linux/drivers/mmc/queue.c
+ *
+ *  Copyright (C) 2003 Russell King, All Rights Reserved.
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * 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/module.h>
+#include <linux/blkdev.h>
+#include <linux/kthread.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include "queue.h"
+
+#define MMC_QUEUE_SUSPENDED    (1 << 0)
+
+/*
+ * Prepare a MMC request.  Essentially, this means passing the
+ * preparation off to the media driver.  The media driver will
+ * create a mmc_io_request in req->special.
+ */
+static int mmc_prep_request(struct request_queue *q, struct request *req)
+{
+       struct mmc_queue *mq = q->queuedata;
+       int ret = BLKPREP_KILL;
+
+       if (blk_special_request(req)) {
+               /*
+                * Special commands already have the command
+                * blocks already setup in req->special.
+                */
+               BUG_ON(!req->special);
+
+               ret = BLKPREP_OK;
+       } else if (blk_fs_request(req) || blk_pc_request(req)) {
+               /*
+                * Block I/O requests need translating according
+                * to the protocol.
+                */
+               ret = mq->prep_fn(mq, req);
+       } else {
+               /*
+                * Everything else is invalid.
+                */
+               blk_dump_rq_flags(req, "MMC bad request");
+       }
+
+       if (ret == BLKPREP_OK)
+               req->cmd_flags |= REQ_DONTPREP;
+
+       return ret;
+}
+
+static int mmc_queue_thread(void *d)
+{
+       struct mmc_queue *mq = d;
+       struct request_queue *q = mq->queue;
+
+       /*
+        * Set iothread to ensure that we aren't put to sleep by
+        * the process freezing.  We handle suspension ourselves.
+        */
+       current->flags |= PF_MEMALLOC|PF_NOFREEZE;
+
+       down(&mq->thread_sem);
+       do {
+               struct request *req = NULL;
+
+               spin_lock_irq(q->queue_lock);
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (!blk_queue_plugged(q))
+                       req = elv_next_request(q);
+               mq->req = req;
+               spin_unlock_irq(q->queue_lock);
+
+               if (!req) {
+                       if (kthread_should_stop()) {
+                               set_current_state(TASK_RUNNING);
+                               break;
+                       }
+                       up(&mq->thread_sem);
+                       schedule();
+                       down(&mq->thread_sem);
+                       continue;
+               }
+               set_current_state(TASK_RUNNING);
+
+               mq->issue_fn(mq, req);
+       } while (1);
+       up(&mq->thread_sem);
+
+       return 0;
+}
+
+/*
+ * Generic MMC request handler.  This is called for any queue on a
+ * particular host.  When the host is not busy, we look for a request
+ * on any queue on this host, and attempt to issue it.  This may
+ * not be the queue we were asked to process.
+ */
+static void mmc_request(request_queue_t *q)
+{
+       struct mmc_queue *mq = q->queuedata;
+       struct request *req;
+       int ret;
+
+       if (!mq) {
+               printk(KERN_ERR "MMC: killing requests for dead queue\n");
+               while ((req = elv_next_request(q)) != NULL) {
+                       do {
+                               ret = end_that_request_chunk(req, 0,
+                                       req->current_nr_sectors << 9);
+                       } while (ret);
+               }
+               return;
+       }
+
+       if (!mq->req)
+               wake_up_process(mq->thread);
+}
+
+/**
+ * mmc_init_queue - initialise a queue structure.
+ * @mq: mmc queue
+ * @card: mmc card to attach this queue
+ * @lock: queue lock
+ *
+ * Initialise a MMC card request queue.
+ */
+int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)
+{
+       struct mmc_host *host = card->host;
+       u64 limit = BLK_BOUNCE_HIGH;
+       int ret;
+
+       if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
+               limit = *mmc_dev(host)->dma_mask;
+
+       mq->card = card;
+       mq->queue = blk_init_queue(mmc_request, lock);
+       if (!mq->queue)
+               return -ENOMEM;
+
+       blk_queue_prep_rq(mq->queue, mmc_prep_request);
+       blk_queue_bounce_limit(mq->queue, limit);
+       blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
+       blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
+       blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
+       blk_queue_max_segment_size(mq->queue, host->max_seg_size);
+
+       mq->queue->queuedata = mq;
+       mq->req = NULL;
+
+       mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs,
+                        GFP_KERNEL);
+       if (!mq->sg) {
+               ret = -ENOMEM;
+               goto cleanup_queue;
+       }
+
+       init_MUTEX(&mq->thread_sem);
+
+       mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");
+       if (IS_ERR(mq->thread)) {
+               ret = PTR_ERR(mq->thread);
+               goto free_sg;
+       }
+
+       return 0;
+
+ free_sg:
+       kfree(mq->sg);
+       mq->sg = NULL;
+ cleanup_queue:
+       blk_cleanup_queue(mq->queue);
+       return ret;
+}
+
+void mmc_cleanup_queue(struct mmc_queue *mq)
+{
+       request_queue_t *q = mq->queue;
+       unsigned long flags;
+
+       /* Mark that we should start throwing out stragglers */
+       spin_lock_irqsave(q->queue_lock, flags);
+       q->queuedata = NULL;
+       spin_unlock_irqrestore(q->queue_lock, flags);
+
+       /* Then terminate our worker thread */
+       kthread_stop(mq->thread);
+
+       kfree(mq->sg);
+       mq->sg = NULL;
+
+       blk_cleanup_queue(mq->queue);
+
+       mq->card = NULL;
+}
+EXPORT_SYMBOL(mmc_cleanup_queue);
+
+/**
+ * mmc_queue_suspend - suspend a MMC request queue
+ * @mq: MMC queue to suspend
+ *
+ * Stop the block request queue, and wait for our thread to
+ * complete any outstanding requests.  This ensures that we
+ * won't suspend while a request is being processed.
+ */
+void mmc_queue_suspend(struct mmc_queue *mq)
+{
+       request_queue_t *q = mq->queue;
+       unsigned long flags;
+
+       if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
+               mq->flags |= MMC_QUEUE_SUSPENDED;
+
+               spin_lock_irqsave(q->queue_lock, flags);
+               blk_stop_queue(q);
+               spin_unlock_irqrestore(q->queue_lock, flags);
+
+               down(&mq->thread_sem);
+       }
+}
+
+/**
+ * mmc_queue_resume - resume a previously suspended MMC request queue
+ * @mq: MMC queue to resume
+ */
+void mmc_queue_resume(struct mmc_queue *mq)
+{
+       request_queue_t *q = mq->queue;
+       unsigned long flags;
+
+       if (mq->flags & MMC_QUEUE_SUSPENDED) {
+               mq->flags &= ~MMC_QUEUE_SUSPENDED;
+
+               up(&mq->thread_sem);
+
+               spin_lock_irqsave(q->queue_lock, flags);
+               blk_start_queue(q);
+               spin_unlock_irqrestore(q->queue_lock, flags);
+       }
+}
+
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
new file mode 100644 (file)
index 0000000..c9f139e
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef MMC_QUEUE_H
+#define MMC_QUEUE_H
+
+struct request;
+struct task_struct;
+
+struct mmc_queue {
+       struct mmc_card         *card;
+       struct task_struct      *thread;
+       struct semaphore        thread_sem;
+       unsigned int            flags;
+       struct request          *req;
+       int                     (*prep_fn)(struct mmc_queue *, struct request *);
+       int                     (*issue_fn)(struct mmc_queue *, struct request *);
+       void                    *data;
+       struct request_queue    *queue;
+       struct scatterlist      *sg;
+};
+
+struct mmc_io_request {
+       struct request          *rq;
+       int                     num;
+       struct mmc_command      selcmd;         /* mmc_queue private */
+       struct mmc_command      cmd[4];         /* max 4 commands */
+};
+
+extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
+extern void mmc_cleanup_queue(struct mmc_queue *);
+extern void mmc_queue_suspend(struct mmc_queue *);
+extern void mmc_queue_resume(struct mmc_queue *);
+
+#endif
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
new file mode 100644 (file)
index 0000000..ed4deab
--- /dev/null
@@ -0,0 +1,103 @@
+#
+# MMC/SD host controller drivers
+#
+
+comment "MMC/SD Host Controller Drivers"
+       depends on MMC
+
+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.
+
+config MMC_PXA
+       tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
+       depends on ARCH_PXA && MMC
+       help
+         This selects the Intel(R) PXA(R) Multimedia card Interface.
+         If you have a PXA(R) platform with a Multimedia Card slot,
+         say Y or M here.
+
+         If unsure, say N.
+
+config MMC_SDHCI
+       tristate "Secure Digital Host Controller Interface support  (EXPERIMENTAL)"
+       depends on PCI && MMC && EXPERIMENTAL
+       help
+         This select the generic Secure Digital Host Controller Interface.
+         It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
+         and Toshiba(R). Most controllers found in laptops are of this type.
+         If you have a controller with this interface, say Y or M here.
+
+         If unsure, say N.
+
+config MMC_OMAP
+       tristate "TI OMAP Multimedia Card Interface support"
+       depends on ARCH_OMAP && MMC
+       select TPS65010 if MACH_OMAP_H2
+       help
+         This selects the TI OMAP Multimedia card Interface.
+         If you have an OMAP board 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
+       help
+         This selects the Winbond(R) W83L51xD Secure digital and
+          Multimedia card Interface.
+         If you have a machine with a integrated W83L518D or W83L519D
+         SD/MMC card reader, say Y or M here.
+
+         If unsure, say N.
+
+config MMC_AU1X
+       tristate "Alchemy AU1XX0 MMC Card Interface support"
+       depends on MMC && SOC_AU1200
+       help
+         This selects the AMD Alchemy(R) Multimedia card interface.
+         If you have a Alchemy platform with a MMC slot, say Y or M here.
+
+         If unsure, say N.
+
+config MMC_AT91
+       tristate "AT91 SD/MMC Card Interface support"
+       depends on ARCH_AT91 && MMC
+       help
+         This selects the AT91 MCI controller.
+
+         If unsure, say N.
+
+config MMC_IMX
+       tristate "Motorola i.MX Multimedia Card Interface support"
+       depends on ARCH_IMX && MMC
+       help
+         This selects the Motorola i.MX Multimedia card Interface.
+         If you have a i.MX platform with a Multimedia Card slot,
+         say Y or M here.
+
+         If unsure, say N.
+
+config MMC_TIFM_SD
+       tristate "TI Flash Media MMC/SD Interface support  (EXPERIMENTAL)"
+       depends on MMC && EXPERIMENTAL && PCI
+       select TIFM_CORE
+       help
+         Say Y here if you want to be able to access MMC/SD cards with
+         the Texas Instruments(R) Flash Media card reader, found in many
+         laptops.
+         This option 'selects' (turns on, enables) 'TIFM_CORE', but you
+         probably also need appropriate card reader host adapter, such as
+         'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support
+         (TIFM_7XX1)'.
+
+          To compile this driver as a module, choose M here: the
+         module will be called tifm_sd.
+
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
new file mode 100644 (file)
index 0000000..6685f64
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for MMC/SD host controller drivers
+#
+
+ifeq ($(CONFIG_MMC_DEBUG),y)
+       EXTRA_CFLAGS            += -DDEBUG
+endif
+
+obj-$(CONFIG_MMC_ARMMMCI)      += mmci.o
+obj-$(CONFIG_MMC_PXA)          += pxamci.o
+obj-$(CONFIG_MMC_IMX)          += imxmmc.o
+obj-$(CONFIG_MMC_SDHCI)                += sdhci.o
+obj-$(CONFIG_MMC_WBSD)         += wbsd.o
+obj-$(CONFIG_MMC_AU1X)         += au1xmmc.o
+obj-$(CONFIG_MMC_OMAP)         += omap.o
+obj-$(CONFIG_MMC_AT91)         += at91_mci.o
+obj-$(CONFIG_MMC_TIFM_SD)      += tifm_sd.o
+
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
new file mode 100644 (file)
index 0000000..e37943c
--- /dev/null
@@ -0,0 +1,1001 @@
+/*
+ *  linux/drivers/mmc/at91_mci.c - ATMEL AT91 MCI Driver
+ *
+ *  Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
+ *
+ *  Copyright (C) 2006 Malcolm Noyes
+ *
+ * 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.
+ */
+
+/*
+   This is the AT91 MCI driver that has been tested with both MMC cards
+   and SD-cards.  Boards that support write protect are now supported.
+   The CCAT91SBC001 board does not support SD cards.
+
+   The three entry points are at91_mci_request, at91_mci_set_ios
+   and at91_mci_get_ro.
+
+   SET IOS
+     This configures the device to put it into the correct mode and clock speed
+     required.
+
+   MCI REQUEST
+     MCI request processes the commands sent in the mmc_request structure. This
+     can consist of a processing command and a stop command in the case of
+     multiple block transfers.
+
+     There are three main types of request, commands, reads and writes.
+
+     Commands are straight forward. The command is submitted to the controller and
+     the request function returns. When the controller generates an interrupt to indicate
+     the command is finished, the response to the command are read and the mmc_request_done
+     function called to end the request.
+
+     Reads and writes work in a similar manner to normal commands but involve the PDC (DMA)
+     controller to manage the transfers.
+
+     A read is done from the controller directly to the scatterlist passed in from the request.
+     Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte
+     swapped in the scatterlist buffers.  AT91SAM926x are not affected by this bug.
+
+     The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
+
+     A write is slightly different in that the bytes to write are read from the scatterlist
+     into a dma memory buffer (this is in case the source buffer should be read only). The
+     entire write buffer is then done from this single dma memory buffer.
+
+     The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY
+
+   GET RO
+     Gets the status of the write protect pin, if available.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/atmel_pdc.h>
+
+#include <linux/mmc/host.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/mmc.h>
+#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91_mci.h>
+
+#define DRIVER_NAME "at91_mci"
+
+#undef SUPPORT_4WIRE
+
+#define FL_SENT_COMMAND        (1 << 0)
+#define FL_SENT_STOP   (1 << 1)
+
+#define AT91_MCI_ERRORS        (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE       \
+               | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE               \
+               | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)                        
+
+#define at91_mci_read(host, reg)       __raw_readl((host)->baseaddr + (reg))
+#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg))
+
+
+/*
+ * Low level type for this driver
+ */
+struct at91mci_host
+{
+       struct mmc_host *mmc;
+       struct mmc_command *cmd;
+       struct mmc_request *request;
+
+       void __iomem *baseaddr;
+       int irq;
+
+       struct at91_mmc_data *board;
+       int present;
+
+       struct clk *mci_clk;
+
+       /*
+        * Flag indicating when the command has been sent. This is used to
+        * work out whether or not to send the stop
+        */
+       unsigned int flags;
+       /* flag for current bus settings */
+       u32 bus_mode;
+
+       /* DMA buffer used for transmitting */
+       unsigned int* buffer;
+       dma_addr_t physical_address;
+       unsigned int total_length;
+
+       /* Latest in the scatterlist that has been enabled for transfer, but not freed */
+       int in_use_index;
+
+       /* Latest in the scatterlist that has been enabled for transfer */
+       int transfer_index;
+};
+
+/*
+ * Copy from sg to a dma block - used for transfers
+ */
+static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)
+{
+       unsigned int len, i, size;
+       unsigned *dmabuf = host->buffer;
+
+       size = host->total_length;
+       len = data->sg_len;
+
+       /*
+        * Just loop through all entries. Size might not
+        * be the entire list though so make sure that
+        * we do not transfer too much.
+        */
+       for (i = 0; i < len; i++) {
+               struct scatterlist *sg;
+               int amount;
+               unsigned int *sgbuffer;
+
+               sg = &data->sg[i];
+
+               sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+               amount = min(size, sg->length);
+               size -= amount;
+
+               if (cpu_is_at91rm9200()) {      /* AT91RM9200 errata */
+                       int index;
+
+                       for (index = 0; index < (amount / 4); index++)
+                               *dmabuf++ = swab32(sgbuffer[index]);
+               }
+               else
+                       memcpy(dmabuf, sgbuffer, amount);
+
+               kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
+
+               if (size == 0)
+                       break;
+       }
+
+       /*
+        * Check that we didn't get a request to transfer
+        * more data than can fit into the SG list.
+        */
+       BUG_ON(size != 0);
+}
+
+/*
+ * Prepare a dma read
+ */
+static void at91mci_pre_dma_read(struct at91mci_host *host)
+{
+       int i;
+       struct scatterlist *sg;
+       struct mmc_command *cmd;
+       struct mmc_data *data;
+
+       pr_debug("pre dma read\n");
+
+       cmd = host->cmd;
+       if (!cmd) {
+               pr_debug("no command\n");
+               return;
+       }
+
+       data = cmd->data;
+       if (!data) {
+               pr_debug("no data\n");
+               return;
+       }
+
+       for (i = 0; i < 2; i++) {
+               /* nothing left to transfer */
+               if (host->transfer_index >= data->sg_len) {
+                       pr_debug("Nothing left to transfer (index = %d)\n", host->transfer_index);
+                       break;
+               }
+
+               /* Check to see if this needs filling */
+               if (i == 0) {
+                       if (at91_mci_read(host, ATMEL_PDC_RCR) != 0) {
+                               pr_debug("Transfer active in current\n");
+                               continue;
+                       }
+               }
+               else {
+                       if (at91_mci_read(host, ATMEL_PDC_RNCR) != 0) {
+                               pr_debug("Transfer active in next\n");
+                               continue;
+                       }
+               }
+
+               /* Setup the next transfer */
+               pr_debug("Using transfer index %d\n", host->transfer_index);
+
+               sg = &data->sg[host->transfer_index++];
+               pr_debug("sg = %p\n", sg);
+
+               sg->dma_address = dma_map_page(NULL, sg->page, sg->offset, sg->length, DMA_FROM_DEVICE);
+
+               pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
+
+               if (i == 0) {
+                       at91_mci_write(host, ATMEL_PDC_RPR, sg->dma_address);
+                       at91_mci_write(host, ATMEL_PDC_RCR, sg->length / 4);
+               }
+               else {
+                       at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address);
+                       at91_mci_write(host, ATMEL_PDC_RNCR, sg->length / 4);
+               }
+       }
+
+       pr_debug("pre dma read done\n");
+}
+
+/*
+ * Handle after a dma read
+ */
+static void at91mci_post_dma_read(struct at91mci_host *host)
+{
+       struct mmc_command *cmd;
+       struct mmc_data *data;
+
+       pr_debug("post dma read\n");
+
+       cmd = host->cmd;
+       if (!cmd) {
+               pr_debug("no command\n");
+               return;
+       }
+
+       data = cmd->data;
+       if (!data) {
+               pr_debug("no data\n");
+               return;
+       }
+
+       while (host->in_use_index < host->transfer_index) {
+               unsigned int *buffer;
+
+               struct scatterlist *sg;
+
+               pr_debug("finishing index %d\n", host->in_use_index);
+
+               sg = &data->sg[host->in_use_index++];
+
+               pr_debug("Unmapping page %08X\n", sg->dma_address);
+
+               dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE);
+
+               /* Swap the contents of the buffer */
+               buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+               pr_debug("buffer = %p, length = %d\n", buffer, sg->length);
+
+               data->bytes_xfered += sg->length;
+
+               if (cpu_is_at91rm9200()) {      /* AT91RM9200 errata */
+                       int index;
+
+                       for (index = 0; index < (sg->length / 4); index++)
+                               buffer[index] = swab32(buffer[index]);
+               }
+
+               kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
+               flush_dcache_page(sg->page);
+       }
+
+       /* Is there another transfer to trigger? */
+       if (host->transfer_index < data->sg_len)
+               at91mci_pre_dma_read(host);
+       else {
+               at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
+               at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+       }
+
+       pr_debug("post dma read done\n");
+}
+
+/*
+ * Handle transmitted data
+ */
+static void at91_mci_handle_transmitted(struct at91mci_host *host)
+{
+       struct mmc_command *cmd;
+       struct mmc_data *data;
+
+       pr_debug("Handling the transmit\n");
+
+       /* Disable the transfer */
+       at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+
+       /* Now wait for cmd ready */
+       at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
+       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
+
+       cmd = host->cmd;
+       if (!cmd) return;
+
+       data = cmd->data;
+       if (!data) return;
+
+       data->bytes_xfered = host->total_length;
+}
+
+/*
+ * Enable the controller
+ */
+static void at91_mci_enable(struct at91mci_host *host)
+{
+       at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
+       at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
+       at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
+       at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a);
+
+       /* use Slot A or B (only one at same time) */
+       at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
+}
+
+/*
+ * Disable the controller
+ */
+static void at91_mci_disable(struct at91mci_host *host)
+{
+       at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
+}
+
+/*
+ * Send a command
+ * return the interrupts to enable
+ */
+static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)
+{
+       unsigned int cmdr, mr;
+       unsigned int block_length;
+       struct mmc_data *data = cmd->data;
+
+       unsigned int blocks;
+       unsigned int ier = 0;
+
+       host->cmd = cmd;
+
+       /* Not sure if this is needed */
+#if 0
+       if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
+               pr_debug("Clearing timeout\n");
+               at91_mci_write(host, AT91_MCI_ARGR, 0);
+               at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
+               while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
+                       /* spin */
+                       pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
+               }
+       }
+#endif
+       cmdr = cmd->opcode;
+
+       if (mmc_resp_type(cmd) == MMC_RSP_NONE)
+               cmdr |= AT91_MCI_RSPTYP_NONE;
+       else {
+               /* if a response is expected then allow maximum response latancy */
+               cmdr |= AT91_MCI_MAXLAT;
+               /* set 136 bit response for R2, 48 bit response otherwise */
+               if (mmc_resp_type(cmd) == MMC_RSP_R2)
+                       cmdr |= AT91_MCI_RSPTYP_136;
+               else
+                       cmdr |= AT91_MCI_RSPTYP_48;
+       }
+
+       if (data) {
+               block_length = data->blksz;
+               blocks = data->blocks;
+
+               /* always set data start - also set direction flag for read */
+               if (data->flags & MMC_DATA_READ)
+                       cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START);
+               else if (data->flags & MMC_DATA_WRITE)
+                       cmdr |= AT91_MCI_TRCMD_START;
+
+               if (data->flags & MMC_DATA_STREAM)
+                       cmdr |= AT91_MCI_TRTYP_STREAM;
+               if (data->flags & MMC_DATA_MULTI)
+                       cmdr |= AT91_MCI_TRTYP_MULTIPLE;
+       }
+       else {
+               block_length = 0;
+               blocks = 0;
+       }
+
+       if (cmd->opcode == MMC_STOP_TRANSMISSION)
+               cmdr |= AT91_MCI_TRCMD_STOP;
+
+       if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
+               cmdr |= AT91_MCI_OPDCMD;
+
+       /*
+        * Set the arguments and send the command
+        */
+       pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
+               cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
+
+       if (!data) {
+               at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS);
+               at91_mci_write(host, ATMEL_PDC_RPR, 0);
+               at91_mci_write(host, ATMEL_PDC_RCR, 0);
+               at91_mci_write(host, ATMEL_PDC_RNPR, 0);
+               at91_mci_write(host, ATMEL_PDC_RNCR, 0);
+               at91_mci_write(host, ATMEL_PDC_TPR, 0);
+               at91_mci_write(host, ATMEL_PDC_TCR, 0);
+               at91_mci_write(host, ATMEL_PDC_TNPR, 0);
+               at91_mci_write(host, ATMEL_PDC_TNCR, 0);
+
+               at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
+               at91_mci_write(host, AT91_MCI_CMDR, cmdr);
+               return AT91_MCI_CMDRDY;
+       }
+
+       mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */
+       at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
+
+       /*
+        * Disable the PDC controller
+        */
+       at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+
+       if (cmdr & AT91_MCI_TRCMD_START) {
+               data->bytes_xfered = 0;
+               host->transfer_index = 0;
+               host->in_use_index = 0;
+               if (cmdr & AT91_MCI_TRDIR) {
+                       /*
+                        * Handle a read
+                        */
+                       host->buffer = NULL;
+                       host->total_length = 0;
+
+                       at91mci_pre_dma_read(host);
+                       ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;
+               }
+               else {
+                       /*
+                        * Handle a write
+                        */
+                       host->total_length = block_length * blocks;
+                       host->buffer = dma_alloc_coherent(NULL,
+                                                 host->total_length,
+                                                 &host->physical_address, GFP_KERNEL);
+
+                       at91mci_sg_to_dma(host, data);
+
+                       pr_debug("Transmitting %d bytes\n", host->total_length);
+
+                       at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
+                       at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4);
+                       ier = AT91_MCI_TXBUFE;
+               }
+       }
+
+       /*
+        * Send the command and then enable the PDC - not the other way round as
+        * the data sheet says
+        */
+
+       at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
+       at91_mci_write(host, AT91_MCI_CMDR, cmdr);
+
+       if (cmdr & AT91_MCI_TRCMD_START) {
+               if (cmdr & AT91_MCI_TRDIR)
+                       at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
+               else
+                       at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
+       }
+       return ier;
+}
+
+/*
+ * Wait for a command to complete
+ */
+static void at91mci_process_command(struct at91mci_host *host, struct mmc_command *cmd)
+{
+       unsigned int ier;
+
+       ier = at91_mci_send_command(host, cmd);
+
+       pr_debug("setting ier to %08X\n", ier);
+
+       /* Stop on errors or the required value */
+       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
+}
+
+/*
+ * Process the next step in the request
+ */
+static void at91mci_process_next(struct at91mci_host *host)
+{
+       if (!(host->flags & FL_SENT_COMMAND)) {
+               host->flags |= FL_SENT_COMMAND;
+               at91mci_process_command(host, host->request->cmd);
+       }
+       else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {
+               host->flags |= FL_SENT_STOP;
+               at91mci_process_command(host, host->request->stop);
+       }
+       else
+               mmc_request_done(host->mmc, host->request);
+}
+
+/*
+ * Handle a command that has been completed
+ */
+static void at91mci_completed_command(struct at91mci_host *host)
+{
+       struct mmc_command *cmd = host->cmd;
+       unsigned int status;
+
+       at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
+
+       cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
+       cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
+       cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
+       cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
+
+       if (host->buffer) {
+               dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address);
+               host->buffer = NULL;
+       }
+
+       status = at91_mci_read(host, AT91_MCI_SR);
+
+       pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
+                status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+
+       if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE |
+                       AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
+                       AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
+               if ((status & AT91_MCI_RCRCE) &&
+                       ((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) {
+                       cmd->error = MMC_ERR_NONE;
+               }
+               else {
+                       if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE))
+                               cmd->error = MMC_ERR_TIMEOUT;
+                       else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE))
+                               cmd->error = MMC_ERR_BADCRC;
+                       else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE))
+                               cmd->error = MMC_ERR_FIFO;
+                       else
+                               cmd->error = MMC_ERR_FAILED;
+
+                       pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n",
+                                cmd->error, cmd->opcode, cmd->retries);
+               }
+       }
+       else
+               cmd->error = MMC_ERR_NONE;
+
+       at91mci_process_next(host);
+}
+
+/*
+ * Handle an MMC request
+ */
+static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct at91mci_host *host = mmc_priv(mmc);
+       host->request = mrq;
+       host->flags = 0;
+
+       at91mci_process_next(host);
+}
+
+/*
+ * Set the IOS
+ */
+static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       int clkdiv;
+       struct at91mci_host *host = mmc_priv(mmc);
+       unsigned long at91_master_clock = clk_get_rate(host->mci_clk);
+
+       host->bus_mode = ios->bus_mode;
+
+       if (ios->clock == 0) {
+               /* Disable the MCI controller */
+               at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS);
+               clkdiv = 0;
+       }
+       else {
+               /* Enable the MCI controller */
+               at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
+
+               if ((at91_master_clock % (ios->clock * 2)) == 0)
+                       clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
+               else
+                       clkdiv = (at91_master_clock / ios->clock) / 2;
+
+               pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv,
+                       at91_master_clock / (2 * (clkdiv + 1)));
+       }
+       if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
+               pr_debug("MMC: Setting controller bus width to 4\n");
+               at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
+       }
+       else {
+               pr_debug("MMC: Setting controller bus width to 1\n");
+               at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
+       }
+
+       /* Set the clock divider */
+       at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
+
+       /* maybe switch power to the card */
+       if (host->board->vcc_pin) {
+               switch (ios->power_mode) {
+                       case MMC_POWER_OFF:
+                               at91_set_gpio_value(host->board->vcc_pin, 0);
+                               break;
+                       case MMC_POWER_UP:
+                       case MMC_POWER_ON:
+                               at91_set_gpio_value(host->board->vcc_pin, 1);
+                               break;
+               }
+       }
+}
+
+/*
+ * Handle an interrupt
+ */
+static irqreturn_t at91_mci_irq(int irq, void *devid)
+{
+       struct at91mci_host *host = devid;
+       int completed = 0;
+       unsigned int int_status, int_mask;
+
+       int_status = at91_mci_read(host, AT91_MCI_SR);
+       int_mask = at91_mci_read(host, AT91_MCI_IMR);
+       
+       pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
+               int_status & int_mask);
+       
+       int_status = int_status & int_mask;
+
+       if (int_status & AT91_MCI_ERRORS) {
+               completed = 1;
+               
+               if (int_status & AT91_MCI_UNRE)
+                       pr_debug("MMC: Underrun error\n");
+               if (int_status & AT91_MCI_OVRE)
+                       pr_debug("MMC: Overrun error\n");
+               if (int_status & AT91_MCI_DTOE)
+                       pr_debug("MMC: Data timeout\n");
+               if (int_status & AT91_MCI_DCRCE)
+                       pr_debug("MMC: CRC error in data\n");
+               if (int_status & AT91_MCI_RTOE)
+                       pr_debug("MMC: Response timeout\n");
+               if (int_status & AT91_MCI_RENDE)
+                       pr_debug("MMC: Response end bit error\n");
+               if (int_status & AT91_MCI_RCRCE)
+                       pr_debug("MMC: Response CRC error\n");
+               if (int_status & AT91_MCI_RDIRE)
+                       pr_debug("MMC: Response direction error\n");
+               if (int_status & AT91_MCI_RINDE)
+                       pr_debug("MMC: Response index error\n");
+       } else {
+               /* Only continue processing if no errors */
+
+               if (int_status & AT91_MCI_TXBUFE) {
+                       pr_debug("TX buffer empty\n");
+                       at91_mci_handle_transmitted(host);
+               }
+
+               if (int_status & AT91_MCI_RXBUFF) {
+                       pr_debug("RX buffer full\n");
+                       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
+               }
+
+               if (int_status & AT91_MCI_ENDTX)
+                       pr_debug("Transmit has ended\n");
+
+               if (int_status & AT91_MCI_ENDRX) {
+                       pr_debug("Receive has ended\n");
+                       at91mci_post_dma_read(host);
+               }
+
+               if (int_status & AT91_MCI_NOTBUSY) {
+                       pr_debug("Card is ready\n");
+                       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
+               }
+
+               if (int_status & AT91_MCI_DTIP)
+                       pr_debug("Data transfer in progress\n");
+
+               if (int_status & AT91_MCI_BLKE)
+                       pr_debug("Block transfer has ended\n");
+
+               if (int_status & AT91_MCI_TXRDY)
+                       pr_debug("Ready to transmit\n");
+
+               if (int_status & AT91_MCI_RXRDY)
+                       pr_debug("Ready to receive\n");
+
+               if (int_status & AT91_MCI_CMDRDY) {
+                       pr_debug("Command ready\n");
+                       completed = 1;
+               }
+       }
+
+       if (completed) {
+               pr_debug("Completed command\n");
+               at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
+               at91mci_completed_command(host);
+       } else
+               at91_mci_write(host, AT91_MCI_IDR, int_status);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
+{
+       struct at91mci_host *host = _host;
+       int present = !at91_get_gpio_value(irq);
+
+       /*
+        * we expect this irq on both insert and remove,
+        * and use a short delay to debounce.
+        */
+       if (present != host->present) {
+               host->present = present;
+               pr_debug("%s: card %s\n", mmc_hostname(host->mmc),
+                       present ? "insert" : "remove");
+               if (!present) {
+                       pr_debug("****** Resetting SD-card bus width ******\n");
+                       at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
+               }
+               mmc_detect_change(host->mmc, msecs_to_jiffies(100));
+       }
+       return IRQ_HANDLED;
+}
+
+static int at91_mci_get_ro(struct mmc_host *mmc)
+{
+       int read_only = 0;
+       struct at91mci_host *host = mmc_priv(mmc);
+
+       if (host->board->wp_pin) {
+               read_only = at91_get_gpio_value(host->board->wp_pin);
+               printk(KERN_WARNING "%s: card is %s\n", mmc_hostname(mmc),
+                               (read_only ? "read-only" : "read-write") );
+       }
+       else {
+               printk(KERN_WARNING "%s: host does not support reading read-only "
+                               "switch.  Assuming write-enable.\n", mmc_hostname(mmc));
+       }
+       return read_only;
+}
+
+static const struct mmc_host_ops at91_mci_ops = {
+       .request        = at91_mci_request,
+       .set_ios        = at91_mci_set_ios,
+       .get_ro         = at91_mci_get_ro,
+};
+
+/*
+ * Probe for the device
+ */
+static int __init at91_mci_probe(struct platform_device *pdev)
+{
+       struct mmc_host *mmc;
+       struct at91mci_host *host;
+       struct resource *res;
+       int ret;
+
+       pr_debug("Probe MCI devices\n");
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENXIO;
+
+       if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))
+               return -EBUSY;
+
+       mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
+       if (!mmc) {
+               pr_debug("Failed to allocate mmc host\n");
+               release_mem_region(res->start, res->end - res->start + 1);
+               return -ENOMEM;
+       }
+
+       mmc->ops = &at91_mci_ops;
+       mmc->f_min = 375000;
+       mmc->f_max = 25000000;
+       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+       mmc->caps = MMC_CAP_BYTEBLOCK;
+
+       mmc->max_blk_size = 4095;
+       mmc->max_blk_count = mmc->max_req_size;
+
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+       host->buffer = NULL;
+       host->bus_mode = 0;
+       host->board = pdev->dev.platform_data;
+       if (host->board->wire4) {
+#ifdef SUPPORT_4WIRE
+               mmc->caps |= MMC_CAP_4_BIT_DATA;
+#else
+               printk("AT91 MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");
+#endif
+       }
+
+       /*
+        * Get Clock
+        */
+       host->mci_clk = clk_get(&pdev->dev, "mci_clk");
+       if (IS_ERR(host->mci_clk)) {
+               printk(KERN_ERR "AT91 MMC: no clock defined.\n");
+               mmc_free_host(mmc);
+               release_mem_region(res->start, res->end - res->start + 1);
+               return -ENODEV;
+       }
+
+       /*
+        * Map I/O region
+        */
+       host->baseaddr = ioremap(res->start, res->end - res->start + 1);
+       if (!host->baseaddr) {
+               clk_put(host->mci_clk);
+               mmc_free_host(mmc);
+               release_mem_region(res->start, res->end - res->start + 1);
+               return -ENOMEM;
+       }
+
+       /*
+        * Reset hardware
+        */
+       clk_enable(host->mci_clk);              /* Enable the peripheral clock */
+       at91_mci_disable(host);
+       at91_mci_enable(host);
+
+       /*
+        * Allocate the MCI interrupt
+        */
+       host->irq = platform_get_irq(pdev, 0);
+       ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
+       if (ret) {
+               printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n");
+               clk_disable(host->mci_clk);
+               clk_put(host->mci_clk);
+               mmc_free_host(mmc);
+               iounmap(host->baseaddr);
+               release_mem_region(res->start, res->end - res->start + 1);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, mmc);
+
+       /*
+        * Add host to MMC layer
+        */
+       if (host->board->det_pin)
+               host->present = !at91_get_gpio_value(host->board->det_pin);
+       else
+               host->present = -1;
+
+       mmc_add_host(mmc);
+
+       /*
+        * monitor card insertion/removal if we can
+        */
+       if (host->board->det_pin) {
+               ret = request_irq(host->board->det_pin, at91_mmc_det_irq,
+                               0, DRIVER_NAME, host);
+               if (ret)
+                       printk(KERN_ERR "AT91 MMC: Couldn't allocate MMC detect irq\n");
+       }
+
+       pr_debug("Added MCI driver\n");
+
+       return 0;
+}
+
+/*
+ * Remove a device
+ */
+static int __exit at91_mci_remove(struct platform_device *pdev)
+{
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
+       struct at91mci_host *host;
+       struct resource *res;
+
+       if (!mmc)
+               return -1;
+
+       host = mmc_priv(mmc);
+
+       if (host->present != -1) {
+               free_irq(host->board->det_pin, host);
+               cancel_delayed_work(&host->mmc->detect);
+       }
+
+       at91_mci_disable(host);
+       mmc_remove_host(mmc);
+       free_irq(host->irq, host);
+
+       clk_disable(host->mci_clk);                     /* Disable the peripheral clock */
+       clk_put(host->mci_clk);
+
+       iounmap(host->baseaddr);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, res->end - res->start + 1);
+
+       mmc_free_host(mmc);
+       platform_set_drvdata(pdev, NULL);
+       pr_debug("MCI Removed\n");
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
+       int ret = 0;
+
+       if (mmc)
+               ret = mmc_suspend_host(mmc, state);
+
+       return ret;
+}
+
+static int at91_mci_resume(struct platform_device *pdev)
+{
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
+       int ret = 0;
+
+       if (mmc)
+               ret = mmc_resume_host(mmc);
+
+       return ret;
+}
+#else
+#define at91_mci_suspend       NULL
+#define at91_mci_resume                NULL
+#endif
+
+static struct platform_driver at91_mci_driver = {
+       .remove         = __exit_p(at91_mci_remove),
+       .suspend        = at91_mci_suspend,
+       .resume         = at91_mci_resume,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init at91_mci_init(void)
+{
+       return platform_driver_probe(&at91_mci_driver, at91_mci_probe);
+}
+
+static void __exit at91_mci_exit(void)
+{
+       platform_driver_unregister(&at91_mci_driver);
+}
+
+module_init(at91_mci_init);
+module_exit(at91_mci_exit);
+
+MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver");
+MODULE_AUTHOR("Nick Randell");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
new file mode 100644 (file)
index 0000000..b7156a4
--- /dev/null
@@ -0,0 +1,1031 @@
+/*
+ * linux/drivers/mmc/au1xmmc.c - AU1XX0 MMC driver
+ *
+ *  Copyright (c) 2005, Advanced Micro Devices, Inc.
+ *
+ *  Developed with help from the 2.4.30 MMC AU1XXX controller including
+ *  the following copyright notices:
+ *     Copyright (c) 2003-2004 Embedded Edge, LLC.
+ *     Portions Copyright (C) 2002 Embedix, Inc
+ *     Copyright 2002 Hewlett-Packard Company
+
+ *  2.6 version of this driver inspired by:
+ *     (drivers/mmc/wbsd.c) Copyright (C) 2004-2005 Pierre Ossman,
+ *     All Rights Reserved.
+ *     (drivers/mmc/pxa.c) Copyright (C) 2003 Russell King,
+ *     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.
+ */
+
+/* Why is a timer used to detect insert events?
+ *
+ * From the AU1100 MMC application guide:
+ * If the Au1100-based design is intended to support both MultiMediaCards
+ * and 1- or 4-data bit SecureDigital cards, then the solution is to
+ * connect a weak (560KOhm) pull-up resistor to connector pin 1.
+ * In doing so, a MMC card never enters SPI-mode communications,
+ * but now the SecureDigital card-detect feature of CD/DAT3 is ineffective
+ * (the low to high transition will not occur).
+ *
+ * So we use the timer to check the status manually.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/mmc/host.h>
+#include <asm/io.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1100_mmc.h>
+#include <asm/scatterlist.h>
+
+#include <au1xxx.h>
+#include "au1xmmc.h"
+
+#define DRIVER_NAME "au1xxx-mmc"
+
+/* Set this to enable special debugging macros */
+
+#ifdef DEBUG
+#define DBG(fmt, idx, args...) printk("au1xx(%d): DEBUG: " fmt, idx, ##args)
+#else
+#define DBG(fmt, idx, args...)
+#endif
+
+const struct {
+       u32 iobase;
+       u32 tx_devid, rx_devid;
+       u16 bcsrpwr;
+       u16 bcsrstatus;
+       u16 wpstatus;
+} au1xmmc_card_table[] = {
+       { SD0_BASE, DSCR_CMD0_SDMS_TX0, DSCR_CMD0_SDMS_RX0,
+         BCSR_BOARD_SD0PWR, BCSR_INT_SD0INSERT, BCSR_STATUS_SD0WP },
+#ifndef CONFIG_MIPS_DB1200
+       { SD1_BASE, DSCR_CMD0_SDMS_TX1, DSCR_CMD0_SDMS_RX1,
+         BCSR_BOARD_DS1PWR, BCSR_INT_SD1INSERT, BCSR_STATUS_SD1WP }
+#endif
+};
+
+#define AU1XMMC_CONTROLLER_COUNT \
+       (sizeof(au1xmmc_card_table) / sizeof(au1xmmc_card_table[0]))
+
+/* This array stores pointers for the hosts (used by the IRQ handler) */
+struct au1xmmc_host *au1xmmc_hosts[AU1XMMC_CONTROLLER_COUNT];
+static int dma = 1;
+
+#ifdef MODULE
+module_param(dma, bool, 0);
+MODULE_PARM_DESC(dma, "Use DMA engine for data transfers (0 = disabled)");
+#endif
+
+static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask)
+{
+       u32 val = au_readl(HOST_CONFIG(host));
+       val |= mask;
+       au_writel(val, HOST_CONFIG(host));
+       au_sync();
+}
+
+static inline void FLUSH_FIFO(struct au1xmmc_host *host)
+{
+       u32 val = au_readl(HOST_CONFIG2(host));
+
+       au_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host));
+       au_sync_delay(1);
+
+       /* SEND_STOP will turn off clock control - this re-enables it */
+       val &= ~SD_CONFIG2_DF;
+
+       au_writel(val, HOST_CONFIG2(host));
+       au_sync();
+}
+
+static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask)
+{
+       u32 val = au_readl(HOST_CONFIG(host));
+       val &= ~mask;
+       au_writel(val, HOST_CONFIG(host));
+       au_sync();
+}
+
+static inline void SEND_STOP(struct au1xmmc_host *host)
+{
+
+       /* We know the value of CONFIG2, so avoid a read we don't need */
+       u32 mask = SD_CONFIG2_EN;
+
+       WARN_ON(host->status != HOST_S_DATA);
+       host->status = HOST_S_STOP;
+
+       au_writel(mask | SD_CONFIG2_DF, HOST_CONFIG2(host));
+       au_sync();
+
+       /* Send the stop commmand */
+       au_writel(STOP_CMD, HOST_CMD(host));
+}
+
+static void au1xmmc_set_power(struct au1xmmc_host *host, int state)
+{
+
+       u32 val = au1xmmc_card_table[host->id].bcsrpwr;
+
+       bcsr->board &= ~val;
+       if (state) bcsr->board |= val;
+
+       au_sync_delay(1);
+}
+
+static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
+{
+       return (bcsr->sig_status & au1xmmc_card_table[host->id].bcsrstatus)
+               ? 1 : 0;
+}
+
+static int au1xmmc_card_readonly(struct mmc_host *mmc)
+{
+       struct au1xmmc_host *host = mmc_priv(mmc);
+       return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
+               ? 1 : 0;
+}
+
+static void au1xmmc_finish_request(struct au1xmmc_host *host)
+{
+
+       struct mmc_request *mrq = host->mrq;
+
+       host->mrq = NULL;
+       host->flags &= HOST_F_ACTIVE;
+
+       host->dma.len = 0;
+       host->dma.dir = 0;
+
+       host->pio.index  = 0;
+       host->pio.offset = 0;
+       host->pio.len = 0;
+
+       host->status = HOST_S_IDLE;
+
+       bcsr->disk_leds |= (1 << 8);
+
+       mmc_request_done(host->mmc, mrq);
+}
+
+static void au1xmmc_tasklet_finish(unsigned long param)
+{
+       struct au1xmmc_host *host = (struct au1xmmc_host *) param;
+       au1xmmc_finish_request(host);
+}
+
+static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
+                               struct mmc_command *cmd)
+{
+
+       u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
+
+       switch (mmc_resp_type(cmd)) {
+       case MMC_RSP_NONE:
+               break;
+       case MMC_RSP_R1:
+               mmccmd |= SD_CMD_RT_1;
+               break;
+       case MMC_RSP_R1B:
+               mmccmd |= SD_CMD_RT_1B;
+               break;
+       case MMC_RSP_R2:
+               mmccmd |= SD_CMD_RT_2;
+               break;
+       case MMC_RSP_R3:
+               mmccmd |= SD_CMD_RT_3;
+               break;
+       default:
+               printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
+                       mmc_resp_type(cmd));
+               return MMC_ERR_INVALID;
+       }
+
+       switch(cmd->opcode) {
+       case MMC_READ_SINGLE_BLOCK:
+       case SD_APP_SEND_SCR:
+               mmccmd |= SD_CMD_CT_2;
+               break;
+       case MMC_READ_MULTIPLE_BLOCK:
+               mmccmd |= SD_CMD_CT_4;
+               break;
+       case MMC_WRITE_BLOCK:
+               mmccmd |= SD_CMD_CT_1;
+               break;
+
+       case MMC_WRITE_MULTIPLE_BLOCK:
+               mmccmd |= SD_CMD_CT_3;
+               break;
+       case MMC_STOP_TRANSMISSION:
+               mmccmd |= SD_CMD_CT_7;
+               break;
+       }
+
+       au_writel(cmd->arg, HOST_CMDARG(host));
+       au_sync();
+
+       if (wait)
+               IRQ_OFF(host, SD_CONFIG_CR);
+
+       au_writel((mmccmd | SD_CMD_GO), HOST_CMD(host));
+       au_sync();
+
+       /* Wait for the command to go on the line */
+
+       while(1) {
+               if (!(au_readl(HOST_CMD(host)) & SD_CMD_GO))
+                       break;
+       }
+
+       /* Wait for the command to come back */
+
+       if (wait) {
+               u32 status = au_readl(HOST_STATUS(host));
+
+               while(!(status & SD_STATUS_CR))
+                       status = au_readl(HOST_STATUS(host));
+
+               /* Clear the CR status */
+               au_writel(SD_STATUS_CR, HOST_STATUS(host));
+
+               IRQ_ON(host, SD_CONFIG_CR);
+       }
+
+       return MMC_ERR_NONE;
+}
+
+static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
+{
+
+       struct mmc_request *mrq = host->mrq;
+       struct mmc_data *data;
+       u32 crc;
+
+       WARN_ON(host->status != HOST_S_DATA && host->status != HOST_S_STOP);
+
+       if (host->mrq == NULL)
+               return;
+
+       data = mrq->cmd->data;
+
+       if (status == 0)
+               status = au_readl(HOST_STATUS(host));
+
+       /* The transaction is really over when the SD_STATUS_DB bit is clear */
+
+       while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
+               status = au_readl(HOST_STATUS(host));
+
+       data->error = MMC_ERR_NONE;
+       dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir);
+
+        /* Process any errors */
+
+       crc = (status & (SD_STATUS_WC | SD_STATUS_RC));
+       if (host->flags & HOST_F_XMIT)
+               crc |= ((status & 0x07) == 0x02) ? 0 : 1;
+
+       if (crc)
+               data->error = MMC_ERR_BADCRC;
+
+       /* Clear the CRC bits */
+       au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host));
+
+       data->bytes_xfered = 0;
+
+       if (data->error == MMC_ERR_NONE) {
+               if (host->flags & HOST_F_DMA) {
+                       u32 chan = DMA_CHANNEL(host);
+
+                       chan_tab_t *c = *((chan_tab_t **) chan);
+                       au1x_dma_chan_t *cp = c->chan_ptr;
+                       data->bytes_xfered = cp->ddma_bytecnt;
+               }
+               else
+                       data->bytes_xfered =
+                               (data->blocks * data->blksz) -
+                               host->pio.len;
+       }
+
+       au1xmmc_finish_request(host);
+}
+
+static void au1xmmc_tasklet_data(unsigned long param)
+{
+       struct au1xmmc_host *host = (struct au1xmmc_host *) param;
+
+       u32 status = au_readl(HOST_STATUS(host));
+       au1xmmc_data_complete(host, status);
+}
+
+#define AU1XMMC_MAX_TRANSFER 8
+
+static void au1xmmc_send_pio(struct au1xmmc_host *host)
+{
+
+       struct mmc_data *data = 0;
+       int sg_len, max, count = 0;
+       unsigned char *sg_ptr;
+       u32 status = 0;
+       struct scatterlist *sg;
+
+       data = host->mrq->data;
+
+       if (!(host->flags & HOST_F_XMIT))
+               return;
+
+       /* This is the pointer to the data buffer */
+       sg = &data->sg[host->pio.index];
+       sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
+
+       /* This is the space left inside the buffer */
+       sg_len = data->sg[host->pio.index].length - host->pio.offset;
+
+       /* Check to if we need less then the size of the sg_buffer */
+
+       max = (sg_len > host->pio.len) ? host->pio.len : sg_len;
+       if (max > AU1XMMC_MAX_TRANSFER) max = AU1XMMC_MAX_TRANSFER;
+
+       for(count = 0; count < max; count++ ) {
+               unsigned char val;
+
+               status = au_readl(HOST_STATUS(host));
+
+               if (!(status & SD_STATUS_TH))
+                       break;
+
+               val = *sg_ptr++;
+
+               au_writel((unsigned long) val, HOST_TXPORT(host));
+               au_sync();
+       }
+
+       host->pio.len -= count;
+       host->pio.offset += count;
+
+       if (count == sg_len) {
+               host->pio.index++;
+               host->pio.offset = 0;
+       }
+
+       if (host->pio.len == 0) {
+               IRQ_OFF(host, SD_CONFIG_TH);
+
+               if (host->flags & HOST_F_STOP)
+                       SEND_STOP(host);
+
+               tasklet_schedule(&host->data_task);
+       }
+}
+
+static void au1xmmc_receive_pio(struct au1xmmc_host *host)
+{
+
+       struct mmc_data *data = 0;
+       int sg_len = 0, max = 0, count = 0;
+       unsigned char *sg_ptr = 0;
+       u32 status = 0;
+       struct scatterlist *sg;
+
+       data = host->mrq->data;
+
+       if (!(host->flags & HOST_F_RECV))
+               return;
+
+       max = host->pio.len;
+
+       if (host->pio.index < host->dma.len) {
+               sg = &data->sg[host->pio.index];
+               sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
+
+               /* This is the space left inside the buffer */
+               sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
+
+               /* Check to if we need less then the size of the sg_buffer */
+               if (sg_len < max) max = sg_len;
+       }
+
+       if (max > AU1XMMC_MAX_TRANSFER)
+               max = AU1XMMC_MAX_TRANSFER;
+
+       for(count = 0; count < max; count++ ) {
+               u32 val;
+               status = au_readl(HOST_STATUS(host));
+
+               if (!(status & SD_STATUS_NE))
+                       break;
+
+               if (status & SD_STATUS_RC) {
+                       DBG("RX CRC Error [%d + %d].\n", host->id,
+                                       host->pio.len, count);
+                       break;
+               }
+
+               if (status & SD_STATUS_RO) {
+                       DBG("RX Overrun [%d + %d]\n", host->id,
+                                       host->pio.len, count);
+                       break;
+               }
+               else if (status & SD_STATUS_RU) {
+                       DBG("RX Underrun [%d + %d]\n", host->id,
+                                       host->pio.len,  count);
+                       break;
+               }
+
+               val = au_readl(HOST_RXPORT(host));
+
+               if (sg_ptr)
+                       *sg_ptr++ = (unsigned char) (val & 0xFF);
+       }
+
+       host->pio.len -= count;
+       host->pio.offset += count;
+
+       if (sg_len && count == sg_len) {
+               host->pio.index++;
+               host->pio.offset = 0;
+       }
+
+       if (host->pio.len == 0) {
+               //IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF);
+               IRQ_OFF(host, SD_CONFIG_NE);
+
+               if (host->flags & HOST_F_STOP)
+                       SEND_STOP(host);
+
+               tasklet_schedule(&host->data_task);
+       }
+}
+
+/* static void au1xmmc_cmd_complete
+   This is called when a command has been completed - grab the response
+   and check for errors.  Then start the data transfer if it is indicated.
+*/
+
+static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
+{
+
+       struct mmc_request *mrq = host->mrq;
+       struct mmc_command *cmd;
+       int trans;
+
+       if (!host->mrq)
+               return;
+
+       cmd = mrq->cmd;
+       cmd->error = MMC_ERR_NONE;
+
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               if (cmd->flags & MMC_RSP_136) {
+                       u32 r[4];
+                       int i;
+
+                       r[0] = au_readl(host->iobase + SD_RESP3);
+                       r[1] = au_readl(host->iobase + SD_RESP2);
+                       r[2] = au_readl(host->iobase + SD_RESP1);
+                       r[3] = au_readl(host->iobase + SD_RESP0);
+
+                       /* The CRC is omitted from the response, so really
+                        * we only got 120 bytes, but the engine expects
+                        * 128 bits, so we have to shift things up
+                        */
+
+                       for(i = 0; i < 4; i++) {
+                               cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
+                               if (i != 3)
+                                       cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
+                       }
+               } else {
+                       /* Techincally, we should be getting all 48 bits of
+                        * the response (SD_RESP1 + SD_RESP2), but because
+                        * our response omits the CRC, our data ends up
+                        * being shifted 8 bits to the right.  In this case,
+                        * that means that the OSR data starts at bit 31,
+                        * so we can just read RESP0 and return that
+                        */
+                       cmd->resp[0] = au_readl(host->iobase + SD_RESP0);
+               }
+       }
+
+        /* Figure out errors */
+
+       if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC))
+               cmd->error = MMC_ERR_BADCRC;
+
+       trans = host->flags & (HOST_F_XMIT | HOST_F_RECV);
+
+       if (!trans || cmd->error != MMC_ERR_NONE) {
+
+               IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF);
+               tasklet_schedule(&host->finish_task);
+               return;
+       }
+
+       host->status = HOST_S_DATA;
+
+       if (host->flags & HOST_F_DMA) {
+               u32 channel = DMA_CHANNEL(host);
+
+               /* Start the DMA as soon as the buffer gets something in it */
+
+               if (host->flags & HOST_F_RECV) {
+                       u32 mask = SD_STATUS_DB | SD_STATUS_NE;
+
+                       while((status & mask) != mask)
+                               status = au_readl(HOST_STATUS(host));
+               }
+
+               au1xxx_dbdma_start(channel);
+       }
+}
+
+static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate)
+{
+
+       unsigned int pbus = get_au1x00_speed();
+       unsigned int divisor;
+       u32 config;
+
+       /* From databook:
+          divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1
+       */
+
+       pbus /= ((au_readl(SYS_POWERCTRL) & 0x3) + 2);
+       pbus /= 2;
+
+       divisor = ((pbus / rate) / 2) - 1;
+
+       config = au_readl(HOST_CONFIG(host));
+
+       config &= ~(SD_CONFIG_DIV);
+       config |= (divisor & SD_CONFIG_DIV) | SD_CONFIG_DE;
+
+       au_writel(config, HOST_CONFIG(host));
+       au_sync();
+}
+
+static int
+au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
+{
+
+       int datalen = data->blocks * data->blksz;
+
+       if (dma != 0)
+               host->flags |= HOST_F_DMA;
+
+       if (data->flags & MMC_DATA_READ)
+               host->flags |= HOST_F_RECV;
+       else
+               host->flags |= HOST_F_XMIT;
+
+       if (host->mrq->stop)
+               host->flags |= HOST_F_STOP;
+
+       host->dma.dir = DMA_BIDIRECTIONAL;
+
+       host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+                                  data->sg_len, host->dma.dir);
+
+       if (host->dma.len == 0)
+               return MMC_ERR_TIMEOUT;
+
+       au_writel(data->blksz - 1, HOST_BLKSIZE(host));
+
+       if (host->flags & HOST_F_DMA) {
+               int i;
+               u32 channel = DMA_CHANNEL(host);
+
+               au1xxx_dbdma_stop(channel);
+
+               for(i = 0; i < host->dma.len; i++) {
+                       u32 ret = 0, flags = DDMA_FLAGS_NOIE;
+                       struct scatterlist *sg = &data->sg[i];
+                       int sg_len = sg->length;
+
+                       int len = (datalen > sg_len) ? sg_len : datalen;
+
+                       if (i == host->dma.len - 1)
+                               flags = DDMA_FLAGS_IE;
+
+                       if (host->flags & HOST_F_XMIT){
+                               ret = au1xxx_dbdma_put_source_flags(channel,
+                                       (void *) (page_address(sg->page) +
+                                                 sg->offset),
+                                       len, flags);
+                       }
+                       else {
+                               ret = au1xxx_dbdma_put_dest_flags(channel,
+                                       (void *) (page_address(sg->page) +
+                                                 sg->offset),
+                                       len, flags);
+                       }
+
+                       if (!ret)
+                               goto dataerr;
+
+                       datalen -= len;
+               }
+       }
+       else {
+               host->pio.index = 0;
+               host->pio.offset = 0;
+               host->pio.len = datalen;
+
+               if (host->flags & HOST_F_XMIT)
+                       IRQ_ON(host, SD_CONFIG_TH);
+               else
+                       IRQ_ON(host, SD_CONFIG_NE);
+                       //IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF);
+       }
+
+       return MMC_ERR_NONE;
+
+ dataerr:
+       dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir);
+       return MMC_ERR_TIMEOUT;
+}
+
+/* static void au1xmmc_request
+   This actually starts a command or data transaction
+*/
+
+static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
+{
+
+       struct au1xmmc_host *host = mmc_priv(mmc);
+       int ret = MMC_ERR_NONE;
+
+       WARN_ON(irqs_disabled());
+       WARN_ON(host->status != HOST_S_IDLE);
+
+       host->mrq = mrq;
+       host->status = HOST_S_CMD;
+
+       bcsr->disk_leds &= ~(1 << 8);
+
+       if (mrq->data) {
+               FLUSH_FIFO(host);
+               ret = au1xmmc_prepare_data(host, mrq->data);
+       }
+
+       if (ret == MMC_ERR_NONE)
+               ret = au1xmmc_send_command(host, 0, mrq->cmd);
+
+       if (ret != MMC_ERR_NONE) {
+               mrq->cmd->error = ret;
+               au1xmmc_finish_request(host);
+       }
+}
+
+static void au1xmmc_reset_controller(struct au1xmmc_host *host)
+{
+
+       /* Apply the clock */
+       au_writel(SD_ENABLE_CE, HOST_ENABLE(host));
+        au_sync_delay(1);
+
+       au_writel(SD_ENABLE_R | SD_ENABLE_CE, HOST_ENABLE(host));
+       au_sync_delay(5);
+
+       au_writel(~0, HOST_STATUS(host));
+       au_sync();
+
+       au_writel(0, HOST_BLKSIZE(host));
+       au_writel(0x001fffff, HOST_TIMEOUT(host));
+       au_sync();
+
+       au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
+        au_sync();
+
+       au_writel(SD_CONFIG2_EN | SD_CONFIG2_FF, HOST_CONFIG2(host));
+       au_sync_delay(1);
+
+       au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
+       au_sync();
+
+       /* Configure interrupts */
+       au_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host));
+       au_sync();
+}
+
+
+static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
+{
+       struct au1xmmc_host *host = mmc_priv(mmc);
+
+       if (ios->power_mode == MMC_POWER_OFF)
+               au1xmmc_set_power(host, 0);
+       else if (ios->power_mode == MMC_POWER_ON) {
+               au1xmmc_set_power(host, 1);
+       }
+
+       if (ios->clock && ios->clock != host->clock) {
+               au1xmmc_set_clock(host, ios->clock);
+               host->clock = ios->clock;
+       }
+}
+
+static void au1xmmc_dma_callback(int irq, void *dev_id)
+{
+       struct au1xmmc_host *host = (struct au1xmmc_host *) dev_id;
+
+       /* Avoid spurious interrupts */
+
+       if (!host->mrq)
+               return;
+
+       if (host->flags & HOST_F_STOP)
+               SEND_STOP(host);
+
+       tasklet_schedule(&host->data_task);
+}
+
+#define STATUS_TIMEOUT (SD_STATUS_RAT | SD_STATUS_DT)
+#define STATUS_DATA_IN  (SD_STATUS_NE)
+#define STATUS_DATA_OUT (SD_STATUS_TH)
+
+static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
+{
+
+       u32 status;
+       int i, ret = 0;
+
+       disable_irq(AU1100_SD_IRQ);
+
+       for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
+               struct au1xmmc_host * host = au1xmmc_hosts[i];
+               u32 handled = 1;
+
+               status = au_readl(HOST_STATUS(host));
+
+               if (host->mrq && (status & STATUS_TIMEOUT)) {
+                       if (status & SD_STATUS_RAT)
+                               host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+
+                       else if (status & SD_STATUS_DT)
+                               host->mrq->data->error = MMC_ERR_TIMEOUT;
+
+                       /* In PIO mode, interrupts might still be enabled */
+                       IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
+
+                       //IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF);
+                       tasklet_schedule(&host->finish_task);
+               }
+#if 0
+               else if (status & SD_STATUS_DD) {
+
+                       /* Sometimes we get a DD before a NE in PIO mode */
+
+                       if (!(host->flags & HOST_F_DMA) &&
+                                       (status & SD_STATUS_NE))
+                               au1xmmc_receive_pio(host);
+                       else {
+                               au1xmmc_data_complete(host, status);
+                               //tasklet_schedule(&host->data_task);
+                       }
+               }
+#endif
+               else if (status & (SD_STATUS_CR)) {
+                       if (host->status == HOST_S_CMD)
+                               au1xmmc_cmd_complete(host,status);
+               }
+               else if (!(host->flags & HOST_F_DMA)) {
+                       if ((host->flags & HOST_F_XMIT) &&
+                           (status & STATUS_DATA_OUT))
+                               au1xmmc_send_pio(host);
+                       else if ((host->flags & HOST_F_RECV) &&
+                           (status & STATUS_DATA_IN))
+                               au1xmmc_receive_pio(host);
+               }
+               else if (status & 0x203FBC70) {
+                       DBG("Unhandled status %8.8x\n", host->id, status);
+                       handled = 0;
+               }
+
+               au_writel(status, HOST_STATUS(host));
+               au_sync();
+
+               ret |= handled;
+       }
+
+       enable_irq(AU1100_SD_IRQ);
+       return ret;
+}
+
+static void au1xmmc_poll_event(unsigned long arg)
+{
+       struct au1xmmc_host *host = (struct au1xmmc_host *) arg;
+
+       int card = au1xmmc_card_inserted(host);
+        int controller = (host->flags & HOST_F_ACTIVE) ? 1 : 0;
+
+       if (card != controller) {
+               host->flags &= ~HOST_F_ACTIVE;
+               if (card) host->flags |= HOST_F_ACTIVE;
+               mmc_detect_change(host->mmc, 0);
+       }
+
+       if (host->mrq != NULL) {
+               u32 status = au_readl(HOST_STATUS(host));
+               DBG("PENDING - %8.8x\n", host->id, status);
+       }
+
+       mod_timer(&host->timer, jiffies + AU1XMMC_DETECT_TIMEOUT);
+}
+
+static dbdev_tab_t au1xmmc_mem_dbdev =
+{
+       DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 8, 0x00000000, 0, 0
+};
+
+static void au1xmmc_init_dma(struct au1xmmc_host *host)
+{
+
+       u32 rxchan, txchan;
+
+       int txid = au1xmmc_card_table[host->id].tx_devid;
+       int rxid = au1xmmc_card_table[host->id].rx_devid;
+
+       /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
+          of 8 bits.  And since devices are shared, we need to create
+          our own to avoid freaking out other devices
+       */
+
+       int memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);
+
+       txchan = au1xxx_dbdma_chan_alloc(memid, txid,
+                                        au1xmmc_dma_callback, (void *) host);
+
+       rxchan = au1xxx_dbdma_chan_alloc(rxid, memid,
+                                        au1xmmc_dma_callback, (void *) host);
+
+       au1xxx_dbdma_set_devwidth(txchan, 8);
+       au1xxx_dbdma_set_devwidth(rxchan, 8);
+
+       au1xxx_dbdma_ring_alloc(txchan, AU1XMMC_DESCRIPTOR_COUNT);
+       au1xxx_dbdma_ring_alloc(rxchan, AU1XMMC_DESCRIPTOR_COUNT);
+
+       host->tx_chan = txchan;
+       host->rx_chan = rxchan;
+}
+
+static const struct mmc_host_ops au1xmmc_ops = {
+       .request        = au1xmmc_request,
+       .set_ios        = au1xmmc_set_ios,
+       .get_ro         = au1xmmc_card_readonly,
+};
+
+static int __devinit au1xmmc_probe(struct platform_device *pdev)
+{
+
+       int i, ret = 0;
+
+       /* THe interrupt is shared among all controllers */
+       ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, IRQF_DISABLED, "MMC", 0);
+
+       if (ret) {
+               printk(DRIVER_NAME "ERROR: Couldn't get int %d: %d\n",
+                               AU1100_SD_IRQ, ret);
+               return -ENXIO;
+       }
+
+       disable_irq(AU1100_SD_IRQ);
+
+       for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
+               struct mmc_host *mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
+               struct au1xmmc_host *host = 0;
+
+               if (!mmc) {
+                       printk(DRIVER_NAME "ERROR: no mem for host %d\n", i);
+                       au1xmmc_hosts[i] = 0;
+                       continue;
+               }
+
+               mmc->ops = &au1xmmc_ops;
+
+               mmc->f_min =   450000;
+               mmc->f_max = 24000000;
+
+               mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
+               mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
+
+               mmc->max_blk_size = 2048;
+               mmc->max_blk_count = 512;
+
+               mmc->ocr_avail = AU1XMMC_OCR;
+
+               host = mmc_priv(mmc);
+               host->mmc = mmc;
+
+               host->id = i;
+               host->iobase = au1xmmc_card_table[host->id].iobase;
+               host->clock = 0;
+               host->power_mode = MMC_POWER_OFF;
+
+               host->flags = au1xmmc_card_inserted(host) ? HOST_F_ACTIVE : 0;
+               host->status = HOST_S_IDLE;
+
+               init_timer(&host->timer);
+
+               host->timer.function = au1xmmc_poll_event;
+               host->timer.data = (unsigned long) host;
+               host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT;
+
+               tasklet_init(&host->data_task, au1xmmc_tasklet_data,
+                               (unsigned long) host);
+
+               tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
+                               (unsigned long) host);
+
+               spin_lock_init(&host->lock);
+
+               if (dma != 0)
+                       au1xmmc_init_dma(host);
+
+               au1xmmc_reset_controller(host);
+
+               mmc_add_host(mmc);
+               au1xmmc_hosts[i] = host;
+
+               add_timer(&host->timer);
+
+               printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X (mode=%s)\n",
+                      host->id, host->iobase, dma ? "dma" : "pio");
+       }
+
+       enable_irq(AU1100_SD_IRQ);
+
+       return 0;
+}
+
+static int __devexit au1xmmc_remove(struct platform_device *pdev)
+{
+
+       int i;
+
+       disable_irq(AU1100_SD_IRQ);
+
+       for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
+               struct au1xmmc_host *host = au1xmmc_hosts[i];
+               if (!host) continue;
+
+               tasklet_kill(&host->data_task);
+               tasklet_kill(&host->finish_task);
+
+               del_timer_sync(&host->timer);
+               au1xmmc_set_power(host, 0);
+
+               mmc_remove_host(host->mmc);
+
+               au1xxx_dbdma_chan_free(host->tx_chan);
+               au1xxx_dbdma_chan_free(host->rx_chan);
+
+               au_writel(0x0, HOST_ENABLE(host));
+               au_sync();
+       }
+
+       free_irq(AU1100_SD_IRQ, 0);
+       return 0;
+}
+
+static struct platform_driver au1xmmc_driver = {
+       .probe         = au1xmmc_probe,
+       .remove        = au1xmmc_remove,
+       .suspend       = NULL,
+       .resume        = NULL,
+       .driver        = {
+               .name  = DRIVER_NAME,
+       },
+};
+
+static int __init au1xmmc_init(void)
+{
+       return platform_driver_register(&au1xmmc_driver);
+}
+
+static void __exit au1xmmc_exit(void)
+{
+       platform_driver_unregister(&au1xmmc_driver);
+}
+
+module_init(au1xmmc_init);
+module_exit(au1xmmc_exit);
+
+#ifdef MODULE
+MODULE_AUTHOR("Advanced Micro Devices, Inc");
+MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX");
+MODULE_LICENSE("GPL");
+#endif
+
diff --git a/drivers/mmc/host/au1xmmc.h b/drivers/mmc/host/au1xmmc.h
new file mode 100644 (file)
index 0000000..341cbdf
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef _AU1XMMC_H_
+#define _AU1XMMC_H_
+
+/* Hardware definitions */
+
+#define AU1XMMC_DESCRIPTOR_COUNT 1
+#define AU1XMMC_DESCRIPTOR_SIZE  2048
+
+#define AU1XMMC_OCR ( MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30  | \
+                     MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33  | \
+                     MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36)
+
+/* Easy access macros */
+
+#define HOST_STATUS(h) ((h)->iobase + SD_STATUS)
+#define HOST_CONFIG(h) ((h)->iobase + SD_CONFIG)
+#define HOST_ENABLE(h) ((h)->iobase + SD_ENABLE)
+#define HOST_TXPORT(h) ((h)->iobase + SD_TXPORT)
+#define HOST_RXPORT(h) ((h)->iobase + SD_RXPORT)
+#define HOST_CMDARG(h) ((h)->iobase + SD_CMDARG)
+#define HOST_BLKSIZE(h)        ((h)->iobase + SD_BLKSIZE)
+#define HOST_CMD(h)    ((h)->iobase + SD_CMD)
+#define HOST_CONFIG2(h)        ((h)->iobase + SD_CONFIG2)
+#define HOST_TIMEOUT(h)        ((h)->iobase + SD_TIMEOUT)
+#define HOST_DEBUG(h)  ((h)->iobase + SD_DEBUG)
+
+#define DMA_CHANNEL(h) \
+       ( ((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan)
+
+/* This gives us a hard value for the stop command that we can write directly
+ * to the command register
+ */
+
+#define STOP_CMD (SD_CMD_RT_1B|SD_CMD_CT_7|(0xC << SD_CMD_CI_SHIFT)|SD_CMD_GO)
+
+/* This is the set of interrupts that we configure by default */
+
+#if 0
+#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | SD_CONFIG_DD | \
+               SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
+#endif
+
+#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | \
+               SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
+/* The poll event (looking for insert/remove events runs twice a second */
+#define AU1XMMC_DETECT_TIMEOUT (HZ/2)
+
+struct au1xmmc_host {
+  struct mmc_host *mmc;
+  struct mmc_request *mrq;
+
+  u32 id;
+
+  u32 flags;
+  u32 iobase;
+  u32 clock;
+  u32 bus_width;
+  u32 power_mode;
+
+  int status;
+
+   struct {
+          int len;
+          int dir;
+  } dma;
+
+   struct {
+          int index;
+          int offset;
+          int len;
+  } pio;
+
+  u32 tx_chan;
+  u32 rx_chan;
+
+  struct timer_list timer;
+  struct tasklet_struct finish_task;
+  struct tasklet_struct data_task;
+
+  spinlock_t lock;
+};
+
+/* Status flags used by the host structure */
+
+#define HOST_F_XMIT   0x0001
+#define HOST_F_RECV   0x0002
+#define HOST_F_DMA    0x0010
+#define HOST_F_ACTIVE 0x0100
+#define HOST_F_STOP   0x1000
+
+#define HOST_S_IDLE   0x0001
+#define HOST_S_CMD    0x0002
+#define HOST_S_DATA   0x0003
+#define HOST_S_STOP   0x0004
+
+#endif
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c
new file mode 100644 (file)
index 0000000..7ee2045
--- /dev/null
@@ -0,0 +1,1137 @@
+/*
+ *  linux/drivers/mmc/imxmmc.c - Motorola i.MX MMCI driver
+ *
+ *  Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de>
+ *  Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
+ *
+ *  derived from pxamci.c by Russell King
+ *
+ * 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.
+ *
+ *  2005-04-17 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *             Changed to conform redesigned i.MX scatter gather DMA interface
+ *
+ *  2005-11-04 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *             Updated for 2.6.14 kernel
+ *
+ *  2005-12-13 Jay Monkman <jtm@smoothsmoothie.com>
+ *             Found and corrected problems in the write path
+ *
+ *  2005-12-30 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *             The event handling rewritten right way in softirq.
+ *             Added many ugly hacks and delays to overcome SDHC
+ *             deficiencies
+ *
+ */
+
+#ifdef CONFIG_MMC_DEBUG
+#define DEBUG
+#else
+#undef  DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/delay.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/imx-dma.h>
+
+#include "imxmmc.h"
+
+#define DRIVER_NAME "imx-mmc"
+
+#define IMXMCI_INT_MASK_DEFAULT (INT_MASK_BUF_READY | INT_MASK_DATA_TRAN | \
+                     INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \
+                     INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO)
+
+struct imxmci_host {
+       struct mmc_host         *mmc;
+       spinlock_t              lock;
+       struct resource         *res;
+       int                     irq;
+       imx_dmach_t             dma;
+       unsigned int            clkrt;
+       unsigned int            cmdat;
+       volatile unsigned int   imask;
+       unsigned int            power_mode;
+       unsigned int            present;
+       struct imxmmc_platform_data *pdata;
+
+       struct mmc_request      *req;
+       struct mmc_command      *cmd;
+       struct mmc_data         *data;
+
+       struct timer_list       timer;
+       struct tasklet_struct   tasklet;
+       unsigned int            status_reg;
+       unsigned long           pending_events;
+       /* Next to fields are there for CPU driven transfers to overcome SDHC deficiencies */
+       u16                     *data_ptr;
+       unsigned int            data_cnt;
+       atomic_t                stuck_timeout;
+
+       unsigned int            dma_nents;
+       unsigned int            dma_size;
+       unsigned int            dma_dir;
+       int                     dma_allocated;
+
+       unsigned char           actual_bus_width;
+
+       int                     prev_cmd_code;
+};
+
+#define IMXMCI_PEND_IRQ_b      0
+#define IMXMCI_PEND_DMA_END_b  1
+#define IMXMCI_PEND_DMA_ERR_b  2
+#define IMXMCI_PEND_WAIT_RESP_b        3
+#define IMXMCI_PEND_DMA_DATA_b 4
+#define IMXMCI_PEND_CPU_DATA_b 5
+#define IMXMCI_PEND_CARD_XCHG_b        6
+#define IMXMCI_PEND_SET_INIT_b 7
+#define IMXMCI_PEND_STARTED_b  8
+
+#define IMXMCI_PEND_IRQ_m      (1 << IMXMCI_PEND_IRQ_b)
+#define IMXMCI_PEND_DMA_END_m  (1 << IMXMCI_PEND_DMA_END_b)
+#define IMXMCI_PEND_DMA_ERR_m  (1 << IMXMCI_PEND_DMA_ERR_b)
+#define IMXMCI_PEND_WAIT_RESP_m        (1 << IMXMCI_PEND_WAIT_RESP_b)
+#define IMXMCI_PEND_DMA_DATA_m (1 << IMXMCI_PEND_DMA_DATA_b)
+#define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b)
+#define IMXMCI_PEND_CARD_XCHG_m        (1 << IMXMCI_PEND_CARD_XCHG_b)
+#define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b)
+#define IMXMCI_PEND_STARTED_m  (1 << IMXMCI_PEND_STARTED_b)
+
+static void imxmci_stop_clock(struct imxmci_host *host)
+{
+       int i = 0;
+       MMC_STR_STP_CLK &= ~STR_STP_CLK_START_CLK;
+       while(i < 0x1000) {
+               if(!(i & 0x7f))
+                       MMC_STR_STP_CLK |= STR_STP_CLK_STOP_CLK;
+
+               if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)) {
+                       /* Check twice before cut */
+                       if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN))
+                               return;
+               }
+
+               i++;
+       }
+       dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n");
+}
+
+static int imxmci_start_clock(struct imxmci_host *host)
+{
+       unsigned int trials = 0;
+       unsigned int delay_limit = 128;
+       unsigned long flags;
+
+       MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK;
+
+       clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
+
+       /*
+        * Command start of the clock, this usually succeeds in less
+        * then 6 delay loops, but during card detection (low clockrate)
+        * it takes up to 5000 delay loops and sometimes fails for the first time
+        */
+       MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
+
+       do {
+               unsigned int delay = delay_limit;
+
+               while(delay--){
+                       if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
+                               /* Check twice before cut */
+                               if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
+                                       return 0;
+
+                       if(test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
+                               return 0;
+               }
+
+               local_irq_save(flags);
+               /*
+                * Ensure, that request is not doubled under all possible circumstances.
+                * It is possible, that cock running state is missed, because some other
+                * IRQ or schedule delays this function execution and the clocks has
+                * been already stopped by other means (response processing, SDHC HW)
+                */
+               if(!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
+                       MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
+               local_irq_restore(flags);
+
+       } while(++trials<256);
+
+       dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n");
+
+       return -1;
+}
+
+static void imxmci_softreset(void)
+{
+       /* reset sequence */
+       MMC_STR_STP_CLK = 0x8;
+       MMC_STR_STP_CLK = 0xD;
+       MMC_STR_STP_CLK = 0x5;
+       MMC_STR_STP_CLK = 0x5;
+       MMC_STR_STP_CLK = 0x5;
+       MMC_STR_STP_CLK = 0x5;
+       MMC_STR_STP_CLK = 0x5;
+       MMC_STR_STP_CLK = 0x5;
+       MMC_STR_STP_CLK = 0x5;
+       MMC_STR_STP_CLK = 0x5;
+
+       MMC_RES_TO = 0xff;
+       MMC_BLK_LEN = 512;
+       MMC_NOB = 1;
+}
+
+static int imxmci_busy_wait_for_status(struct imxmci_host *host,
+                       unsigned int *pstat, unsigned int stat_mask,
+                       int timeout, const char *where)
+{
+       int loops=0;
+       while(!(*pstat & stat_mask)) {
+               loops+=2;
+               if(loops >= timeout) {
+                       dev_dbg(mmc_dev(host->mmc), "busy wait timeout in %s, STATUS = 0x%x (0x%x)\n",
+                               where, *pstat, stat_mask);
+                       return -1;
+               }
+               udelay(2);
+               *pstat |= MMC_STATUS;
+       }
+       if(!loops)
+               return 0;
+
+       /* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */
+       if(!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock>=8000000))
+               dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n",
+                       loops, where, *pstat, stat_mask);
+       return loops;
+}
+
+static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
+{
+       unsigned int nob = data->blocks;
+       unsigned int blksz = data->blksz;
+       unsigned int datasz = nob * blksz;
+       int i;
+
+       if (data->flags & MMC_DATA_STREAM)
+               nob = 0xffff;
+
+       host->data = data;
+       data->bytes_xfered = 0;
+
+       MMC_NOB = nob;
+       MMC_BLK_LEN = blksz;
+
+       /*
+        * DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise.
+        * We are in big troubles for non-512 byte transfers according to note in the paragraph
+        * 20.6.7 of User Manual anyway, but we need to be able to transfer SCR at least.
+        * The situation is even more complex in reality. The SDHC in not able to handle wll
+        * partial FIFO fills and reads. The length has to be rounded up to burst size multiple.
+        * This is required for SCR read at least.
+        */
+       if (datasz < 512) {
+               host->dma_size = datasz;
+               if (data->flags & MMC_DATA_READ) {
+                       host->dma_dir = DMA_FROM_DEVICE;
+
+                       /* Hack to enable read SCR */
+                       MMC_NOB = 1;
+                       MMC_BLK_LEN = 512;
+               } else {
+                       host->dma_dir = DMA_TO_DEVICE;
+               }
+
+               /* Convert back to virtual address */
+               host->data_ptr = (u16*)(page_address(data->sg->page) + data->sg->offset);
+               host->data_cnt = 0;
+
+               clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
+               set_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
+
+               return;
+       }
+
+       if (data->flags & MMC_DATA_READ) {
+               host->dma_dir = DMA_FROM_DEVICE;
+               host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
+                                               data->sg_len,  host->dma_dir);
+
+               imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
+                       host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_READ);
+
+               /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/
+               CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN;
+       } else {
+               host->dma_dir = DMA_TO_DEVICE;
+
+               host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
+                                               data->sg_len,  host->dma_dir);
+
+               imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
+                       host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_WRITE);
+
+               /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/
+               CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN;
+       }
+
+#if 1  /* This code is there only for consistency checking and can be disabled in future */
+       host->dma_size = 0;
+       for(i=0; i<host->dma_nents; i++)
+               host->dma_size+=data->sg[i].length;
+
+       if (datasz > host->dma_size) {
+               dev_err(mmc_dev(host->mmc), "imxmci_setup_data datasz 0x%x > 0x%x dm_size\n",
+                      datasz, host->dma_size);
+       }
+#endif
+
+       host->dma_size = datasz;
+
+       wmb();
+
+       if(host->actual_bus_width == MMC_BUS_WIDTH_4)
+               BLR(host->dma) = 0;     /* burst 64 byte read / 64 bytes write */
+       else
+               BLR(host->dma) = 16;    /* burst 16 byte read / 16 bytes write */
+
+       RSSR(host->dma) = DMA_REQ_SDHC;
+
+       set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
+       clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
+
+       /* start DMA engine for read, write is delayed after initial response */
+       if (host->dma_dir == DMA_FROM_DEVICE) {
+               imx_dma_enable(host->dma);
+       }
+}
+
+static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat)
+{
+       unsigned long flags;
+       u32 imask;
+
+       WARN_ON(host->cmd != NULL);
+       host->cmd = cmd;
+
+       /* Ensure, that clock are stopped else command programming and start fails */
+       imxmci_stop_clock(host);
+
+       if (cmd->flags & MMC_RSP_BUSY)
+               cmdat |= CMD_DAT_CONT_BUSY;
+
+       switch (mmc_resp_type(cmd)) {
+       case MMC_RSP_R1: /* short CRC, OPCODE */
+       case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */
+               cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1;
+               break;
+       case MMC_RSP_R2: /* long 136 bit + CRC */
+               cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2;
+               break;
+       case MMC_RSP_R3: /* short */
+               cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3;
+               break;
+       default:
+               break;
+       }
+
+       if ( test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events) )
+               cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */
+
+       if ( host->actual_bus_width == MMC_BUS_WIDTH_4 )
+               cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
+
+       MMC_CMD = cmd->opcode;
+       MMC_ARGH = cmd->arg >> 16;
+       MMC_ARGL = cmd->arg & 0xffff;
+       MMC_CMD_DAT_CONT = cmdat;
+
+       atomic_set(&host->stuck_timeout, 0);
+       set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events);
+
+
+       imask = IMXMCI_INT_MASK_DEFAULT;
+       imask &= ~INT_MASK_END_CMD_RES;
+       if ( cmdat & CMD_DAT_CONT_DATA_ENABLE ) {
+               /*imask &= ~INT_MASK_BUF_READY;*/
+               imask &= ~INT_MASK_DATA_TRAN;
+               if ( cmdat & CMD_DAT_CONT_WRITE )
+                       imask &= ~INT_MASK_WRITE_OP_DONE;
+               if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
+                       imask &= ~INT_MASK_BUF_READY;
+       }
+
+       spin_lock_irqsave(&host->lock, flags);
+       host->imask = imask;
+       MMC_INT_MASK = host->imask;
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n",
+               cmd->opcode, cmd->opcode, imask);
+
+       imxmci_start_clock(host);
+}
+
+static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *req)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       host->pending_events &= ~(IMXMCI_PEND_WAIT_RESP_m | IMXMCI_PEND_DMA_END_m |
+                       IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m);
+
+       host->imask = IMXMCI_INT_MASK_DEFAULT;
+       MMC_INT_MASK = host->imask;
+
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       if(req && req->cmd)
+               host->prev_cmd_code = req->cmd->opcode;
+
+       host->req = NULL;
+       host->cmd = NULL;
+       host->data = NULL;
+       mmc_request_done(host->mmc, req);
+}
+
+static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat)
+{
+       struct mmc_data *data = host->data;
+       int data_error;
+
+       if(test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)){
+               imx_dma_disable(host->dma);
+               dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents,
+                            host->dma_dir);
+       }
+
+       if ( stat & STATUS_ERR_MASK ) {
+               dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat);
+               if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR))
+                       data->error = MMC_ERR_BADCRC;
+               else if(stat & STATUS_TIME_OUT_READ)
+                       data->error = MMC_ERR_TIMEOUT;
+               else
+                       data->error = MMC_ERR_FAILED;
+       } else {
+               data->bytes_xfered = host->dma_size;
+       }
+
+       data_error = data->error;
+
+       host->data = NULL;
+
+       return data_error;
+}
+
+static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
+{
+       struct mmc_command *cmd = host->cmd;
+       int i;
+       u32 a,b,c;
+       struct mmc_data *data = host->data;
+
+       if (!cmd)
+               return 0;
+
+       host->cmd = NULL;
+
+       if (stat & STATUS_TIME_OUT_RESP) {
+               dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n");
+               cmd->error = MMC_ERR_TIMEOUT;
+       } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
+               dev_dbg(mmc_dev(host->mmc), "cmd crc error\n");
+               cmd->error = MMC_ERR_BADCRC;
+       }
+
+       if(cmd->flags & MMC_RSP_PRESENT) {
+               if(cmd->flags & MMC_RSP_136) {
+                       for (i = 0; i < 4; i++) {
+                               u32 a = MMC_RES_FIFO & 0xffff;
+                               u32 b = MMC_RES_FIFO & 0xffff;
+                               cmd->resp[i] = a<<16 | b;
+                       }
+               } else {
+                       a = MMC_RES_FIFO & 0xffff;
+                       b = MMC_RES_FIFO & 0xffff;
+                       c = MMC_RES_FIFO & 0xffff;
+                       cmd->resp[0] = a<<24 | b<<8 | c>>8;
+               }
+       }
+
+       dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n",
+               cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error);
+
+       if (data && (cmd->error == MMC_ERR_NONE) && !(stat & STATUS_ERR_MASK)) {
+               if (host->req->data->flags & MMC_DATA_WRITE) {
+
+                       /* Wait for FIFO to be empty before starting DMA write */
+
+                       stat = MMC_STATUS;
+                       if(imxmci_busy_wait_for_status(host, &stat,
+                               STATUS_APPL_BUFF_FE,
+                               40, "imxmci_cmd_done DMA WR") < 0) {
+                               cmd->error = MMC_ERR_FIFO;
+                               imxmci_finish_data(host, stat);
+                               if(host->req)
+                                       imxmci_finish_request(host, host->req);
+                               dev_warn(mmc_dev(host->mmc), "STATUS = 0x%04x\n",
+                                      stat);
+                               return 0;
+                       }
+
+                       if(test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
+                               imx_dma_enable(host->dma);
+                       }
+               }
+       } else {
+               struct mmc_request *req;
+               imxmci_stop_clock(host);
+               req = host->req;
+
+               if(data)
+                       imxmci_finish_data(host, stat);
+
+               if( req ) {
+                       imxmci_finish_request(host, req);
+               } else {
+                       dev_warn(mmc_dev(host->mmc), "imxmci_cmd_done: no request to finish\n");
+               }
+       }
+
+       return 1;
+}
+
+static int imxmci_data_done(struct imxmci_host *host, unsigned int stat)
+{
+       struct mmc_data *data = host->data;
+       int data_error;
+
+       if (!data)
+               return 0;
+
+       data_error = imxmci_finish_data(host, stat);
+
+       if (host->req->stop) {
+               imxmci_stop_clock(host);
+               imxmci_start_cmd(host, host->req->stop, 0);
+       } else {
+               struct mmc_request *req;
+               req = host->req;
+               if( req ) {
+                       imxmci_finish_request(host, req);
+               } else {
+                       dev_warn(mmc_dev(host->mmc), "imxmci_data_done: no request to finish\n");
+               }
+       }
+
+       return 1;
+}
+
+static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
+{
+       int i;
+       int burst_len;
+       int trans_done = 0;
+       unsigned int stat = *pstat;
+
+       if(host->actual_bus_width != MMC_BUS_WIDTH_4)
+               burst_len = 16;
+       else
+               burst_len = 64;
+
+       /* This is unfortunately required */
+       dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data running STATUS = 0x%x\n",
+               stat);
+
+       udelay(20);     /* required for clocks < 8MHz*/
+
+       if(host->dma_dir == DMA_FROM_DEVICE) {
+               imxmci_busy_wait_for_status(host, &stat,
+                               STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE |
+                               STATUS_TIME_OUT_READ,
+                               50, "imxmci_cpu_driven_data read");
+
+               while((stat & (STATUS_APPL_BUFF_FF |  STATUS_DATA_TRANS_DONE)) &&
+                     !(stat & STATUS_TIME_OUT_READ) &&
+                     (host->data_cnt < 512)) {
+
+                       udelay(20);     /* required for clocks < 8MHz*/
+
+                       for(i = burst_len; i>=2 ; i-=2) {
+                               u16 data;
+                               data = MMC_BUFFER_ACCESS;
+                               udelay(10);     /* required for clocks < 8MHz*/
+                               if(host->data_cnt+2 <= host->dma_size) {
+                                       *(host->data_ptr++) = data;
+                               } else {
+                                       if(host->data_cnt < host->dma_size)
+                                               *(u8*)(host->data_ptr) = data;
+                               }
+                               host->data_cnt += 2;
+                       }
+
+                       stat = MMC_STATUS;
+
+                       dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read %d burst %d STATUS = 0x%x\n",
+                               host->data_cnt, burst_len, stat);
+               }
+
+               if((stat & STATUS_DATA_TRANS_DONE) && (host->data_cnt >= 512))
+                       trans_done = 1;
+
+               if(host->dma_size & 0x1ff)
+                       stat &= ~STATUS_CRC_READ_ERR;
+
+               if(stat & STATUS_TIME_OUT_READ) {
+                       dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read timeout STATUS = 0x%x\n",
+                               stat);
+                       trans_done = -1;
+               }
+
+       } else {
+               imxmci_busy_wait_for_status(host, &stat,
+                               STATUS_APPL_BUFF_FE,
+                               20, "imxmci_cpu_driven_data write");
+
+               while((stat & STATUS_APPL_BUFF_FE) &&
+                     (host->data_cnt < host->dma_size)) {
+                       if(burst_len >= host->dma_size - host->data_cnt) {
+                               burst_len = host->dma_size - host->data_cnt;
+                               host->data_cnt = host->dma_size;
+                               trans_done = 1;
+                       } else {
+                               host->data_cnt += burst_len;
+                       }
+
+                       for(i = burst_len; i>0 ; i-=2)
+                               MMC_BUFFER_ACCESS = *(host->data_ptr++);
+
+                       stat = MMC_STATUS;
+
+                       dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n",
+                               burst_len, stat);
+               }
+       }
+
+       *pstat = stat;
+
+       return trans_done;
+}
+
+static void imxmci_dma_irq(int dma, void *devid)
+{
+       struct imxmci_host *host = devid;
+       uint32_t stat = MMC_STATUS;
+
+       atomic_set(&host->stuck_timeout, 0);
+       host->status_reg = stat;
+       set_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
+       tasklet_schedule(&host->tasklet);
+}
+
+static irqreturn_t imxmci_irq(int irq, void *devid)
+{
+       struct imxmci_host *host = devid;
+       uint32_t stat = MMC_STATUS;
+       int handled = 1;
+
+       MMC_INT_MASK = host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT;
+
+       atomic_set(&host->stuck_timeout, 0);
+       host->status_reg = stat;
+       set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
+       set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
+       tasklet_schedule(&host->tasklet);
+
+       return IRQ_RETVAL(handled);;
+}
+
+static void imxmci_tasklet_fnc(unsigned long data)
+{
+       struct imxmci_host *host = (struct imxmci_host *)data;
+       u32 stat;
+       unsigned int data_dir_mask = 0; /* STATUS_WR_CRC_ERROR_CODE_MASK */
+       int timeout = 0;
+
+       if(atomic_read(&host->stuck_timeout) > 4) {
+               char *what;
+               timeout = 1;
+               stat = MMC_STATUS;
+               host->status_reg = stat;
+               if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+                       if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
+                               what = "RESP+DMA";
+                       else
+                               what = "RESP";
+               else
+                       if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
+                               if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events))
+                                       what = "DATA";
+                               else
+                                       what = "DMA";
+                       else
+                               what = "???";
+
+               dev_err(mmc_dev(host->mmc), "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n",
+                      what, stat, MMC_INT_MASK);
+               dev_err(mmc_dev(host->mmc), "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n",
+                      MMC_CMD_DAT_CONT, MMC_BLK_LEN, MMC_NOB, CCR(host->dma));
+               dev_err(mmc_dev(host->mmc), "CMD%d, prevCMD%d, bus %d-bit, dma_size = 0x%x\n",
+                      host->cmd?host->cmd->opcode:0, host->prev_cmd_code, 1<<host->actual_bus_width, host->dma_size);
+       }
+
+       if(!host->present || timeout)
+               host->status_reg = STATUS_TIME_OUT_RESP | STATUS_TIME_OUT_READ |
+                                   STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR;
+
+       if(test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) {
+               clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
+
+               stat = MMC_STATUS;
+               /*
+                * This is not required in theory, but there is chance to miss some flag
+                * which clears automatically by mask write, FreeScale original code keeps
+                * stat from IRQ time so do I
+                */
+               stat |= host->status_reg;
+
+               if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
+                       stat &= ~STATUS_CRC_READ_ERR;
+
+               if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
+                       imxmci_busy_wait_for_status(host, &stat,
+                                       STATUS_END_CMD_RESP | STATUS_ERR_MASK,
+                                       20, "imxmci_tasklet_fnc resp (ERRATUM #4)");
+               }
+
+               if(stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) {
+                       if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+                               imxmci_cmd_done(host, stat);
+                       if(host->data && (stat & STATUS_ERR_MASK))
+                               imxmci_data_done(host, stat);
+               }
+
+               if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) {
+                       stat |= MMC_STATUS;
+                       if(imxmci_cpu_driven_data(host, &stat)){
+                               if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+                                       imxmci_cmd_done(host, stat);
+                               atomic_clear_mask(IMXMCI_PEND_IRQ_m|IMXMCI_PEND_CPU_DATA_m,
+                                                       &host->pending_events);
+                               imxmci_data_done(host, stat);
+                       }
+               }
+       }
+
+       if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) &&
+          !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
+
+               stat = MMC_STATUS;
+               /* Same as above */
+               stat |= host->status_reg;
+
+               if(host->dma_dir == DMA_TO_DEVICE) {
+                       data_dir_mask = STATUS_WRITE_OP_DONE;
+               } else {
+                       data_dir_mask = STATUS_DATA_TRANS_DONE;
+               }
+
+               if(stat & data_dir_mask) {
+                       clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
+                       imxmci_data_done(host, stat);
+               }
+       }
+
+       if(test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) {
+
+               if(host->cmd)
+                       imxmci_cmd_done(host, STATUS_TIME_OUT_RESP);
+
+               if(host->data)
+                       imxmci_data_done(host, STATUS_TIME_OUT_READ |
+                                        STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR);
+
+               if(host->req)
+                       imxmci_finish_request(host, host->req);
+
+               mmc_detect_change(host->mmc, msecs_to_jiffies(100));
+
+       }
+}
+
+static void imxmci_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+       struct imxmci_host *host = mmc_priv(mmc);
+       unsigned int cmdat;
+
+       WARN_ON(host->req != NULL);
+
+       host->req = req;
+
+       cmdat = 0;
+
+       if (req->data) {
+               imxmci_setup_data(host, req->data);
+
+               cmdat |= CMD_DAT_CONT_DATA_ENABLE;
+
+               if (req->data->flags & MMC_DATA_WRITE)
+                       cmdat |= CMD_DAT_CONT_WRITE;
+
+               if (req->data->flags & MMC_DATA_STREAM) {
+                       cmdat |= CMD_DAT_CONT_STREAM_BLOCK;
+               }
+       }
+
+       imxmci_start_cmd(host, req->cmd, cmdat);
+}
+
+#define CLK_RATE 19200000
+
+static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct imxmci_host *host = mmc_priv(mmc);
+       int prescaler;
+
+       if( ios->bus_width==MMC_BUS_WIDTH_4 ) {
+               host->actual_bus_width = MMC_BUS_WIDTH_4;
+               imx_gpio_mode(PB11_PF_SD_DAT3);
+       }else{
+               host->actual_bus_width = MMC_BUS_WIDTH_1;
+               imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
+       }
+
+       if ( host->power_mode != ios->power_mode ) {
+               switch (ios->power_mode) {
+               case MMC_POWER_OFF:
+                       break;
+               case MMC_POWER_UP:
+                       set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
+                       break;
+               case MMC_POWER_ON:
+                       break;
+               }
+               host->power_mode = ios->power_mode;
+       }
+
+       if ( ios->clock ) {
+               unsigned int clk;
+
+               /* The prescaler is 5 for PERCLK2 equal to 96MHz
+                * then 96MHz / 5 = 19.2 MHz
+                */
+               clk=imx_get_perclk2();
+               prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE;
+               switch(prescaler) {
+               case 0:
+               case 1: prescaler = 0;
+                       break;
+               case 2: prescaler = 1;
+                       break;
+               case 3: prescaler = 2;
+                       break;
+               case 4: prescaler = 4;
+                       break;
+               default:
+               case 5: prescaler = 5;
+                       break;
+               }
+
+               dev_dbg(mmc_dev(host->mmc), "PERCLK2 %d MHz -> prescaler %d\n",
+                       clk, prescaler);
+
+               for(clk=0; clk<8; clk++) {
+                       int x;
+                       x = CLK_RATE / (1<<clk);
+                       if( x <= ios->clock)
+                               break;
+               }
+
+               MMC_STR_STP_CLK |= STR_STP_CLK_ENABLE; /* enable controller */
+
+               imxmci_stop_clock(host);
+               MMC_CLK_RATE = (prescaler<<3) | clk;
+               /*
+                * Under my understanding, clock should not be started there, because it would
+                * initiate SDHC sequencer and send last or random command into card
+                */
+               /*imxmci_start_clock(host);*/
+
+               dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE);
+       } else {
+               imxmci_stop_clock(host);
+       }
+}
+
+static const struct mmc_host_ops imxmci_ops = {
+       .request        = imxmci_request,
+       .set_ios        = imxmci_set_ios,
+};
+
+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() != host->present ) {
+               host->present ^= 1;
+               dev_info(mmc_dev(host->mmc), "card %s\n",
+                     host->present ? "inserted" : "removed");
+
+               set_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events);
+               tasklet_schedule(&host->tasklet);
+       }
+
+       if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) ||
+          test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
+               atomic_inc(&host->stuck_timeout);
+               if(atomic_read(&host->stuck_timeout) > 4)
+                       tasklet_schedule(&host->tasklet);
+       } else {
+               atomic_set(&host->stuck_timeout, 0);
+
+       }
+
+       mod_timer(&host->timer, jiffies + (HZ>>1));
+}
+
+static int imxmci_probe(struct platform_device *pdev)
+{
+       struct mmc_host *mmc;
+       struct imxmci_host *host = NULL;
+       struct resource *r;
+       int ret = 0, irq;
+
+       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)
+               return -ENXIO;
+
+       r = request_mem_region(r->start, 0x100, "IMXMCI");
+       if (!r)
+               return -EBUSY;
+
+       mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev);
+       if (!mmc) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       mmc->ops = &imxmci_ops;
+       mmc->f_min = 150000;
+       mmc->f_max = CLK_RATE/2;
+       mmc->ocr_avail = MMC_VDD_32_33;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_BYTEBLOCK;
+
+       /* MMC core transfer sizes tunable parameters */
+       mmc->max_hw_segs = 64;
+       mmc->max_phys_segs = 64;
+       mmc->max_seg_size = 64*512;     /* default PAGE_CACHE_SIZE */
+       mmc->max_req_size = 64*512;     /* default PAGE_CACHE_SIZE */
+       mmc->max_blk_size = 2048;
+       mmc->max_blk_count = 65535;
+
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+       host->dma_allocated = 0;
+       host->pdata = pdev->dev.platform_data;
+
+       spin_lock_init(&host->lock);
+       host->res = r;
+       host->irq = irq;
+
+       imx_gpio_mode(PB8_PF_SD_DAT0);
+       imx_gpio_mode(PB9_PF_SD_DAT1);
+       imx_gpio_mode(PB10_PF_SD_DAT2);
+       /* Configured as GPIO with pull-up to ensure right MCC card mode */
+       /* Switched to PB11_PF_SD_DAT3 if 4 bit bus is configured */
+       imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
+       /* imx_gpio_mode(PB11_PF_SD_DAT3); */
+       imx_gpio_mode(PB12_PF_SD_CLK);
+       imx_gpio_mode(PB13_PF_SD_CMD);
+
+       imxmci_softreset();
+
+       if ( MMC_REV_NO != 0x390 ) {
+               dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
+                       MMC_REV_NO);
+               goto out;
+       }
+
+       MMC_READ_TO = 0x2db4; /* recommended in data sheet */
+
+       host->imask = IMXMCI_INT_MASK_DEFAULT;
+       MMC_INT_MASK = host->imask;
+
+
+       if(imx_dma_request_by_prio(&host->dma, DRIVER_NAME, DMA_PRIO_LOW)<0){
+               dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n");
+               ret = -EBUSY;
+               goto out;
+       }
+       host->dma_allocated=1;
+       imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host);
+
+       tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host);
+       host->status_reg=0;
+       host->pending_events=0;
+
+       ret = request_irq(host->irq, imxmci_irq, 0, DRIVER_NAME, host);
+       if (ret)
+               goto out;
+
+       host->present = host->pdata->card_present();
+       init_timer(&host->timer);
+       host->timer.data = (unsigned long)host;
+       host->timer.function = imxmci_check_status;
+       add_timer(&host->timer);
+       mod_timer(&host->timer, jiffies + (HZ>>1));
+
+       platform_set_drvdata(pdev, mmc);
+
+       mmc_add_host(mmc);
+
+       return 0;
+
+out:
+       if (host) {
+               if(host->dma_allocated){
+                       imx_dma_free(host->dma);
+                       host->dma_allocated=0;
+               }
+       }
+       if (mmc)
+               mmc_free_host(mmc);
+       release_resource(r);
+       return ret;
+}
+
+static int imxmci_remove(struct platform_device *pdev)
+{
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (mmc) {
+               struct imxmci_host *host = mmc_priv(mmc);
+
+               tasklet_disable(&host->tasklet);
+
+               del_timer_sync(&host->timer);
+               mmc_remove_host(mmc);
+
+               free_irq(host->irq, host);
+               if(host->dma_allocated){
+                       imx_dma_free(host->dma);
+                       host->dma_allocated=0;
+               }
+
+               tasklet_kill(&host->tasklet);
+
+               release_resource(host->res);
+
+               mmc_free_host(mmc);
+       }
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int imxmci_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct mmc_host *mmc = platform_get_drvdata(dev);
+       int ret = 0;
+
+       if (mmc)
+               ret = mmc_suspend_host(mmc, state);
+
+       return ret;
+}
+
+static int imxmci_resume(struct platform_device *dev)
+{
+       struct mmc_host *mmc = platform_get_drvdata(dev);
+       struct imxmci_host *host;
+       int ret = 0;
+
+       if (mmc) {
+               host = mmc_priv(mmc);
+               if(host)
+                       set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
+               ret = mmc_resume_host(mmc);
+       }
+
+       return ret;
+}
+#else
+#define imxmci_suspend  NULL
+#define imxmci_resume   NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver imxmci_driver = {
+       .probe          = imxmci_probe,
+       .remove         = imxmci_remove,
+       .suspend        = imxmci_suspend,
+       .resume         = imxmci_resume,
+       .driver         = {
+               .name           = DRIVER_NAME,
+       }
+};
+
+static int __init imxmci_init(void)
+{
+       return platform_driver_register(&imxmci_driver);
+}
+
+static void __exit imxmci_exit(void)
+{
+       platform_driver_unregister(&imxmci_driver);
+}
+
+module_init(imxmci_init);
+module_exit(imxmci_exit);
+
+MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/imxmmc.h b/drivers/mmc/host/imxmmc.h
new file mode 100644 (file)
index 0000000..e5339e3
--- /dev/null
@@ -0,0 +1,67 @@
+
+# define __REG16(x)    (*((volatile u16 *)IO_ADDRESS(x)))
+
+#define MMC_STR_STP_CLK  __REG16(IMX_MMC_BASE + 0x00)
+#define MMC_STATUS       __REG16(IMX_MMC_BASE + 0x04)
+#define MMC_CLK_RATE     __REG16(IMX_MMC_BASE + 0x08)
+#define MMC_CMD_DAT_CONT __REG16(IMX_MMC_BASE + 0x0C)
+#define MMC_RES_TO       __REG16(IMX_MMC_BASE + 0x10)
+#define MMC_READ_TO      __REG16(IMX_MMC_BASE + 0x14)
+#define MMC_BLK_LEN      __REG16(IMX_MMC_BASE + 0x18)
+#define MMC_NOB          __REG16(IMX_MMC_BASE + 0x1C)
+#define MMC_REV_NO       __REG16(IMX_MMC_BASE + 0x20)
+#define MMC_INT_MASK     __REG16(IMX_MMC_BASE + 0x24)
+#define MMC_CMD          __REG16(IMX_MMC_BASE + 0x28)
+#define MMC_ARGH         __REG16(IMX_MMC_BASE + 0x2C)
+#define MMC_ARGL         __REG16(IMX_MMC_BASE + 0x30)
+#define MMC_RES_FIFO     __REG16(IMX_MMC_BASE + 0x34)
+#define MMC_BUFFER_ACCESS __REG16(IMX_MMC_BASE + 0x38)
+#define MMC_BUFFER_ACCESS_OFS 0x38
+
+
+#define STR_STP_CLK_ENDIAN              (1<<5)
+#define STR_STP_CLK_RESET               (1<<3)
+#define STR_STP_CLK_ENABLE              (1<<2)
+#define STR_STP_CLK_START_CLK           (1<<1)
+#define STR_STP_CLK_STOP_CLK            (1<<0)
+#define STATUS_CARD_PRESENCE            (1<<15)
+#define STATUS_SDIO_INT_ACTIVE          (1<<14)
+#define STATUS_END_CMD_RESP             (1<<13)
+#define STATUS_WRITE_OP_DONE            (1<<12)
+#define STATUS_DATA_TRANS_DONE          (1<<11)
+#define STATUS_WR_CRC_ERROR_CODE_MASK   (3<<10)
+#define STATUS_CARD_BUS_CLK_RUN         (1<<8)
+#define STATUS_APPL_BUFF_FF             (1<<7)
+#define STATUS_APPL_BUFF_FE             (1<<6)
+#define STATUS_RESP_CRC_ERR             (1<<5)
+#define STATUS_CRC_READ_ERR             (1<<3)
+#define STATUS_CRC_WRITE_ERR            (1<<2)
+#define STATUS_TIME_OUT_RESP            (1<<1)
+#define STATUS_TIME_OUT_READ            (1<<0)
+#define STATUS_ERR_MASK                 0x2f
+#define CLK_RATE_PRESCALER(x)           ((x) & 0x7)
+#define CLK_RATE_CLK_RATE(x)            (((x) & 0x7) << 3)
+#define CMD_DAT_CONT_CMD_RESP_LONG_OFF  (1<<12)
+#define CMD_DAT_CONT_STOP_READWAIT      (1<<11)
+#define CMD_DAT_CONT_START_READWAIT     (1<<10)
+#define CMD_DAT_CONT_BUS_WIDTH_1        (0<<8)
+#define CMD_DAT_CONT_BUS_WIDTH_4        (2<<8)
+#define CMD_DAT_CONT_INIT               (1<<7)
+#define CMD_DAT_CONT_BUSY               (1<<6)
+#define CMD_DAT_CONT_STREAM_BLOCK       (1<<5)
+#define CMD_DAT_CONT_WRITE              (1<<4)
+#define CMD_DAT_CONT_DATA_ENABLE        (1<<3)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R1 (1)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R2 (2)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R3 (3)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R4 (4)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R5 (5)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R6 (6)
+#define INT_MASK_AUTO_CARD_DETECT       (1<<6)
+#define INT_MASK_DAT0_EN                (1<<5)
+#define INT_MASK_SDIO                   (1<<4)
+#define INT_MASK_BUF_READY              (1<<3)
+#define INT_MASK_END_CMD_RES            (1<<2)
+#define INT_MASK_WRITE_OP_DONE          (1<<1)
+#define INT_MASK_DATA_TRAN              (1<<0)
+#define INT_ALL                         (0x7f)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
new file mode 100644 (file)
index 0000000..d11c2d2
--- /dev/null
@@ -0,0 +1,702 @@
+/*
+ *  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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/highmem.h>
+#include <linux/mmc/host.h>
+#include <linux/amba/bus.h>
+#include <linux/clk.h>
+
+#include <asm/cacheflush.h>
+#include <asm/div64.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <asm/sizes.h>
+#include <asm/mach/mmc.h>
+
+#include "mmci.h"
+
+#define DRIVER_NAME "mmci-pl18x"
+
+#define DBG(host,fmt,args...)  \
+       pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
+
+static unsigned int fmax = 515633;
+
+static void
+mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
+{
+       writel(0, host->base + MMCICOMMAND);
+
+       BUG_ON(host->data);
+
+       host->mrq = NULL;
+       host->cmd = NULL;
+
+       if (mrq->data)
+               mrq->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, mrq);
+       spin_lock(&host->lock);
+}
+
+static void mmci_stop_data(struct mmci_host *host)
+{
+       writel(0, host->base + MMCIDATACTRL);
+       writel(0, host->base + MMCIMASK1);
+       host->data = NULL;
+}
+
+static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
+{
+       unsigned int datactrl, timeout, irqmask;
+       unsigned long long clks;
+       void __iomem *base;
+       int blksz_bits;
+
+       DBG(host, "blksz %04x blks %04x flags %08x\n",
+           data->blksz, data->blocks, data->flags);
+
+       host->data = data;
+       host->size = data->blksz;
+       host->data_xfered = 0;
+
+       mmci_init_sg(host, data);
+
+       clks = (unsigned long long)data->timeout_ns * host->cclk;
+       do_div(clks, 1000000000UL);
+
+       timeout = data->timeout_clks + (unsigned int)clks;
+
+       base = host->base;
+       writel(timeout, base + MMCIDATATIMER);
+       writel(host->size, base + MMCIDATALENGTH);
+
+       blksz_bits = ffs(data->blksz) - 1;
+       BUG_ON(1 << blksz_bits != data->blksz);
+
+       datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
+       if (data->flags & MMC_DATA_READ) {
+               datactrl |= MCI_DPSM_DIRECTION;
+               irqmask = MCI_RXFIFOHALFFULLMASK;
+
+               /*
+                * If we have less than a FIFOSIZE of bytes to transfer,
+                * trigger a PIO interrupt as soon as any data is available.
+                */
+               if (host->size < MCI_FIFOSIZE)
+                       irqmask |= MCI_RXDATAAVLBLMASK;
+       } else {
+               /*
+                * We don't actually need to include "FIFO empty" here
+                * since its implicit in "FIFO half empty".
+                */
+               irqmask = MCI_TXFIFOHALFEMPTYMASK;
+       }
+
+       writel(datactrl, base + MMCIDATACTRL);
+       writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
+       writel(irqmask, base + MMCIMASK1);
+}
+
+static void
+mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
+{
+       void __iomem *base = host->base;
+
+       DBG(host, "op %02x arg %08x flags %08x\n",
+           cmd->opcode, cmd->arg, cmd->flags);
+
+       if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
+               writel(0, base + MMCICOMMAND);
+               udelay(1);
+       }
+
+       c |= cmd->opcode | MCI_CPSM_ENABLE;
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               if (cmd->flags & MMC_RSP_136)
+                       c |= MCI_CPSM_LONGRSP;
+               c |= MCI_CPSM_RESPONSE;
+       }
+       if (/*interrupt*/0)
+               c |= MCI_CPSM_INTERRUPT;
+
+       host->cmd = cmd;
+
+       writel(cmd->arg, base + MMCIARGUMENT);
+       writel(c, 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 += data->blksz;
+       }
+       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;
+
+               /*
+                * We hit an error condition.  Ensure that any data
+                * partially written to a page is properly coherent.
+                */
+               if (host->sg_len && data->flags & MMC_DATA_READ)
+                       flush_dcache_page(host->sg_ptr->page);
+       }
+       if (status & MCI_DATAEND) {
+               mmci_stop_data(host);
+
+               if (!data->stop) {
+                       mmci_request_end(host, data->mrq);
+               } else {
+                       mmci_start_command(host, data->stop, 0);
+               }
+       }
+}
+
+static void
+mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
+            unsigned int status)
+{
+       void __iomem *base = host->base;
+
+       host->cmd = NULL;
+
+       cmd->resp[0] = readl(base + MMCIRESPONSE0);
+       cmd->resp[1] = readl(base + MMCIRESPONSE1);
+       cmd->resp[2] = readl(base + MMCIRESPONSE2);
+       cmd->resp[3] = readl(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) {
+               if (host->data)
+                       mmci_stop_data(host);
+               mmci_request_end(host, cmd->mrq);
+       } else if (!(cmd->data->flags & MMC_DATA_READ)) {
+               mmci_start_data(host, cmd->data);
+       }
+}
+
+static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain)
+{
+       void __iomem *base = host->base;
+       char *ptr = buffer;
+       u32 status;
+
+       do {
+               int count = host->size - (readl(base + MMCIFIFOCNT) << 2);
+
+               if (count > remain)
+                       count = remain;
+
+               if (count <= 0)
+                       break;
+
+               readsl(base + MMCIFIFO, ptr, count >> 2);
+
+               ptr += count;
+               remain -= count;
+
+               if (remain == 0)
+                       break;
+
+               status = readl(base + MMCISTATUS);
+       } while (status & MCI_RXDATAAVLBL);
+
+       return ptr - buffer;
+}
+
+static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status)
+{
+       void __iomem *base = host->base;
+       char *ptr = buffer;
+
+       do {
+               unsigned int count, maxcnt;
+
+               maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
+               count = min(remain, maxcnt);
+
+               writesl(base + MMCIFIFO, ptr, count >> 2);
+
+               ptr += count;
+               remain -= count;
+
+               if (remain == 0)
+                       break;
+
+               status = readl(base + MMCISTATUS);
+       } while (status & MCI_TXFIFOHALFEMPTY);
+
+       return ptr - buffer;
+}
+
+/*
+ * PIO data transfer IRQ handler.
+ */
+static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
+{
+       struct mmci_host *host = dev_id;
+       void __iomem *base = host->base;
+       u32 status;
+
+       status = readl(base + MMCISTATUS);
+
+       DBG(host, "irq1 %08x\n", status);
+
+       do {
+               unsigned long flags;
+               unsigned int remain, len;
+               char *buffer;
+
+               /*
+                * For write, we only need to test the half-empty flag
+                * here - if the FIFO is completely empty, then by
+                * definition it is more than half empty.
+                *
+                * For read, check for data available.
+                */
+               if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)))
+                       break;
+
+               /*
+                * Map the current scatter buffer.
+                */
+               buffer = mmci_kmap_atomic(host, &flags) + host->sg_off;
+               remain = host->sg_ptr->length - host->sg_off;
+
+               len = 0;
+               if (status & MCI_RXACTIVE)
+                       len = mmci_pio_read(host, buffer, remain);
+               if (status & MCI_TXACTIVE)
+                       len = mmci_pio_write(host, buffer, remain, status);
+
+               /*
+                * Unmap the buffer.
+                */
+               mmci_kunmap_atomic(host, buffer, &flags);
+
+               host->sg_off += len;
+               host->size -= len;
+               remain -= len;
+
+               if (remain)
+                       break;
+
+               /*
+                * If we were reading, and we have completed this
+                * page, ensure that the data cache is coherent.
+                */
+               if (status & MCI_RXACTIVE)
+                       flush_dcache_page(host->sg_ptr->page);
+
+               if (!mmci_next_sg(host))
+                       break;
+
+               status = readl(base + MMCISTATUS);
+       } while (1);
+
+       /*
+        * If we're nearing the end of the read, switch to
+        * "any data available" mode.
+        */
+       if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE)
+               writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
+
+       /*
+        * If we run out of data, disable the data IRQs; this
+        * prevents a race where the FIFO becomes empty before
+        * the chip itself has disabled the data path, and
+        * stops us racing with our data end IRQ.
+        */
+       if (host->size == 0) {
+               writel(0, base + MMCIMASK1);
+               writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Handle completion of command and data transfers.
+ */
+static irqreturn_t mmci_irq(int irq, void *dev_id)
+{
+       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);
+               status &= readl(host->base + MMCIMASK0);
+               writel(status, host->base + MMCICLEAR);
+
+               DBG(host, "irq0 %08x\n", status);
+
+               data = host->data;
+               if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
+                             MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data)
+                       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 *mrq)
+{
+       struct mmci_host *host = mmc_priv(mmc);
+
+       WARN_ON(host->mrq != NULL);
+
+       spin_lock_irq(&host->lock);
+
+       host->mrq = mrq;
+
+       if (mrq->data && mrq->data->flags & MMC_DATA_READ)
+               mmci_start_data(host, mrq->data);
+
+       mmci_start_command(host, mrq->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;
+
+       if (ios->clock) {
+               if (ios->clock >= host->mclk) {
+                       clk = MCI_CLK_BYPASS;
+                       host->cclk = host->mclk;
+               } else {
+                       clk = host->mclk / (2 * ios->clock) - 1;
+                       if (clk > 256)
+                               clk = 255;
+                       host->cclk = host->mclk / (2 * (clk + 1));
+               }
+               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 const 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, 0);
+
+       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;
+       struct mmc_host *mmc;
+       int ret;
+
+       /* must have platform data */
+       if (!plat) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = amba_request_regions(dev, DRIVER_NAME);
+       if (ret)
+               goto out;
+
+       mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
+       if (!mmc) {
+               ret = -ENOMEM;
+               goto rel_regions;
+       }
+
+       host = mmc_priv(mmc);
+       host->clk = clk_get(&dev->dev, "MCLK");
+       if (IS_ERR(host->clk)) {
+               ret = PTR_ERR(host->clk);
+               host->clk = NULL;
+               goto host_free;
+       }
+
+       ret = clk_enable(host->clk);
+       if (ret)
+               goto clk_free;
+
+       host->plat = plat;
+       host->mclk = clk_get_rate(host->clk);
+       host->mmc = mmc;
+       host->base = ioremap(dev->res.start, SZ_4K);
+       if (!host->base) {
+               ret = -ENOMEM;
+               goto clk_disable;
+       }
+
+       mmc->ops = &mmci_ops;
+       mmc->f_min = (host->mclk + 511) / 512;
+       mmc->f_max = min(host->mclk, fmax);
+       mmc->ocr_avail = plat->ocr_mask;
+       mmc->caps = MMC_CAP_MULTIWRITE;
+
+       /*
+        * We can do SGIO
+        */
+       mmc->max_hw_segs = 16;
+       mmc->max_phys_segs = NR_SG;
+
+       /*
+        * Since we only have a 16-bit data length register, we must
+        * ensure that we don't exceed 2^16-1 bytes in a single request.
+        */
+       mmc->max_req_size = 65535;
+
+       /*
+        * Set the maximum segment size.  Since we aren't doing DMA
+        * (yet) we are only limited by the data length register.
+        */
+       mmc->max_seg_size = mmc->max_req_size;
+
+       /*
+        * Block size can be up to 2048 bytes, but must be a power of two.
+        */
+       mmc->max_blk_size = 2048;
+
+       /*
+        * No limit on the number of blocks transferred.
+        */
+       mmc->max_blk_count = mmc->max_req_size;
+
+       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, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
+       if (ret)
+               goto unmap;
+
+       ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host);
+       if (ret)
+               goto irq0_free;
+
+       writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+
+       amba_set_drvdata(dev, mmc);
+
+       mmc_add_host(mmc);
+
+       printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
+               mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
+               (unsigned long long)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;
+
+ irq0_free:
+       free_irq(dev->irq[0], host);
+ unmap:
+       iounmap(host->base);
+ clk_disable:
+       clk_disable(host->clk);
+ clk_free:
+       clk_put(host->clk);
+ host_free:
+       mmc_free_host(mmc);
+ rel_regions:
+       amba_release_regions(dev);
+ out:
+       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);
+               clk_disable(host->clk);
+               clk_put(host->clk);
+
+               mmc_free_host(mmc);
+
+               amba_release_regions(dev);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int mmci_suspend(struct amba_device *dev, pm_message_t 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 --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
new file mode 100644 (file)
index 0000000..6d7eadc
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ *  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_CLK_PWRSAVE                (1 << 9)
+#define MCI_CLK_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_IRQENABLE  \
+       (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK|     \
+       MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|       \
+       MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
+
+/*
+ * The size of the FIFO in bytes.
+ */
+#define MCI_FIFOSIZE   (16*4)
+       
+#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
+
+#define NR_SG          16
+
+struct clk;
+
+struct mmci_host {
+       void __iomem            *base;
+       struct mmc_request      *mrq;
+       struct mmc_command      *cmd;
+       struct mmc_data         *data;
+       struct mmc_host         *mmc;
+       struct clk              *clk;
+
+       unsigned int            data_xfered;
+
+       spinlock_t              lock;
+
+       unsigned int            mclk;
+       unsigned int            cclk;
+       u32                     pwr;
+       struct mmc_platform_data *plat;
+
+       struct timer_list       timer;
+       unsigned int            oldstat;
+
+       unsigned int            sg_len;
+
+       /* pio stuff */
+       struct scatterlist      *sg_ptr;
+       unsigned int            sg_off;
+       unsigned int            size;
+};
+
+static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
+{
+       /*
+        * Ideally, we want the higher levels to pass us a scatter list.
+        */
+       host->sg_len = data->sg_len;
+       host->sg_ptr = data->sg;
+       host->sg_off = 0;
+}
+
+static inline int mmci_next_sg(struct mmci_host *host)
+{
+       host->sg_ptr++;
+       host->sg_off = 0;
+       return --host->sg_len;
+}
+
+static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags)
+{
+       struct scatterlist *sg = host->sg_ptr;
+
+       local_irq_save(*flags);
+       return kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+}
+
+static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags)
+{
+       kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
+       local_irq_restore(*flags);
+}
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
new file mode 100644 (file)
index 0000000..e851384
--- /dev/null
@@ -0,0 +1,1288 @@
+/*
+ *  linux/drivers/media/mmc/omap.c
+ *
+ *  Copyright (C) 2004 Nokia Corporation
+ *  Written by Tuukka Tikkanen and Juha Yrjölä<juha.yrjola@nokia.com>
+ *  Misc hacks here and there by Tony Lindgren <tony@atomide.com>
+ *  Other hacks (DMA, SD, etc) by David Brownell
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/scatterlist.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/fpga.h>
+#include <asm/arch/tps65010.h>
+
+#define        OMAP_MMC_REG_CMD        0x00
+#define        OMAP_MMC_REG_ARGL       0x04
+#define        OMAP_MMC_REG_ARGH       0x08
+#define        OMAP_MMC_REG_CON        0x0c
+#define        OMAP_MMC_REG_STAT       0x10
+#define        OMAP_MMC_REG_IE         0x14
+#define        OMAP_MMC_REG_CTO        0x18
+#define        OMAP_MMC_REG_DTO        0x1c
+#define        OMAP_MMC_REG_DATA       0x20
+#define        OMAP_MMC_REG_BLEN       0x24
+#define        OMAP_MMC_REG_NBLK       0x28
+#define        OMAP_MMC_REG_BUF        0x2c
+#define OMAP_MMC_REG_SDIO      0x34
+#define        OMAP_MMC_REG_REV        0x3c
+#define        OMAP_MMC_REG_RSP0       0x40
+#define        OMAP_MMC_REG_RSP1       0x44
+#define        OMAP_MMC_REG_RSP2       0x48
+#define        OMAP_MMC_REG_RSP3       0x4c
+#define        OMAP_MMC_REG_RSP4       0x50
+#define        OMAP_MMC_REG_RSP5       0x54
+#define        OMAP_MMC_REG_RSP6       0x58
+#define        OMAP_MMC_REG_RSP7       0x5c
+#define        OMAP_MMC_REG_IOSR       0x60
+#define        OMAP_MMC_REG_SYSC       0x64
+#define        OMAP_MMC_REG_SYSS       0x68
+
+#define        OMAP_MMC_STAT_CARD_ERR          (1 << 14)
+#define        OMAP_MMC_STAT_CARD_IRQ          (1 << 13)
+#define        OMAP_MMC_STAT_OCR_BUSY          (1 << 12)
+#define        OMAP_MMC_STAT_A_EMPTY           (1 << 11)
+#define        OMAP_MMC_STAT_A_FULL            (1 << 10)
+#define        OMAP_MMC_STAT_CMD_CRC           (1 <<  8)
+#define        OMAP_MMC_STAT_CMD_TOUT          (1 <<  7)
+#define        OMAP_MMC_STAT_DATA_CRC          (1 <<  6)
+#define        OMAP_MMC_STAT_DATA_TOUT         (1 <<  5)
+#define        OMAP_MMC_STAT_END_BUSY          (1 <<  4)
+#define        OMAP_MMC_STAT_END_OF_DATA       (1 <<  3)
+#define        OMAP_MMC_STAT_CARD_BUSY         (1 <<  2)
+#define        OMAP_MMC_STAT_END_OF_CMD        (1 <<  0)
+
+#define OMAP_MMC_READ(host, reg)       __raw_readw((host)->virt_base + OMAP_MMC_REG_##reg)
+#define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG_##reg)
+
+/*
+ * Command types
+ */
+#define OMAP_MMC_CMDTYPE_BC    0
+#define OMAP_MMC_CMDTYPE_BCR   1
+#define OMAP_MMC_CMDTYPE_AC    2
+#define OMAP_MMC_CMDTYPE_ADTC  3
+
+
+#define DRIVER_NAME "mmci-omap"
+
+/* Specifies how often in millisecs to poll for card status changes
+ * when the cover switch is open */
+#define OMAP_MMC_SWITCH_POLL_DELAY     500
+
+static int mmc_omap_enable_poll = 1;
+
+struct mmc_omap_host {
+       int                     initialized;
+       int                     suspended;
+       struct mmc_request *    mrq;
+       struct mmc_command *    cmd;
+       struct mmc_data *       data;
+       struct mmc_host *       mmc;
+       struct device *         dev;
+       unsigned char           id; /* 16xx chips have 2 MMC blocks */
+       struct clk *            iclk;
+       struct clk *            fclk;
+       struct resource         *mem_res;
+       void __iomem            *virt_base;
+       unsigned int            phys_base;
+       int                     irq;
+       unsigned char           bus_mode;
+       unsigned char           hw_bus_mode;
+
+       unsigned int            sg_len;
+       int                     sg_idx;
+       u16 *                   buffer;
+       u32                     buffer_bytes_left;
+       u32                     total_bytes_left;
+
+       unsigned                use_dma:1;
+       unsigned                brs_received:1, dma_done:1;
+       unsigned                dma_is_read:1;
+       unsigned                dma_in_use:1;
+       int                     dma_ch;
+       spinlock_t              dma_lock;
+       struct timer_list       dma_timer;
+       unsigned                dma_len;
+
+       short                   power_pin;
+       short                   wp_pin;
+
+       int                     switch_pin;
+       struct work_struct      switch_work;
+       struct timer_list       switch_timer;
+       int                     switch_last_state;
+};
+
+static inline int
+mmc_omap_cover_is_open(struct mmc_omap_host *host)
+{
+       if (host->switch_pin < 0)
+               return 0;
+       return omap_get_gpio_datain(host->switch_pin);
+}
+
+static ssize_t
+mmc_omap_show_cover_switch(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct mmc_omap_host *host = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", mmc_omap_cover_is_open(host) ? "open" :
+                       "closed");
+}
+
+static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);
+
+static ssize_t
+mmc_omap_show_enable_poll(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", mmc_omap_enable_poll);
+}
+
+static ssize_t
+mmc_omap_store_enable_poll(struct device *dev,
+       struct device_attribute *attr, const char *buf,
+       size_t size)
+{
+       int enable_poll;
+
+       if (sscanf(buf, "%10d", &enable_poll) != 1)
+               return -EINVAL;
+
+       if (enable_poll != mmc_omap_enable_poll) {
+               struct mmc_omap_host *host = dev_get_drvdata(dev);
+
+               mmc_omap_enable_poll = enable_poll;
+               if (enable_poll && host->switch_pin >= 0)
+                       schedule_work(&host->switch_work);
+       }
+       return size;
+}
+
+static DEVICE_ATTR(enable_poll, 0664,
+                  mmc_omap_show_enable_poll, mmc_omap_store_enable_poll);
+
+static void
+mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
+{
+       u32 cmdreg;
+       u32 resptype;
+       u32 cmdtype;
+
+       host->cmd = cmd;
+
+       resptype = 0;
+       cmdtype = 0;
+
+       /* Our hardware needs to know exact type */
+       switch (mmc_resp_type(cmd)) {
+       case MMC_RSP_NONE:
+               break;
+       case MMC_RSP_R1:
+       case MMC_RSP_R1B:
+               /* resp 1, 1b, 6, 7 */
+               resptype = 1;
+               break;
+       case MMC_RSP_R2:
+               resptype = 2;
+               break;
+       case MMC_RSP_R3:
+               resptype = 3;
+               break;
+       default:
+               dev_err(mmc_dev(host->mmc), "Invalid response type: %04x\n", mmc_resp_type(cmd));
+               break;
+       }
+
+       if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) {
+               cmdtype = OMAP_MMC_CMDTYPE_ADTC;
+       } else if (mmc_cmd_type(cmd) == MMC_CMD_BC) {
+               cmdtype = OMAP_MMC_CMDTYPE_BC;
+       } else if (mmc_cmd_type(cmd) == MMC_CMD_BCR) {
+               cmdtype = OMAP_MMC_CMDTYPE_BCR;
+       } else {
+               cmdtype = OMAP_MMC_CMDTYPE_AC;
+       }
+
+       cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12);
+
+       if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
+               cmdreg |= 1 << 6;
+
+       if (cmd->flags & MMC_RSP_BUSY)
+               cmdreg |= 1 << 11;
+
+       if (host->data && !(host->data->flags & MMC_DATA_WRITE))
+               cmdreg |= 1 << 15;
+
+       clk_enable(host->fclk);
+
+       OMAP_MMC_WRITE(host, CTO, 200);
+       OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
+       OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16);
+       OMAP_MMC_WRITE(host, IE,
+                      OMAP_MMC_STAT_A_EMPTY    | OMAP_MMC_STAT_A_FULL    |
+                      OMAP_MMC_STAT_CMD_CRC    | OMAP_MMC_STAT_CMD_TOUT  |
+                      OMAP_MMC_STAT_DATA_CRC   | OMAP_MMC_STAT_DATA_TOUT |
+                      OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR  |
+                      OMAP_MMC_STAT_END_OF_DATA);
+       OMAP_MMC_WRITE(host, CMD, cmdreg);
+}
+
+static void
+mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
+{
+       if (host->dma_in_use) {
+               enum dma_data_direction dma_data_dir;
+
+               BUG_ON(host->dma_ch < 0);
+               if (data->error != MMC_ERR_NONE)
+                       omap_stop_dma(host->dma_ch);
+               /* Release DMA channel lazily */
+               mod_timer(&host->dma_timer, jiffies + HZ);
+               if (data->flags & MMC_DATA_WRITE)
+                       dma_data_dir = DMA_TO_DEVICE;
+               else
+                       dma_data_dir = DMA_FROM_DEVICE;
+               dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
+                            dma_data_dir);
+       }
+       host->data = NULL;
+       host->sg_len = 0;
+       clk_disable(host->fclk);
+
+       /* NOTE:  MMC layer will sometimes poll-wait CMD13 next, issuing
+        * dozens of requests until the card finishes writing data.
+        * It'd be cheaper to just wait till an EOFB interrupt arrives...
+        */
+
+       if (!data->stop) {
+               host->mrq = NULL;
+               mmc_request_done(host->mmc, data->mrq);
+               return;
+       }
+
+       mmc_omap_start_command(host, data->stop);
+}
+
+static void
+mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data)
+{
+       unsigned long flags;
+       int done;
+
+       if (!host->dma_in_use) {
+               mmc_omap_xfer_done(host, data);
+               return;
+       }
+       done = 0;
+       spin_lock_irqsave(&host->dma_lock, flags);
+       if (host->dma_done)
+               done = 1;
+       else
+               host->brs_received = 1;
+       spin_unlock_irqrestore(&host->dma_lock, flags);
+       if (done)
+               mmc_omap_xfer_done(host, data);
+}
+
+static void
+mmc_omap_dma_timer(unsigned long data)
+{
+       struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+
+       BUG_ON(host->dma_ch < 0);
+       omap_free_dma(host->dma_ch);
+       host->dma_ch = -1;
+}
+
+static void
+mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data)
+{
+       unsigned long flags;
+       int done;
+
+       done = 0;
+       spin_lock_irqsave(&host->dma_lock, flags);
+       if (host->brs_received)
+               done = 1;
+       else
+               host->dma_done = 1;
+       spin_unlock_irqrestore(&host->dma_lock, flags);
+       if (done)
+               mmc_omap_xfer_done(host, data);
+}
+
+static void
+mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
+{
+       host->cmd = NULL;
+
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               if (cmd->flags & MMC_RSP_136) {
+                       /* response type 2 */
+                       cmd->resp[3] =
+                               OMAP_MMC_READ(host, RSP0) |
+                               (OMAP_MMC_READ(host, RSP1) << 16);
+                       cmd->resp[2] =
+                               OMAP_MMC_READ(host, RSP2) |
+                               (OMAP_MMC_READ(host, RSP3) << 16);
+                       cmd->resp[1] =
+                               OMAP_MMC_READ(host, RSP4) |
+                               (OMAP_MMC_READ(host, RSP5) << 16);
+                       cmd->resp[0] =
+                               OMAP_MMC_READ(host, RSP6) |
+                               (OMAP_MMC_READ(host, RSP7) << 16);
+               } else {
+                       /* response types 1, 1b, 3, 4, 5, 6 */
+                       cmd->resp[0] =
+                               OMAP_MMC_READ(host, RSP6) |
+                               (OMAP_MMC_READ(host, RSP7) << 16);
+               }
+       }
+
+       if (host->data == NULL || cmd->error != MMC_ERR_NONE) {
+               host->mrq = NULL;
+               clk_disable(host->fclk);
+               mmc_request_done(host->mmc, cmd->mrq);
+       }
+}
+
+/* PIO only */
+static void
+mmc_omap_sg_to_buf(struct mmc_omap_host *host)
+{
+       struct scatterlist *sg;
+
+       sg = host->data->sg + host->sg_idx;
+       host->buffer_bytes_left = sg->length;
+       host->buffer = page_address(sg->page) + sg->offset;
+       if (host->buffer_bytes_left > host->total_bytes_left)
+               host->buffer_bytes_left = host->total_bytes_left;
+}
+
+/* PIO only */
+static void
+mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
+{
+       int n;
+
+       if (host->buffer_bytes_left == 0) {
+               host->sg_idx++;
+               BUG_ON(host->sg_idx == host->sg_len);
+               mmc_omap_sg_to_buf(host);
+       }
+       n = 64;
+       if (n > host->buffer_bytes_left)
+               n = host->buffer_bytes_left;
+       host->buffer_bytes_left -= n;
+       host->total_bytes_left -= n;
+       host->data->bytes_xfered += n;
+
+       if (write) {
+               __raw_writesw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
+       } else {
+               __raw_readsw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
+       }
+}
+
+static inline void mmc_omap_report_irq(u16 status)
+{
+       static const char *mmc_omap_status_bits[] = {
+               "EOC", "CD", "CB", "BRS", "EOFB", "DTO", "DCRC", "CTO",
+               "CCRC", "CRW", "AF", "AE", "OCRB", "CIRQ", "CERR"
+       };
+       int i, c = 0;
+
+       for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++)
+               if (status & (1 << i)) {
+                       if (c)
+                               printk(" ");
+                       printk("%s", mmc_omap_status_bits[i]);
+                       c++;
+               }
+}
+
+static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
+{
+       struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id;
+       u16 status;
+       int end_command;
+       int end_transfer;
+       int transfer_error;
+
+       if (host->cmd == NULL && host->data == NULL) {
+               status = OMAP_MMC_READ(host, STAT);
+               dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status);
+               if (status != 0) {
+                       OMAP_MMC_WRITE(host, STAT, status);
+                       OMAP_MMC_WRITE(host, IE, 0);
+               }
+               return IRQ_HANDLED;
+       }
+
+       end_command = 0;
+       end_transfer = 0;
+       transfer_error = 0;
+
+       while ((status = OMAP_MMC_READ(host, STAT)) != 0) {
+               OMAP_MMC_WRITE(host, STAT, status);
+#ifdef CONFIG_MMC_DEBUG
+               dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ",
+                       status, host->cmd != NULL ? host->cmd->opcode : -1);
+               mmc_omap_report_irq(status);
+               printk("\n");
+#endif
+               if (host->total_bytes_left) {
+                       if ((status & OMAP_MMC_STAT_A_FULL) ||
+                           (status & OMAP_MMC_STAT_END_OF_DATA))
+                               mmc_omap_xfer_data(host, 0);
+                       if (status & OMAP_MMC_STAT_A_EMPTY)
+                               mmc_omap_xfer_data(host, 1);
+               }
+
+               if (status & OMAP_MMC_STAT_END_OF_DATA) {
+                       end_transfer = 1;
+               }
+
+               if (status & OMAP_MMC_STAT_DATA_TOUT) {
+                       dev_dbg(mmc_dev(host->mmc), "data timeout\n");
+                       if (host->data) {
+                               host->data->error |= MMC_ERR_TIMEOUT;
+                               transfer_error = 1;
+                       }
+               }
+
+               if (status & OMAP_MMC_STAT_DATA_CRC) {
+                       if (host->data) {
+                               host->data->error |= MMC_ERR_BADCRC;
+                               dev_dbg(mmc_dev(host->mmc),
+                                        "data CRC error, bytes left %d\n",
+                                       host->total_bytes_left);
+                               transfer_error = 1;
+                       } else {
+                               dev_dbg(mmc_dev(host->mmc), "data CRC error\n");
+                       }
+               }
+
+               if (status & OMAP_MMC_STAT_CMD_TOUT) {
+                       /* Timeouts are routine with some commands */
+                       if (host->cmd) {
+                               if (host->cmd->opcode != MMC_ALL_SEND_CID &&
+                                               host->cmd->opcode !=
+                                               MMC_SEND_OP_COND &&
+                                               host->cmd->opcode !=
+                                               MMC_APP_CMD &&
+                                               !mmc_omap_cover_is_open(host))
+                                       dev_err(mmc_dev(host->mmc),
+                                               "command timeout, CMD %d\n",
+                                               host->cmd->opcode);
+                               host->cmd->error = MMC_ERR_TIMEOUT;
+                               end_command = 1;
+                       }
+               }
+
+               if (status & OMAP_MMC_STAT_CMD_CRC) {
+                       if (host->cmd) {
+                               dev_err(mmc_dev(host->mmc),
+                                       "command CRC error (CMD%d, arg 0x%08x)\n",
+                                       host->cmd->opcode, host->cmd->arg);
+                               host->cmd->error = MMC_ERR_BADCRC;
+                               end_command = 1;
+                       } else
+                               dev_err(mmc_dev(host->mmc),
+                                       "command CRC error without cmd?\n");
+               }
+
+               if (status & OMAP_MMC_STAT_CARD_ERR) {
+                       if (host->cmd && host->cmd->opcode == MMC_STOP_TRANSMISSION) {
+                               u32 response = OMAP_MMC_READ(host, RSP6)
+                                       | (OMAP_MMC_READ(host, RSP7) << 16);
+                               /* STOP sometimes sets must-ignore bits */
+                               if (!(response & (R1_CC_ERROR
+                                                               | R1_ILLEGAL_COMMAND
+                                                               | R1_COM_CRC_ERROR))) {
+                                       end_command = 1;
+                                       continue;
+                               }
+                       }
+
+                       dev_dbg(mmc_dev(host->mmc), "card status error (CMD%d)\n",
+                               host->cmd->opcode);
+                       if (host->cmd) {
+                               host->cmd->error = MMC_ERR_FAILED;
+                               end_command = 1;
+                       }
+                       if (host->data) {
+                               host->data->error = MMC_ERR_FAILED;
+                               transfer_error = 1;
+                       }
+               }
+
+               /*
+                * NOTE: On 1610 the END_OF_CMD may come too early when
+                * starting a write 
+                */
+               if ((status & OMAP_MMC_STAT_END_OF_CMD) &&
+                   (!(status & OMAP_MMC_STAT_A_EMPTY))) {
+                       end_command = 1;
+               }
+       }
+
+       if (end_command) {
+               mmc_omap_cmd_done(host, host->cmd);
+       }
+       if (transfer_error)
+               mmc_omap_xfer_done(host, host->data);
+       else if (end_transfer)
+               mmc_omap_end_of_data(host, host->data);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id)
+{
+       struct mmc_omap_host *host = (struct mmc_omap_host *) dev_id;
+
+       schedule_work(&host->switch_work);
+
+       return IRQ_HANDLED;
+}
+
+static void mmc_omap_switch_timer(unsigned long arg)
+{
+       struct mmc_omap_host *host = (struct mmc_omap_host *) arg;
+
+       schedule_work(&host->switch_work);
+}
+
+static void mmc_omap_switch_handler(struct work_struct *work)
+{
+       struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, switch_work);
+       struct mmc_card *card;
+       static int complained = 0;
+       int cards = 0, cover_open;
+
+       if (host->switch_pin == -1)
+               return;
+       cover_open = mmc_omap_cover_is_open(host);
+       if (cover_open != host->switch_last_state) {
+               kobject_uevent(&host->dev->kobj, KOBJ_CHANGE);
+               host->switch_last_state = cover_open;
+       }
+       mmc_detect_change(host->mmc, 0);
+       list_for_each_entry(card, &host->mmc->cards, node) {
+               if (mmc_card_present(card))
+                       cards++;
+       }
+       if (mmc_omap_cover_is_open(host)) {
+               if (!complained) {
+                       dev_info(mmc_dev(host->mmc), "cover is open");
+                       complained = 1;
+               }
+               if (mmc_omap_enable_poll)
+                       mod_timer(&host->switch_timer, jiffies +
+                               msecs_to_jiffies(OMAP_MMC_SWITCH_POLL_DELAY));
+       } else {
+               complained = 0;
+       }
+}
+
+/* Prepare to transfer the next segment of a scatterlist */
+static void
+mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
+{
+       int dma_ch = host->dma_ch;
+       unsigned long data_addr;
+       u16 buf, frame;
+       u32 count;
+       struct scatterlist *sg = &data->sg[host->sg_idx];
+       int src_port = 0;
+       int dst_port = 0;
+       int sync_dev = 0;
+
+       data_addr = host->phys_base + OMAP_MMC_REG_DATA;
+       frame = data->blksz;
+       count = sg_dma_len(sg);
+
+       if ((data->blocks == 1) && (count > data->blksz))
+               count = frame;
+
+       host->dma_len = count;
+
+       /* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx.
+        * Use 16 or 32 word frames when the blocksize is at least that large.
+        * Blocksize is usually 512 bytes; but not for some SD reads.
+        */
+       if (cpu_is_omap15xx() && frame > 32)
+               frame = 32;
+       else if (frame > 64)
+               frame = 64;
+       count /= frame;
+       frame >>= 1;
+
+       if (!(data->flags & MMC_DATA_WRITE)) {
+               buf = 0x800f | ((frame - 1) << 8);
+
+               if (cpu_class_is_omap1()) {
+                       src_port = OMAP_DMA_PORT_TIPB;
+                       dst_port = OMAP_DMA_PORT_EMIFF;
+               }
+               if (cpu_is_omap24xx())
+                       sync_dev = OMAP24XX_DMA_MMC1_RX;
+
+               omap_set_dma_src_params(dma_ch, src_port,
+                                       OMAP_DMA_AMODE_CONSTANT,
+                                       data_addr, 0, 0);
+               omap_set_dma_dest_params(dma_ch, dst_port,
+                                        OMAP_DMA_AMODE_POST_INC,
+                                        sg_dma_address(sg), 0, 0);
+               omap_set_dma_dest_data_pack(dma_ch, 1);
+               omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
+       } else {
+               buf = 0x0f80 | ((frame - 1) << 0);
+
+               if (cpu_class_is_omap1()) {
+                       src_port = OMAP_DMA_PORT_EMIFF;
+                       dst_port = OMAP_DMA_PORT_TIPB;
+               }
+               if (cpu_is_omap24xx())
+                       sync_dev = OMAP24XX_DMA_MMC1_TX;
+
+               omap_set_dma_dest_params(dma_ch, dst_port,
+                                        OMAP_DMA_AMODE_CONSTANT,
+                                        data_addr, 0, 0);
+               omap_set_dma_src_params(dma_ch, src_port,
+                                       OMAP_DMA_AMODE_POST_INC,
+                                       sg_dma_address(sg), 0, 0);
+               omap_set_dma_src_data_pack(dma_ch, 1);
+               omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
+       }
+
+       /* Max limit for DMA frame count is 0xffff */
+       BUG_ON(count > 0xffff);
+
+       OMAP_MMC_WRITE(host, BUF, buf);
+       omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16,
+                                    frame, count, OMAP_DMA_SYNC_FRAME,
+                                    sync_dev, 0);
+}
+
+/* A scatterlist segment completed */
+static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
+{
+       struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+       struct mmc_data *mmcdat = host->data;
+
+       if (unlikely(host->dma_ch < 0)) {
+               dev_err(mmc_dev(host->mmc),
+                       "DMA callback while DMA not enabled\n");
+               return;
+       }
+       /* FIXME: We really should do something to _handle_ the errors */
+       if (ch_status & OMAP1_DMA_TOUT_IRQ) {
+               dev_err(mmc_dev(host->mmc),"DMA timeout\n");
+               return;
+       }
+       if (ch_status & OMAP_DMA_DROP_IRQ) {
+               dev_err(mmc_dev(host->mmc), "DMA sync error\n");
+               return;
+       }
+       if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) {
+               return;
+       }
+       mmcdat->bytes_xfered += host->dma_len;
+       host->sg_idx++;
+       if (host->sg_idx < host->sg_len) {
+               mmc_omap_prepare_dma(host, host->data);
+               omap_start_dma(host->dma_ch);
+       } else
+               mmc_omap_dma_done(host, host->data);
+}
+
+static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data)
+{
+       const char *dev_name;
+       int sync_dev, dma_ch, is_read, r;
+
+       is_read = !(data->flags & MMC_DATA_WRITE);
+       del_timer_sync(&host->dma_timer);
+       if (host->dma_ch >= 0) {
+               if (is_read == host->dma_is_read)
+                       return 0;
+               omap_free_dma(host->dma_ch);
+               host->dma_ch = -1;
+       }
+
+       if (is_read) {
+               if (host->id == 1) {
+                       sync_dev = OMAP_DMA_MMC_RX;
+                       dev_name = "MMC1 read";
+               } else {
+                       sync_dev = OMAP_DMA_MMC2_RX;
+                       dev_name = "MMC2 read";
+               }
+       } else {
+               if (host->id == 1) {
+                       sync_dev = OMAP_DMA_MMC_TX;
+                       dev_name = "MMC1 write";
+               } else {
+                       sync_dev = OMAP_DMA_MMC2_TX;
+                       dev_name = "MMC2 write";
+               }
+       }
+       r = omap_request_dma(sync_dev, dev_name, mmc_omap_dma_cb,
+                            host, &dma_ch);
+       if (r != 0) {
+               dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r);
+               return r;
+       }
+       host->dma_ch = dma_ch;
+       host->dma_is_read = is_read;
+
+       return 0;
+}
+
+static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req)
+{
+       u16 reg;
+
+       reg = OMAP_MMC_READ(host, SDIO);
+       reg &= ~(1 << 5);
+       OMAP_MMC_WRITE(host, SDIO, reg);
+       /* Set maximum timeout */
+       OMAP_MMC_WRITE(host, CTO, 0xff);
+}
+
+static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req)
+{
+       int timeout;
+       u16 reg;
+
+       /* Convert ns to clock cycles by assuming 20MHz frequency
+        * 1 cycle at 20MHz = 500 ns
+        */
+       timeout = req->data->timeout_clks + req->data->timeout_ns / 500;
+
+       /* Check if we need to use timeout multiplier register */
+       reg = OMAP_MMC_READ(host, SDIO);
+       if (timeout > 0xffff) {
+               reg |= (1 << 5);
+               timeout /= 1024;
+       } else
+               reg &= ~(1 << 5);
+       OMAP_MMC_WRITE(host, SDIO, reg);
+       OMAP_MMC_WRITE(host, DTO, timeout);
+}
+
+static void
+mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
+{
+       struct mmc_data *data = req->data;
+       int i, use_dma, block_size;
+       unsigned sg_len;
+
+       host->data = data;
+       if (data == NULL) {
+               OMAP_MMC_WRITE(host, BLEN, 0);
+               OMAP_MMC_WRITE(host, NBLK, 0);
+               OMAP_MMC_WRITE(host, BUF, 0);
+               host->dma_in_use = 0;
+               set_cmd_timeout(host, req);
+               return;
+       }
+
+       block_size = data->blksz;
+
+       OMAP_MMC_WRITE(host, NBLK, data->blocks - 1);
+       OMAP_MMC_WRITE(host, BLEN, block_size - 1);
+       set_data_timeout(host, req);
+
+       /* cope with calling layer confusion; it issues "single
+        * block" writes using multi-block scatterlists.
+        */
+       sg_len = (data->blocks == 1) ? 1 : data->sg_len;
+
+       /* Only do DMA for entire blocks */
+       use_dma = host->use_dma;
+       if (use_dma) {
+               for (i = 0; i < sg_len; i++) {
+                       if ((data->sg[i].length % block_size) != 0) {
+                               use_dma = 0;
+                               break;
+                       }
+               }
+       }
+
+       host->sg_idx = 0;
+       if (use_dma) {
+               if (mmc_omap_get_dma_channel(host, data) == 0) {
+                       enum dma_data_direction dma_data_dir;
+
+                       if (data->flags & MMC_DATA_WRITE)
+                               dma_data_dir = DMA_TO_DEVICE;
+                       else
+                               dma_data_dir = DMA_FROM_DEVICE;
+
+                       host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+                                               sg_len, dma_data_dir);
+                       host->total_bytes_left = 0;
+                       mmc_omap_prepare_dma(host, req->data);
+                       host->brs_received = 0;
+                       host->dma_done = 0;
+                       host->dma_in_use = 1;
+               } else
+                       use_dma = 0;
+       }
+
+       /* Revert to PIO? */
+       if (!use_dma) {
+               OMAP_MMC_WRITE(host, BUF, 0x1f1f);
+               host->total_bytes_left = data->blocks * block_size;
+               host->sg_len = sg_len;
+               mmc_omap_sg_to_buf(host);
+               host->dma_in_use = 0;
+       }
+}
+
+static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+       struct mmc_omap_host *host = mmc_priv(mmc);
+
+       WARN_ON(host->mrq != NULL);
+
+       host->mrq = req;
+
+       /* only touch fifo AFTER the controller readies it */
+       mmc_omap_prepare_data(host, req);
+       mmc_omap_start_command(host, req->cmd);
+       if (host->dma_in_use)
+               omap_start_dma(host->dma_ch);
+}
+
+static void innovator_fpga_socket_power(int on)
+{
+#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX)
+       if (on) {
+               fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3),
+                    OMAP1510_FPGA_POWER);
+       } else {
+               fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~(1 << 3),
+                    OMAP1510_FPGA_POWER);
+       }
+#endif
+}
+
+/*
+ * Turn the socket power on/off. Innovator uses FPGA, most boards
+ * probably use GPIO.
+ */
+static void mmc_omap_power(struct mmc_omap_host *host, int on)
+{
+       if (on) {
+               if (machine_is_omap_innovator())
+                       innovator_fpga_socket_power(1);
+               else if (machine_is_omap_h2())
+                       tps65010_set_gpio_out_value(GPIO3, HIGH);
+               else if (machine_is_omap_h3())
+                       /* GPIO 4 of TPS65010 sends SD_EN signal */
+                       tps65010_set_gpio_out_value(GPIO4, HIGH);
+               else if (cpu_is_omap24xx()) {
+                       u16 reg = OMAP_MMC_READ(host, CON);
+                       OMAP_MMC_WRITE(host, CON, reg | (1 << 11));
+               } else
+                       if (host->power_pin >= 0)
+                               omap_set_gpio_dataout(host->power_pin, 1);
+       } else {
+               if (machine_is_omap_innovator())
+                       innovator_fpga_socket_power(0);
+               else if (machine_is_omap_h2())
+                       tps65010_set_gpio_out_value(GPIO3, LOW);
+               else if (machine_is_omap_h3())
+                       tps65010_set_gpio_out_value(GPIO4, LOW);
+               else if (cpu_is_omap24xx()) {
+                       u16 reg = OMAP_MMC_READ(host, CON);
+                       OMAP_MMC_WRITE(host, CON, reg & ~(1 << 11));
+               } else
+                       if (host->power_pin >= 0)
+                               omap_set_gpio_dataout(host->power_pin, 0);
+       }
+}
+
+static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct mmc_omap_host *host = mmc_priv(mmc);
+       int dsor;
+       int realclock, i;
+
+       realclock = ios->clock;
+
+       if (ios->clock == 0)
+               dsor = 0;
+       else {
+               int func_clk_rate = clk_get_rate(host->fclk);
+
+               dsor = func_clk_rate / realclock;
+               if (dsor < 1)
+                       dsor = 1;
+
+               if (func_clk_rate / dsor > realclock)
+                       dsor++;
+
+               if (dsor > 250)
+                       dsor = 250;
+               dsor++;
+
+               if (ios->bus_width == MMC_BUS_WIDTH_4)
+                       dsor |= 1 << 15;
+       }
+
+       switch (ios->power_mode) {
+       case MMC_POWER_OFF:
+               mmc_omap_power(host, 0);
+               break;
+       case MMC_POWER_UP:
+       case MMC_POWER_ON:
+               mmc_omap_power(host, 1);
+               dsor |= 1 << 11;
+               break;
+       }
+
+       host->bus_mode = ios->bus_mode;
+       host->hw_bus_mode = host->bus_mode;
+
+       clk_enable(host->fclk);
+
+       /* On insanely high arm_per frequencies something sometimes
+        * goes somehow out of sync, and the POW bit is not being set,
+        * which results in the while loop below getting stuck.
+        * Writing to the CON register twice seems to do the trick. */
+       for (i = 0; i < 2; i++)
+               OMAP_MMC_WRITE(host, CON, dsor);
+       if (ios->power_mode == MMC_POWER_UP) {
+               /* Send clock cycles, poll completion */
+               OMAP_MMC_WRITE(host, IE, 0);
+               OMAP_MMC_WRITE(host, STAT, 0xffff);
+               OMAP_MMC_WRITE(host, CMD, 1 << 7);
+               while ((OMAP_MMC_READ(host, STAT) & 1) == 0);
+               OMAP_MMC_WRITE(host, STAT, 1);
+       }
+       clk_disable(host->fclk);
+}
+
+static int mmc_omap_get_ro(struct mmc_host *mmc)
+{
+       struct mmc_omap_host *host = mmc_priv(mmc);
+
+       return host->wp_pin && omap_get_gpio_datain(host->wp_pin);
+}
+
+static const struct mmc_host_ops mmc_omap_ops = {
+       .request        = mmc_omap_request,
+       .set_ios        = mmc_omap_set_ios,
+       .get_ro         = mmc_omap_get_ro,
+};
+
+static int __init mmc_omap_probe(struct platform_device *pdev)
+{
+       struct omap_mmc_conf *minfo = pdev->dev.platform_data;
+       struct mmc_host *mmc;
+       struct mmc_omap_host *host = NULL;
+       struct resource *res;
+       int ret = 0;
+       int irq;
+
+       if (minfo == NULL) {
+               dev_err(&pdev->dev, "platform data missing\n");
+               return -ENXIO;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(pdev, 0);
+       if (res == NULL || irq < 0)
+               return -ENXIO;
+
+       res = request_mem_region(res->start, res->end - res->start + 1,
+                                pdev->name);
+       if (res == NULL)
+               return -EBUSY;
+
+       mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev);
+       if (mmc == NULL) {
+               ret = -ENOMEM;
+               goto err_free_mem_region;
+       }
+
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+
+       spin_lock_init(&host->dma_lock);
+       init_timer(&host->dma_timer);
+       host->dma_timer.function = mmc_omap_dma_timer;
+       host->dma_timer.data = (unsigned long) host;
+
+       host->id = pdev->id;
+       host->mem_res = res;
+       host->irq = irq;
+
+       if (cpu_is_omap24xx()) {
+               host->iclk = clk_get(&pdev->dev, "mmc_ick");
+               if (IS_ERR(host->iclk))
+                       goto err_free_mmc_host;
+               clk_enable(host->iclk);
+       }
+
+       if (!cpu_is_omap24xx())
+               host->fclk = clk_get(&pdev->dev, "mmc_ck");
+       else
+               host->fclk = clk_get(&pdev->dev, "mmc_fck");
+
+       if (IS_ERR(host->fclk)) {
+               ret = PTR_ERR(host->fclk);
+               goto err_free_iclk;
+       }
+
+       /* REVISIT:
+        * Also, use minfo->cover to decide how to manage
+        * the card detect sensing.
+        */
+       host->power_pin = minfo->power_pin;
+       host->switch_pin = minfo->switch_pin;
+       host->wp_pin = minfo->wp_pin;
+       host->use_dma = 1;
+       host->dma_ch = -1;
+
+       host->irq = irq;
+       host->phys_base = host->mem_res->start;
+       host->virt_base = (void __iomem *) IO_ADDRESS(host->phys_base);
+
+       mmc->ops = &mmc_omap_ops;
+       mmc->f_min = 400000;
+       mmc->f_max = 24000000;
+       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+       mmc->caps = MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+
+       if (minfo->wire4)
+                mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+       /* Use scatterlist DMA to reduce per-transfer costs.
+        * NOTE max_seg_size assumption that small blocks aren't
+        * normally used (except e.g. for reading SD registers).
+        */
+       mmc->max_phys_segs = 32;
+       mmc->max_hw_segs = 32;
+       mmc->max_blk_size = 2048;       /* BLEN is 11 bits (+1) */
+       mmc->max_blk_count = 2048;      /* NBLK is 11 bits (+1) */
+       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+       mmc->max_seg_size = mmc->max_req_size;
+
+       if (host->power_pin >= 0) {
+               if ((ret = omap_request_gpio(host->power_pin)) != 0) {
+                       dev_err(mmc_dev(host->mmc),
+                               "Unable to get GPIO pin for MMC power\n");
+                       goto err_free_fclk;
+               }
+               omap_set_gpio_direction(host->power_pin, 0);
+       }
+
+       ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
+       if (ret)
+               goto err_free_power_gpio;
+
+       host->dev = &pdev->dev;
+       platform_set_drvdata(pdev, host);
+
+       if (host->switch_pin >= 0) {
+               INIT_WORK(&host->switch_work, mmc_omap_switch_handler);
+               init_timer(&host->switch_timer);
+               host->switch_timer.function = mmc_omap_switch_timer;
+               host->switch_timer.data = (unsigned long) host;
+               if (omap_request_gpio(host->switch_pin) != 0) {
+                       dev_warn(mmc_dev(host->mmc), "Unable to get GPIO pin for MMC cover switch\n");
+                       host->switch_pin = -1;
+                       goto no_switch;
+               }
+
+               omap_set_gpio_direction(host->switch_pin, 1);
+               ret = request_irq(OMAP_GPIO_IRQ(host->switch_pin),
+                                 mmc_omap_switch_irq, IRQF_TRIGGER_RISING, DRIVER_NAME, host);
+               if (ret) {
+                       dev_warn(mmc_dev(host->mmc), "Unable to get IRQ for MMC cover switch\n");
+                       omap_free_gpio(host->switch_pin);
+                       host->switch_pin = -1;
+                       goto no_switch;
+               }
+               ret = device_create_file(&pdev->dev, &dev_attr_cover_switch);
+               if (ret == 0) {
+                       ret = device_create_file(&pdev->dev, &dev_attr_enable_poll);
+                       if (ret != 0)
+                               device_remove_file(&pdev->dev, &dev_attr_cover_switch);
+               }
+               if (ret) {
+                       dev_warn(mmc_dev(host->mmc), "Unable to create sysfs attributes\n");
+                       free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
+                       omap_free_gpio(host->switch_pin);
+                       host->switch_pin = -1;
+                       goto no_switch;
+               }
+               if (mmc_omap_enable_poll && mmc_omap_cover_is_open(host))
+                       schedule_work(&host->switch_work);
+       }
+
+       mmc_add_host(mmc);
+
+       return 0;
+
+no_switch:
+       /* FIXME: Free other resources too. */
+       if (host) {
+               if (host->iclk && !IS_ERR(host->iclk))
+                       clk_put(host->iclk);
+               if (host->fclk && !IS_ERR(host->fclk))
+                       clk_put(host->fclk);
+               mmc_free_host(host->mmc);
+       }
+err_free_power_gpio:
+       if (host->power_pin >= 0)
+               omap_free_gpio(host->power_pin);
+err_free_fclk:
+       clk_put(host->fclk);
+err_free_iclk:
+       if (host->iclk != NULL) {
+               clk_disable(host->iclk);
+               clk_put(host->iclk);
+       }
+err_free_mmc_host:
+       mmc_free_host(host->mmc);
+err_free_mem_region:
+       release_mem_region(res->start, res->end - res->start + 1);
+       return ret;
+}
+
+static int mmc_omap_remove(struct platform_device *pdev)
+{
+       struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       BUG_ON(host == NULL);
+
+       mmc_remove_host(host->mmc);
+       free_irq(host->irq, host);
+
+       if (host->power_pin >= 0)
+               omap_free_gpio(host->power_pin);
+       if (host->switch_pin >= 0) {
+               device_remove_file(&pdev->dev, &dev_attr_enable_poll);
+               device_remove_file(&pdev->dev, &dev_attr_cover_switch);
+               free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
+               omap_free_gpio(host->switch_pin);
+               host->switch_pin = -1;
+               del_timer_sync(&host->switch_timer);
+               flush_scheduled_work();
+       }
+       if (host->iclk && !IS_ERR(host->iclk))
+               clk_put(host->iclk);
+       if (host->fclk && !IS_ERR(host->fclk))
+               clk_put(host->fclk);
+
+       release_mem_region(pdev->resource[0].start,
+                          pdev->resource[0].end - pdev->resource[0].start + 1);
+
+       mmc_free_host(host->mmc);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       int ret = 0;
+       struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+       if (host && host->suspended)
+               return 0;
+
+       if (host) {
+               ret = mmc_suspend_host(host->mmc, mesg);
+               if (ret == 0)
+                       host->suspended = 1;
+       }
+       return ret;
+}
+
+static int mmc_omap_resume(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+       if (host && !host->suspended)
+               return 0;
+
+       if (host) {
+               ret = mmc_resume_host(host->mmc);
+               if (ret == 0)
+                       host->suspended = 0;
+       }
+
+       return ret;
+}
+#else
+#define mmc_omap_suspend       NULL
+#define mmc_omap_resume                NULL
+#endif
+
+static struct platform_driver mmc_omap_driver = {
+       .probe          = mmc_omap_probe,
+       .remove         = mmc_omap_remove,
+       .suspend        = mmc_omap_suspend,
+       .resume         = mmc_omap_resume,
+       .driver         = {
+               .name   = DRIVER_NAME,
+       },
+};
+
+static int __init mmc_omap_init(void)
+{
+       return platform_driver_register(&mmc_omap_driver);
+}
+
+static void __exit mmc_omap_exit(void)
+{
+       platform_driver_unregister(&mmc_omap_driver);
+}
+
+module_init(mmc_omap_init);
+module_exit(mmc_omap_exit);
+
+MODULE_DESCRIPTION("OMAP Multimedia Card driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS(DRIVER_NAME);
+MODULE_AUTHOR("Juha Yrjölä");
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
new file mode 100644 (file)
index 0000000..a98ff98
--- /dev/null
@@ -0,0 +1,616 @@
+/*
+ *  linux/drivers/mmc/pxa.c - PXA MMCI driver
+ *
+ *  Copyright (C) 2003 Russell King, 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.
+ *
+ *  This hardware is really sick:
+ *   - No way to clear interrupts.
+ *   - Have to turn off the clock whenever we touch the device.
+ *   - Doesn't tell you how many data blocks were transferred.
+ *  Yuck!
+ *
+ *     1 and 3 byte data transfers not supported
+ *     max block length up to 1023
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <asm/sizes.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mmc.h>
+
+#include "pxamci.h"
+
+#define DRIVER_NAME    "pxa2xx-mci"
+
+#define NR_SG  1
+
+struct pxamci_host {
+       struct mmc_host         *mmc;
+       spinlock_t              lock;
+       struct resource         *res;
+       void __iomem            *base;
+       int                     irq;
+       int                     dma;
+       unsigned int            clkrt;
+       unsigned int            cmdat;
+       unsigned int            imask;
+       unsigned int            power_mode;
+       struct pxamci_platform_data *pdata;
+
+       struct mmc_request      *mrq;
+       struct mmc_command      *cmd;
+       struct mmc_data         *data;
+
+       dma_addr_t              sg_dma;
+       struct pxa_dma_desc     *sg_cpu;
+       unsigned int            dma_len;
+
+       unsigned int            dma_dir;
+};
+
+static void pxamci_stop_clock(struct pxamci_host *host)
+{
+       if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
+               unsigned long timeout = 10000;
+               unsigned int v;
+
+               writel(STOP_CLOCK, host->base + MMC_STRPCL);
+
+               do {
+                       v = readl(host->base + MMC_STAT);
+                       if (!(v & STAT_CLK_EN))
+                               break;
+                       udelay(1);
+               } while (timeout--);
+
+               if (v & STAT_CLK_EN)
+                       dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
+       }
+}
+
+static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       host->imask &= ~mask;
+       writel(host->imask, host->base + MMC_I_MASK);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       host->imask |= mask;
+       writel(host->imask, host->base + MMC_I_MASK);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
+{
+       unsigned int nob = data->blocks;
+       unsigned long long clks;
+       unsigned int timeout;
+       u32 dcmd;
+       int i;
+
+       host->data = data;
+
+       if (data->flags & MMC_DATA_STREAM)
+               nob = 0xffff;
+
+       writel(nob, host->base + MMC_NOB);
+       writel(data->blksz, host->base + MMC_BLKLEN);
+
+       clks = (unsigned long long)data->timeout_ns * CLOCKRATE;
+       do_div(clks, 1000000000UL);
+       timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
+       writel((timeout + 255) / 256, host->base + MMC_RDTO);
+
+       if (data->flags & MMC_DATA_READ) {
+               host->dma_dir = DMA_FROM_DEVICE;
+               dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
+               DRCMRTXMMC = 0;
+               DRCMRRXMMC = host->dma | DRCMR_MAPVLD;
+       } else {
+               host->dma_dir = DMA_TO_DEVICE;
+               dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
+               DRCMRRXMMC = 0;
+               DRCMRTXMMC = host->dma | DRCMR_MAPVLD;
+       }
+
+       dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
+
+       host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+                                  host->dma_dir);
+
+       for (i = 0; i < host->dma_len; i++) {
+               if (data->flags & MMC_DATA_READ) {
+                       host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
+                       host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
+               } else {
+                       host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
+                       host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
+               }
+               host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);
+               host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
+                                       sizeof(struct pxa_dma_desc);
+       }
+       host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
+       wmb();
+
+       DDADR(host->dma) = host->sg_dma;
+       DCSR(host->dma) = DCSR_RUN;
+}
+
+static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
+{
+       WARN_ON(host->cmd != NULL);
+       host->cmd = cmd;
+
+       if (cmd->flags & MMC_RSP_BUSY)
+               cmdat |= CMDAT_BUSY;
+
+#define RSP_TYPE(x)    ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
+       switch (RSP_TYPE(mmc_resp_type(cmd))) {
+       case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
+               cmdat |= CMDAT_RESP_SHORT;
+               break;
+       case RSP_TYPE(MMC_RSP_R3):
+               cmdat |= CMDAT_RESP_R3;
+               break;
+       case RSP_TYPE(MMC_RSP_R2):
+               cmdat |= CMDAT_RESP_R2;
+               break;
+       default:
+               break;
+       }
+
+       writel(cmd->opcode, host->base + MMC_CMD);
+       writel(cmd->arg >> 16, host->base + MMC_ARGH);
+       writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
+       writel(cmdat, host->base + MMC_CMDAT);
+       writel(host->clkrt, host->base + MMC_CLKRT);
+
+       writel(START_CLOCK, host->base + MMC_STRPCL);
+
+       pxamci_enable_irq(host, END_CMD_RES);
+}
+
+static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
+{
+       host->mrq = NULL;
+       host->cmd = NULL;
+       host->data = NULL;
+       mmc_request_done(host->mmc, mrq);
+}
+
+static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
+{
+       struct mmc_command *cmd = host->cmd;
+       int i;
+       u32 v;
+
+       if (!cmd)
+               return 0;
+
+       host->cmd = NULL;
+
+       /*
+        * Did I mention this is Sick.  We always need to
+        * discard the upper 8 bits of the first 16-bit word.
+        */
+       v = readl(host->base + MMC_RES) & 0xffff;
+       for (i = 0; i < 4; i++) {
+               u32 w1 = readl(host->base + MMC_RES) & 0xffff;
+               u32 w2 = readl(host->base + MMC_RES) & 0xffff;
+               cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
+               v = w2;
+       }
+
+       if (stat & STAT_TIME_OUT_RESPONSE) {
+               cmd->error = MMC_ERR_TIMEOUT;
+       } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
+#ifdef CONFIG_PXA27x
+               /*
+                * workaround for erratum #42:
+                * Intel PXA27x Family Processor Specification Update Rev 001
+                */
+               if (cmd->opcode == MMC_ALL_SEND_CID ||
+                   cmd->opcode == MMC_SEND_CSD ||
+                   cmd->opcode == MMC_SEND_CID) {
+                       /* a bogus CRC error can appear if the msb of
+                          the 15 byte response is a one */
+                       if ((cmd->resp[0] & 0x80000000) == 0)
+                               cmd->error = MMC_ERR_BADCRC;
+               } else {
+                       pr_debug("ignoring CRC from command %d - *risky*\n",cmd->opcode);
+               }
+#else
+               cmd->error = MMC_ERR_BADCRC;
+#endif
+       }
+
+       pxamci_disable_irq(host, END_CMD_RES);
+       if (host->data && cmd->error == MMC_ERR_NONE) {
+               pxamci_enable_irq(host, DATA_TRAN_DONE);
+       } else {
+               pxamci_finish_request(host, host->mrq);
+       }
+
+       return 1;
+}
+
+static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
+{
+       struct mmc_data *data = host->data;
+
+       if (!data)
+               return 0;
+
+       DCSR(host->dma) = 0;
+       dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
+                    host->dma_dir);
+
+       if (stat & STAT_READ_TIME_OUT)
+               data->error = MMC_ERR_TIMEOUT;
+       else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
+               data->error = MMC_ERR_BADCRC;
+
+       /*
+        * There appears to be a hardware design bug here.  There seems to
+        * be no way to find out how much data was transferred to the card.
+        * This means that if there was an error on any block, we mark all
+        * data blocks as being in error.
+        */
+       if (data->error == MMC_ERR_NONE)
+               data->bytes_xfered = data->blocks * data->blksz;
+       else
+               data->bytes_xfered = 0;
+
+       pxamci_disable_irq(host, DATA_TRAN_DONE);
+
+       host->data = NULL;
+       if (host->mrq->stop) {
+               pxamci_stop_clock(host);
+               pxamci_start_cmd(host, host->mrq->stop, 0);
+       } else {
+               pxamci_finish_request(host, host->mrq);
+       }
+
+       return 1;
+}
+
+static irqreturn_t pxamci_irq(int irq, void *devid)
+{
+       struct pxamci_host *host = devid;
+       unsigned int ireg;
+       int handled = 0;
+
+       ireg = readl(host->base + MMC_I_REG);
+
+       if (ireg) {
+               unsigned stat = readl(host->base + MMC_STAT);
+
+               pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
+
+               if (ireg & END_CMD_RES)
+                       handled |= pxamci_cmd_done(host, stat);
+               if (ireg & DATA_TRAN_DONE)
+                       handled |= pxamci_data_done(host, stat);
+       }
+
+       return IRQ_RETVAL(handled);
+}
+
+static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct pxamci_host *host = mmc_priv(mmc);
+       unsigned int cmdat;
+
+       WARN_ON(host->mrq != NULL);
+
+       host->mrq = mrq;
+
+       pxamci_stop_clock(host);
+
+       cmdat = host->cmdat;
+       host->cmdat &= ~CMDAT_INIT;
+
+       if (mrq->data) {
+               pxamci_setup_data(host, mrq->data);
+
+               cmdat &= ~CMDAT_BUSY;
+               cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
+               if (mrq->data->flags & MMC_DATA_WRITE)
+                       cmdat |= CMDAT_WRITE;
+
+               if (mrq->data->flags & MMC_DATA_STREAM)
+                       cmdat |= CMDAT_STREAM;
+       }
+
+       pxamci_start_cmd(host, mrq->cmd, cmdat);
+}
+
+static int pxamci_get_ro(struct mmc_host *mmc)
+{
+       struct pxamci_host *host = mmc_priv(mmc);
+
+       if (host->pdata && host->pdata->get_ro)
+               return host->pdata->get_ro(mmc_dev(mmc));
+       /* Host doesn't support read only detection so assume writeable */
+       return 0;
+}
+
+static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct pxamci_host *host = mmc_priv(mmc);
+
+       if (ios->clock) {
+               unsigned int clk = CLOCKRATE / ios->clock;
+               if (CLOCKRATE / clk > ios->clock)
+                       clk <<= 1;
+               host->clkrt = fls(clk) - 1;
+               pxa_set_cken(CKEN12_MMC, 1);
+
+               /*
+                * we write clkrt on the next command
+                */
+       } else {
+               pxamci_stop_clock(host);
+               pxa_set_cken(CKEN12_MMC, 0);
+       }
+
+       if (host->power_mode != ios->power_mode) {
+               host->power_mode = ios->power_mode;
+
+               if (host->pdata && host->pdata->setpower)
+                       host->pdata->setpower(mmc_dev(mmc), ios->vdd);
+
+               if (ios->power_mode == MMC_POWER_ON)
+                       host->cmdat |= CMDAT_INIT;
+       }
+
+       pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
+                host->clkrt, host->cmdat);
+}
+
+static const struct mmc_host_ops pxamci_ops = {
+       .request        = pxamci_request,
+       .get_ro         = pxamci_get_ro,
+       .set_ios        = pxamci_set_ios,
+};
+
+static void pxamci_dma_irq(int dma, void *devid)
+{
+       printk(KERN_ERR "DMA%d: IRQ???\n", dma);
+       DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
+}
+
+static irqreturn_t pxamci_detect_irq(int irq, void *devid)
+{
+       struct pxamci_host *host = mmc_priv(devid);
+
+       mmc_detect_change(devid, host->pdata->detect_delay);
+       return IRQ_HANDLED;
+}
+
+static int pxamci_probe(struct platform_device *pdev)
+{
+       struct mmc_host *mmc;
+       struct pxamci_host *host = NULL;
+       struct resource *r;
+       int ret, 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, SZ_4K, DRIVER_NAME);
+       if (!r)
+               return -EBUSY;
+
+       mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
+       if (!mmc) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       mmc->ops = &pxamci_ops;
+       mmc->f_min = CLOCKRATE_MIN;
+       mmc->f_max = CLOCKRATE_MAX;
+
+       /*
+        * We can do SG-DMA, but we don't because we never know how much
+        * data we successfully wrote to the card.
+        */
+       mmc->max_phys_segs = NR_SG;
+
+       /*
+        * Our hardware DMA can handle a maximum of one page per SG entry.
+        */
+       mmc->max_seg_size = PAGE_SIZE;
+
+       /*
+        * Block length register is 10 bits.
+        */
+       mmc->max_blk_size = 1023;
+
+       /*
+        * Block count register is 16 bits.
+        */
+       mmc->max_blk_count = 65535;
+
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+       host->dma = -1;
+       host->pdata = pdev->dev.platform_data;
+       mmc->ocr_avail = host->pdata ?
+                        host->pdata->ocr_mask :
+                        MMC_VDD_32_33|MMC_VDD_33_34;
+
+       host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
+       if (!host->sg_cpu) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       spin_lock_init(&host->lock);
+       host->res = r;
+       host->irq = irq;
+       host->imask = MMC_I_MASK_ALL;
+
+       host->base = ioremap(r->start, SZ_4K);
+       if (!host->base) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /*
+        * Ensure that the host controller is shut down, and setup
+        * with our defaults.
+        */
+       pxamci_stop_clock(host);
+       writel(0, host->base + MMC_SPI);
+       writel(64, host->base + MMC_RESTO);
+       writel(host->imask, host->base + MMC_I_MASK);
+
+       host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
+                                   pxamci_dma_irq, host);
+       if (host->dma < 0) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
+       if (ret)
+               goto out;
+
+       platform_set_drvdata(pdev, mmc);
+
+       if (host->pdata && host->pdata->init)
+               host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
+
+       mmc_add_host(mmc);
+
+       return 0;
+
+ out:
+       if (host) {
+               if (host->dma >= 0)
+                       pxa_free_dma(host->dma);
+               if (host->base)
+                       iounmap(host->base);
+               if (host->sg_cpu)
+                       dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+       }
+       if (mmc)
+               mmc_free_host(mmc);
+       release_resource(r);
+       return ret;
+}
+
+static int pxamci_remove(struct platform_device *pdev)
+{
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (mmc) {
+               struct pxamci_host *host = mmc_priv(mmc);
+
+               if (host->pdata && host->pdata->exit)
+                       host->pdata->exit(&pdev->dev, mmc);
+
+               mmc_remove_host(mmc);
+
+               pxamci_stop_clock(host);
+               writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
+                      END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
+                      host->base + MMC_I_MASK);
+
+               DRCMRRXMMC = 0;
+               DRCMRTXMMC = 0;
+
+               free_irq(host->irq, host);
+               pxa_free_dma(host->dma);
+               iounmap(host->base);
+               dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+
+               release_resource(host->res);
+
+               mmc_free_host(mmc);
+       }
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int pxamci_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct mmc_host *mmc = platform_get_drvdata(dev);
+       int ret = 0;
+
+       if (mmc)
+               ret = mmc_suspend_host(mmc, state);
+
+       return ret;
+}
+
+static int pxamci_resume(struct platform_device *dev)
+{
+       struct mmc_host *mmc = platform_get_drvdata(dev);
+       int ret = 0;
+
+       if (mmc)
+               ret = mmc_resume_host(mmc);
+
+       return ret;
+}
+#else
+#define pxamci_suspend NULL
+#define pxamci_resume  NULL
+#endif
+
+static struct platform_driver pxamci_driver = {
+       .probe          = pxamci_probe,
+       .remove         = pxamci_remove,
+       .suspend        = pxamci_suspend,
+       .resume         = pxamci_resume,
+       .driver         = {
+               .name   = DRIVER_NAME,
+       },
+};
+
+static int __init pxamci_init(void)
+{
+       return platform_driver_register(&pxamci_driver);
+}
+
+static void __exit pxamci_exit(void)
+{
+       platform_driver_unregister(&pxamci_driver);
+}
+
+module_init(pxamci_init);
+module_exit(pxamci_exit);
+
+MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h
new file mode 100644 (file)
index 0000000..1b16322
--- /dev/null
@@ -0,0 +1,124 @@
+#undef MMC_STRPCL
+#undef MMC_STAT
+#undef MMC_CLKRT
+#undef MMC_SPI
+#undef MMC_CMDAT
+#undef MMC_RESTO
+#undef MMC_RDTO
+#undef MMC_BLKLEN
+#undef MMC_NOB
+#undef MMC_PRTBUF
+#undef MMC_I_MASK
+#undef END_CMD_RES
+#undef PRG_DONE
+#undef DATA_TRAN_DONE
+#undef MMC_I_REG
+#undef MMC_CMD
+#undef MMC_ARGH
+#undef MMC_ARGL
+#undef MMC_RES
+#undef MMC_RXFIFO
+#undef MMC_TXFIFO
+
+#define MMC_STRPCL     0x0000
+#define STOP_CLOCK             (1 << 0)
+#define START_CLOCK            (2 << 0)
+
+#define MMC_STAT       0x0004
+#define STAT_END_CMD_RES               (1 << 13)
+#define STAT_PRG_DONE                  (1 << 12)
+#define STAT_DATA_TRAN_DONE            (1 << 11)
+#define STAT_CLK_EN                    (1 << 8)
+#define STAT_RECV_FIFO_FULL            (1 << 7)
+#define STAT_XMIT_FIFO_EMPTY           (1 << 6)
+#define STAT_RES_CRC_ERR               (1 << 5)
+#define STAT_SPI_READ_ERROR_TOKEN      (1 << 4)
+#define STAT_CRC_READ_ERROR            (1 << 3)
+#define STAT_CRC_WRITE_ERROR           (1 << 2)
+#define STAT_TIME_OUT_RESPONSE         (1 << 1)
+#define STAT_READ_TIME_OUT             (1 << 0)
+
+#define MMC_CLKRT      0x0008          /* 3 bit */
+
+#define MMC_SPI                0x000c
+#define SPI_CS_ADDRESS         (1 << 3)
+#define SPI_CS_EN              (1 << 2)
+#define CRC_ON                 (1 << 1)
+#define SPI_EN                 (1 << 0)
+
+#define MMC_CMDAT      0x0010
+#define CMDAT_DMAEN            (1 << 7)
+#define CMDAT_INIT             (1 << 6)
+#define CMDAT_BUSY             (1 << 5)
+#define CMDAT_STREAM           (1 << 4)        /* 1 = stream */
+#define CMDAT_WRITE            (1 << 3)        /* 1 = write */
+#define CMDAT_DATAEN           (1 << 2)
+#define CMDAT_RESP_NONE                (0 << 0)
+#define CMDAT_RESP_SHORT       (1 << 0)
+#define CMDAT_RESP_R2          (2 << 0)
+#define CMDAT_RESP_R3          (3 << 0)
+
+#define MMC_RESTO      0x0014  /* 7 bit */
+
+#define MMC_RDTO       0x0018  /* 16 bit */
+
+#define MMC_BLKLEN     0x001c  /* 10 bit */
+
+#define MMC_NOB                0x0020  /* 16 bit */
+
+#define MMC_PRTBUF     0x0024
+#define BUF_PART_FULL          (1 << 0)
+
+#define MMC_I_MASK     0x0028
+
+/*PXA27x MMC interrupts*/
+#define SDIO_SUSPEND_ACK       (1 << 12)
+#define SDIO_INT               (1 << 11)
+#define RD_STALLED             (1 << 10)
+#define RES_ERR                (1 << 9)
+#define DAT_ERR                (1 << 8)
+#define TINT                   (1 << 7)
+
+/*PXA2xx MMC interrupts*/
+#define TXFIFO_WR_REQ          (1 << 6)
+#define RXFIFO_RD_REQ          (1 << 5)
+#define CLK_IS_OFF             (1 << 4)
+#define STOP_CMD               (1 << 3)
+#define END_CMD_RES            (1 << 2)
+#define PRG_DONE               (1 << 1)
+#define DATA_TRAN_DONE         (1 << 0)
+
+#ifdef CONFIG_PXA27x
+#define MMC_I_MASK_ALL          0x00001fff
+#else
+#define MMC_I_MASK_ALL          0x0000007f
+#endif
+
+#define MMC_I_REG      0x002c
+/* same as MMC_I_MASK */
+
+#define MMC_CMD                0x0030
+
+#define MMC_ARGH       0x0034  /* 16 bit */
+
+#define MMC_ARGL       0x0038  /* 16 bit */
+
+#define MMC_RES                0x003c  /* 16 bit */
+
+#define MMC_RXFIFO     0x0040  /* 8 bit */
+
+#define MMC_TXFIFO     0x0044  /* 8 bit */
+
+/*
+ * The base MMC clock rate
+ */
+#ifdef CONFIG_PXA27x
+#define CLOCKRATE_MIN  304688
+#define CLOCKRATE_MAX  19500000
+#else
+#define CLOCKRATE_MIN  312500
+#define CLOCKRATE_MAX  20000000
+#endif
+
+#define CLOCKRATE      CLOCKRATE_MAX
+
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
new file mode 100644 (file)
index 0000000..579142a
--- /dev/null
@@ -0,0 +1,1539 @@
+/*
+ *  linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver
+ *
+ *  Copyright (C) 2005-2007 Pierre Ossman, 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/highmem.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/mmc/host.h>
+
+#include <asm/scatterlist.h>
+
+#include "sdhci.h"
+
+#define DRIVER_NAME "sdhci"
+
+#define DBG(f, x...) \
+       pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
+
+static unsigned int debug_nodma = 0;
+static unsigned int debug_forcedma = 0;
+static unsigned int debug_quirks = 0;
+
+#define SDHCI_QUIRK_CLOCK_BEFORE_RESET                 (1<<0)
+#define SDHCI_QUIRK_FORCE_DMA                          (1<<1)
+/* Controller doesn't like some resets when there is no card inserted. */
+#define SDHCI_QUIRK_NO_CARD_NO_RESET                   (1<<2)
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE                 (1<<3)
+
+static const struct pci_device_id pci_ids[] __devinitdata = {
+       {
+               .vendor         = PCI_VENDOR_ID_RICOH,
+               .device         = PCI_DEVICE_ID_RICOH_R5C822,
+               .subvendor      = PCI_VENDOR_ID_IBM,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_CLOCK_BEFORE_RESET |
+                                 SDHCI_QUIRK_FORCE_DMA,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_RICOH,
+               .device         = PCI_DEVICE_ID_RICOH_R5C822,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_FORCE_DMA |
+                                 SDHCI_QUIRK_NO_CARD_NO_RESET,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_TI,
+               .device         = PCI_DEVICE_ID_TI_XX21_XX11_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_FORCE_DMA,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_ENE,
+               .device         = PCI_DEVICE_ID_ENE_CB712_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE,
+       },
+
+       {       /* Generic SD host controller */
+               PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
+       },
+
+       { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
+static void sdhci_finish_data(struct sdhci_host *);
+
+static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
+static void sdhci_finish_command(struct sdhci_host *);
+
+static void sdhci_dumpregs(struct sdhci_host *host)
+{
+       printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
+
+       printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
+               readl(host->ioaddr + SDHCI_DMA_ADDRESS),
+               readw(host->ioaddr + SDHCI_HOST_VERSION));
+       printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
+               readw(host->ioaddr + SDHCI_BLOCK_SIZE),
+               readw(host->ioaddr + SDHCI_BLOCK_COUNT));
+       printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
+               readl(host->ioaddr + SDHCI_ARGUMENT),
+               readw(host->ioaddr + SDHCI_TRANSFER_MODE));
+       printk(KERN_DEBUG DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
+               readl(host->ioaddr + SDHCI_PRESENT_STATE),
+               readb(host->ioaddr + SDHCI_HOST_CONTROL));
+       printk(KERN_DEBUG DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
+               readb(host->ioaddr + SDHCI_POWER_CONTROL),
+               readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL));
+       printk(KERN_DEBUG DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
+               readb(host->ioaddr + SDHCI_WALK_UP_CONTROL),
+               readw(host->ioaddr + SDHCI_CLOCK_CONTROL));
+       printk(KERN_DEBUG DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
+               readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL),
+               readl(host->ioaddr + SDHCI_INT_STATUS));
+       printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
+               readl(host->ioaddr + SDHCI_INT_ENABLE),
+               readl(host->ioaddr + SDHCI_SIGNAL_ENABLE));
+       printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
+               readw(host->ioaddr + SDHCI_ACMD12_ERR),
+               readw(host->ioaddr + SDHCI_SLOT_INT_STATUS));
+       printk(KERN_DEBUG DRIVER_NAME ": Caps:     0x%08x | Max curr: 0x%08x\n",
+               readl(host->ioaddr + SDHCI_CAPABILITIES),
+               readl(host->ioaddr + SDHCI_MAX_CURRENT));
+
+       printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n");
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Low level functions                                                       *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+       unsigned long timeout;
+
+       if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
+               if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
+                       SDHCI_CARD_PRESENT))
+                       return;
+       }
+
+       writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
+
+       if (mask & SDHCI_RESET_ALL)
+               host->clock = 0;
+
+       /* Wait max 100 ms */
+       timeout = 100;
+
+       /* hw clears the bit when it's done */
+       while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) {
+               if (timeout == 0) {
+                       printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
+                               mmc_hostname(host->mmc), (int)mask);
+                       sdhci_dumpregs(host);
+                       return;
+               }
+               timeout--;
+               mdelay(1);
+       }
+}
+
+static void sdhci_init(struct sdhci_host *host)
+{
+       u32 intmask;
+
+       sdhci_reset(host, SDHCI_RESET_ALL);
+
+       intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
+               SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
+               SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
+               SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
+               SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
+               SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
+
+       writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
+       writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+}
+
+static void sdhci_activate_led(struct sdhci_host *host)
+{
+       u8 ctrl;
+
+       ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+       ctrl |= SDHCI_CTRL_LED;
+       writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+}
+
+static void sdhci_deactivate_led(struct sdhci_host *host)
+{
+       u8 ctrl;
+
+       ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+       ctrl &= ~SDHCI_CTRL_LED;
+       writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Core functions                                                            *
+ *                                                                           *
+\*****************************************************************************/
+
+static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
+{
+       return page_address(host->cur_sg->page) + host->cur_sg->offset;
+}
+
+static inline int sdhci_next_sg(struct sdhci_host* host)
+{
+       /*
+        * Skip to next SG entry.
+        */
+       host->cur_sg++;
+       host->num_sg--;
+
+       /*
+        * Any entries left?
+        */
+       if (host->num_sg > 0) {
+               host->offset = 0;
+               host->remain = host->cur_sg->length;
+       }
+
+       return host->num_sg;
+}
+
+static void sdhci_read_block_pio(struct sdhci_host *host)
+{
+       int blksize, chunk_remain;
+       u32 data;
+       char *buffer;
+       int size;
+
+       DBG("PIO reading\n");
+
+       blksize = host->data->blksz;
+       chunk_remain = 0;
+       data = 0;
+
+       buffer = sdhci_sg_to_buffer(host) + host->offset;
+
+       while (blksize) {
+               if (chunk_remain == 0) {
+                       data = readl(host->ioaddr + SDHCI_BUFFER);
+                       chunk_remain = min(blksize, 4);
+               }
+
+               size = min(host->remain, chunk_remain);
+
+               chunk_remain -= size;
+               blksize -= size;
+               host->offset += size;
+               host->remain -= size;
+
+               while (size) {
+                       *buffer = data & 0xFF;
+                       buffer++;
+                       data >>= 8;
+                       size--;
+               }
+
+               if (host->remain == 0) {
+                       if (sdhci_next_sg(host) == 0) {
+                               BUG_ON(blksize != 0);
+                               return;
+                       }
+                       buffer = sdhci_sg_to_buffer(host);
+               }
+       }
+}
+
+static void sdhci_write_block_pio(struct sdhci_host *host)
+{
+       int blksize, chunk_remain;
+       u32 data;
+       char *buffer;
+       int bytes, size;
+
+       DBG("PIO writing\n");
+
+       blksize = host->data->blksz;
+       chunk_remain = 4;
+       data = 0;
+
+       bytes = 0;
+       buffer = sdhci_sg_to_buffer(host) + host->offset;
+
+       while (blksize) {
+               size = min(host->remain, chunk_remain);
+
+               chunk_remain -= size;
+               blksize -= size;
+               host->offset += size;
+               host->remain -= size;
+
+               while (size) {
+                       data >>= 8;
+                       data |= (u32)*buffer << 24;
+                       buffer++;
+                       size--;
+               }
+
+               if (chunk_remain == 0) {
+                       writel(data, host->ioaddr + SDHCI_BUFFER);
+                       chunk_remain = min(blksize, 4);
+               }
+
+               if (host->remain == 0) {
+                       if (sdhci_next_sg(host) == 0) {
+                               BUG_ON(blksize != 0);
+                               return;
+                       }
+                       buffer = sdhci_sg_to_buffer(host);
+               }
+       }
+}
+
+static void sdhci_transfer_pio(struct sdhci_host *host)
+{
+       u32 mask;
+
+       BUG_ON(!host->data);
+
+       if (host->num_sg == 0)
+               return;
+
+       if (host->data->flags & MMC_DATA_READ)
+               mask = SDHCI_DATA_AVAILABLE;
+       else
+               mask = SDHCI_SPACE_AVAILABLE;
+
+       while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
+               if (host->data->flags & MMC_DATA_READ)
+                       sdhci_read_block_pio(host);
+               else
+                       sdhci_write_block_pio(host);
+
+               if (host->num_sg == 0)
+                       break;
+       }
+
+       DBG("PIO transfer complete.\n");
+}
+
+static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
+{
+       u8 count;
+       unsigned target_timeout, current_timeout;
+
+       WARN_ON(host->data);
+
+       if (data == NULL)
+               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 */
+       BUG_ON(data->blksz * data->blocks > 524288);
+       BUG_ON(data->blksz > host->mmc->max_blk_size);
+       BUG_ON(data->blocks > 65535);
+
+       /* timeout in us */
+       target_timeout = data->timeout_ns / 1000 +
+               data->timeout_clks / host->clock;
+
+       /*
+        * Figure out needed cycles.
+        * We do this in steps in order to fit inside a 32 bit int.
+        * The first step is the minimum timeout, which will have a
+        * minimum resolution of 6 bits:
+        * (1) 2^13*1000 > 2^22,
+        * (2) host->timeout_clk < 2^16
+        *     =>
+        *     (1) / (2) > 2^6
+        */
+       count = 0;
+       current_timeout = (1 << 13) * 1000 / host->timeout_clk;
+       while (current_timeout < target_timeout) {
+               count++;
+               current_timeout <<= 1;
+               if (count >= 0xF)
+                       break;
+       }
+
+       if (count >= 0xF) {
+               printk(KERN_WARNING "%s: Too large timeout requested!\n",
+                       mmc_hostname(host->mmc));
+               count = 0xE;
+       }
+
+       writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
+
+       if (host->flags & SDHCI_USE_DMA) {
+               int count;
+
+               count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len,
+                       (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
+               BUG_ON(count != 1);
+
+               writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
+       } else {
+               host->cur_sg = data->sg;
+               host->num_sg = data->sg_len;
+
+               host->offset = 0;
+               host->remain = host->cur_sg->length;
+       }
+
+       /* We do not handle DMA boundaries, so set it to max (512 KiB) */
+       writew(SDHCI_MAKE_BLKSZ(7, data->blksz),
+               host->ioaddr + SDHCI_BLOCK_SIZE);
+       writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
+}
+
+static void sdhci_set_transfer_mode(struct sdhci_host *host,
+       struct mmc_data *data)
+{
+       u16 mode;
+
+       WARN_ON(host->data);
+
+       if (data == NULL)
+               return;
+
+       mode = SDHCI_TRNS_BLK_CNT_EN;
+       if (data->blocks > 1)
+               mode |= SDHCI_TRNS_MULTI;
+       if (data->flags & MMC_DATA_READ)
+               mode |= SDHCI_TRNS_READ;
+       if (host->flags & SDHCI_USE_DMA)
+               mode |= SDHCI_TRNS_DMA;
+
+       writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
+}
+
+static void sdhci_finish_data(struct sdhci_host *host)
+{
+       struct mmc_data *data;
+       u16 blocks;
+
+       BUG_ON(!host->data);
+
+       data = host->data;
+       host->data = NULL;
+
+       if (host->flags & SDHCI_USE_DMA) {
+               pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len,
+                       (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
+       }
+
+       /*
+        * Controller doesn't count down when in single block mode.
+        */
+       if ((data->blocks == 1) && (data->error == MMC_ERR_NONE))
+               blocks = 0;
+       else
+               blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
+       data->bytes_xfered = data->blksz * (data->blocks - blocks);
+
+       if ((data->error == MMC_ERR_NONE) && blocks) {
+               printk(KERN_ERR "%s: Controller signalled completion even "
+                       "though there were blocks left.\n",
+                       mmc_hostname(host->mmc));
+               data->error = MMC_ERR_FAILED;
+       }
+
+       DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered);
+
+       if (data->stop) {
+               /*
+                * The controller needs a reset of internal state machines
+                * upon error conditions.
+                */
+               if (data->error != MMC_ERR_NONE) {
+                       sdhci_reset(host, SDHCI_RESET_CMD);
+                       sdhci_reset(host, SDHCI_RESET_DATA);
+               }
+
+               sdhci_send_command(host, data->stop);
+       } else
+               tasklet_schedule(&host->finish_tasklet);
+}
+
+static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+{
+       int flags;
+       u32 mask;
+       unsigned long timeout;
+
+       WARN_ON(host->cmd);
+
+       DBG("Sending cmd (%x)\n", cmd->opcode);
+
+       /* Wait max 10 ms */
+       timeout = 10;
+
+       mask = SDHCI_CMD_INHIBIT;
+       if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
+               mask |= SDHCI_DATA_INHIBIT;
+
+       /* We shouldn't wait for data inihibit for stop commands, even
+          though they might use busy signaling */
+       if (host->mrq->data && (cmd == host->mrq->data->stop))
+               mask &= ~SDHCI_DATA_INHIBIT;
+
+       while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
+               if (timeout == 0) {
+                       printk(KERN_ERR "%s: Controller never released "
+                               "inhibit bit(s).\n", mmc_hostname(host->mmc));
+                       sdhci_dumpregs(host);
+                       cmd->error = MMC_ERR_FAILED;
+                       tasklet_schedule(&host->finish_tasklet);
+                       return;
+               }
+               timeout--;
+               mdelay(1);
+       }
+
+       mod_timer(&host->timer, jiffies + 10 * HZ);
+
+       host->cmd = cmd;
+
+       sdhci_prepare_data(host, cmd->data);
+
+       writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT);
+
+       sdhci_set_transfer_mode(host, cmd->data);
+
+       if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
+               printk(KERN_ERR "%s: Unsupported response type!\n",
+                       mmc_hostname(host->mmc));
+               cmd->error = MMC_ERR_INVALID;
+               tasklet_schedule(&host->finish_tasklet);
+               return;
+       }
+
+       if (!(cmd->flags & MMC_RSP_PRESENT))
+               flags = SDHCI_CMD_RESP_NONE;
+       else if (cmd->flags & MMC_RSP_136)
+               flags = SDHCI_CMD_RESP_LONG;
+       else if (cmd->flags & MMC_RSP_BUSY)
+               flags = SDHCI_CMD_RESP_SHORT_BUSY;
+       else
+               flags = SDHCI_CMD_RESP_SHORT;
+
+       if (cmd->flags & MMC_RSP_CRC)
+               flags |= SDHCI_CMD_CRC;
+       if (cmd->flags & MMC_RSP_OPCODE)
+               flags |= SDHCI_CMD_INDEX;
+       if (cmd->data)
+               flags |= SDHCI_CMD_DATA;
+
+       writew(SDHCI_MAKE_CMD(cmd->opcode, flags),
+               host->ioaddr + SDHCI_COMMAND);
+}
+
+static void sdhci_finish_command(struct sdhci_host *host)
+{
+       int i;
+
+       BUG_ON(host->cmd == NULL);
+
+       if (host->cmd->flags & MMC_RSP_PRESENT) {
+               if (host->cmd->flags & MMC_RSP_136) {
+                       /* CRC is stripped so we need to do some shifting. */
+                       for (i = 0;i < 4;i++) {
+                               host->cmd->resp[i] = readl(host->ioaddr +
+                                       SDHCI_RESPONSE + (3-i)*4) << 8;
+                               if (i != 3)
+                                       host->cmd->resp[i] |=
+                                               readb(host->ioaddr +
+                                               SDHCI_RESPONSE + (3-i)*4-1);
+                       }
+               } else {
+                       host->cmd->resp[0] = readl(host->ioaddr + SDHCI_RESPONSE);
+               }
+       }
+
+       host->cmd->error = MMC_ERR_NONE;
+
+       DBG("Ending cmd (%x)\n", host->cmd->opcode);
+
+       if (host->cmd->data)
+               host->data = host->cmd->data;
+       else
+               tasklet_schedule(&host->finish_tasklet);
+
+       host->cmd = NULL;
+}
+
+static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+       int div;
+       u16 clk;
+       unsigned long timeout;
+
+       if (clock == host->clock)
+               return;
+
+       writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
+
+       if (clock == 0)
+               goto out;
+
+       for (div = 1;div < 256;div *= 2) {
+               if ((host->max_clk / div) <= clock)
+                       break;
+       }
+       div >>= 1;
+
+       clk = div << SDHCI_DIVIDER_SHIFT;
+       clk |= SDHCI_CLOCK_INT_EN;
+       writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
+
+       /* Wait max 10 ms */
+       timeout = 10;
+       while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL))
+               & SDHCI_CLOCK_INT_STABLE)) {
+               if (timeout == 0) {
+                       printk(KERN_ERR "%s: Internal clock never "
+                               "stabilised.\n", mmc_hostname(host->mmc));
+                       sdhci_dumpregs(host);
+                       return;
+               }
+               timeout--;
+               mdelay(1);
+       }
+
+       clk |= SDHCI_CLOCK_CARD_EN;
+       writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
+
+out:
+       host->clock = clock;
+}
+
+static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
+{
+       u8 pwr;
+
+       if (host->power == power)
+               return;
+
+       if (power == (unsigned short)-1) {
+               writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
+               goto out;
+       }
+
+       /*
+        * Spec says that we should clear the power reg before setting
+        * a new value. Some controllers don't seem to like this though.
+        */
+       if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+               writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
+
+       pwr = SDHCI_POWER_ON;
+
+       switch (power) {
+       case MMC_VDD_170:
+       case MMC_VDD_180:
+       case MMC_VDD_190:
+               pwr |= SDHCI_POWER_180;
+               break;
+       case MMC_VDD_290:
+       case MMC_VDD_300:
+       case MMC_VDD_310:
+               pwr |= SDHCI_POWER_300;
+               break;
+       case MMC_VDD_320:
+       case MMC_VDD_330:
+       case MMC_VDD_340:
+               pwr |= SDHCI_POWER_330;
+               break;
+       default:
+               BUG();
+       }
+
+       writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
+
+out:
+       host->power = power;
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * MMC callbacks                                                             *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct sdhci_host *host;
+       unsigned long flags;
+
+       host = mmc_priv(mmc);
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       WARN_ON(host->mrq != NULL);
+
+       sdhci_activate_led(host);
+
+       host->mrq = mrq;
+
+       if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
+               host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+               tasklet_schedule(&host->finish_tasklet);
+       } else
+               sdhci_send_command(host, mrq->cmd);
+
+       mmiowb();
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct sdhci_host *host;
+       unsigned long flags;
+       u8 ctrl;
+
+       host = mmc_priv(mmc);
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       /*
+        * Reset the chip on each power off.
+        * Should clear out any weird states.
+        */
+       if (ios->power_mode == MMC_POWER_OFF) {
+               writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+               sdhci_init(host);
+       }
+
+       sdhci_set_clock(host, ios->clock);
+
+       if (ios->power_mode == MMC_POWER_OFF)
+               sdhci_set_power(host, -1);
+       else
+               sdhci_set_power(host, ios->vdd);
+
+       ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+
+       if (ios->bus_width == MMC_BUS_WIDTH_4)
+               ctrl |= SDHCI_CTRL_4BITBUS;
+       else
+               ctrl &= ~SDHCI_CTRL_4BITBUS;
+
+       if (ios->timing == MMC_TIMING_SD_HS)
+               ctrl |= SDHCI_CTRL_HISPD;
+       else
+               ctrl &= ~SDHCI_CTRL_HISPD;
+
+       writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+
+       mmiowb();
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static int sdhci_get_ro(struct mmc_host *mmc)
+{
+       struct sdhci_host *host;
+       unsigned long flags;
+       int present;
+
+       host = mmc_priv(mmc);
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
+
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       return !(present & SDHCI_WRITE_PROTECT);
+}
+
+static const struct mmc_host_ops sdhci_ops = {
+       .request        = sdhci_request,
+       .set_ios        = sdhci_set_ios,
+       .get_ro         = sdhci_get_ro,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Tasklets                                                                  *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_tasklet_card(unsigned long param)
+{
+       struct sdhci_host *host;
+       unsigned long flags;
+
+       host = (struct sdhci_host*)param;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
+               if (host->mrq) {
+                       printk(KERN_ERR "%s: Card removed during transfer!\n",
+                               mmc_hostname(host->mmc));
+                       printk(KERN_ERR "%s: Resetting controller.\n",
+                               mmc_hostname(host->mmc));
+
+                       sdhci_reset(host, SDHCI_RESET_CMD);
+                       sdhci_reset(host, SDHCI_RESET_DATA);
+
+                       host->mrq->cmd->error = MMC_ERR_FAILED;
+                       tasklet_schedule(&host->finish_tasklet);
+               }
+       }
+
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+}
+
+static void sdhci_tasklet_finish(unsigned long param)
+{
+       struct sdhci_host *host;
+       unsigned long flags;
+       struct mmc_request *mrq;
+
+       host = (struct sdhci_host*)param;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       del_timer(&host->timer);
+
+       mrq = host->mrq;
+
+       DBG("Ending request, cmd (%x)\n", mrq->cmd->opcode);
+
+       /*
+        * The controller needs a reset of internal state machines
+        * upon error conditions.
+        */
+       if ((mrq->cmd->error != MMC_ERR_NONE) ||
+               (mrq->data && ((mrq->data->error != MMC_ERR_NONE) ||
+               (mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) {
+
+               /* Some controllers need this kick or reset won't work here */
+               if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
+                       unsigned int clock;
+
+                       /* This is to force an update */
+                       clock = host->clock;
+                       host->clock = 0;
+                       sdhci_set_clock(host, clock);
+               }
+
+               /* Spec says we should do both at the same time, but Ricoh
+                  controllers do not like that. */
+               sdhci_reset(host, SDHCI_RESET_CMD);
+               sdhci_reset(host, SDHCI_RESET_DATA);
+       }
+
+       host->mrq = NULL;
+       host->cmd = NULL;
+       host->data = NULL;
+
+       sdhci_deactivate_led(host);
+
+       mmiowb();
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       mmc_request_done(host->mmc, mrq);
+}
+
+static void sdhci_timeout_timer(unsigned long data)
+{
+       struct sdhci_host *host;
+       unsigned long flags;
+
+       host = (struct sdhci_host*)data;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (host->mrq) {
+               printk(KERN_ERR "%s: Timeout waiting for hardware "
+                       "interrupt.\n", mmc_hostname(host->mmc));
+               sdhci_dumpregs(host);
+
+               if (host->data) {
+                       host->data->error = MMC_ERR_TIMEOUT;
+                       sdhci_finish_data(host);
+               } else {
+                       if (host->cmd)
+                               host->cmd->error = MMC_ERR_TIMEOUT;
+                       else
+                               host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+
+                       tasklet_schedule(&host->finish_tasklet);
+               }
+       }
+
+       mmiowb();
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Interrupt handling                                                        *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
+{
+       BUG_ON(intmask == 0);
+
+       if (!host->cmd) {
+               printk(KERN_ERR "%s: Got command interrupt even though no "
+                       "command operation was in progress.\n",
+                       mmc_hostname(host->mmc));
+               sdhci_dumpregs(host);
+               return;
+       }
+
+       if (intmask & SDHCI_INT_RESPONSE)
+               sdhci_finish_command(host);
+       else {
+               if (intmask & SDHCI_INT_TIMEOUT)
+                       host->cmd->error = MMC_ERR_TIMEOUT;
+               else if (intmask & SDHCI_INT_CRC)
+                       host->cmd->error = MMC_ERR_BADCRC;
+               else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
+                       host->cmd->error = MMC_ERR_FAILED;
+               else
+                       host->cmd->error = MMC_ERR_INVALID;
+
+               tasklet_schedule(&host->finish_tasklet);
+       }
+}
+
+static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
+{
+       BUG_ON(intmask == 0);
+
+       if (!host->data) {
+               /*
+                * A data end interrupt is sent together with the response
+                * for the stop command.
+                */
+               if (intmask & SDHCI_INT_DATA_END)
+                       return;
+
+               printk(KERN_ERR "%s: Got data interrupt even though no "
+                       "data operation was in progress.\n",
+                       mmc_hostname(host->mmc));
+               sdhci_dumpregs(host);
+
+               return;
+       }
+
+       if (intmask & SDHCI_INT_DATA_TIMEOUT)
+               host->data->error = MMC_ERR_TIMEOUT;
+       else if (intmask & SDHCI_INT_DATA_CRC)
+               host->data->error = MMC_ERR_BADCRC;
+       else if (intmask & SDHCI_INT_DATA_END_BIT)
+               host->data->error = MMC_ERR_FAILED;
+
+       if (host->data->error != MMC_ERR_NONE)
+               sdhci_finish_data(host);
+       else {
+               if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
+                       sdhci_transfer_pio(host);
+
+               if (intmask & SDHCI_INT_DATA_END)
+                       sdhci_finish_data(host);
+       }
+}
+
+static irqreturn_t sdhci_irq(int irq, void *dev_id)
+{
+       irqreturn_t result;
+       struct sdhci_host* host = dev_id;
+       u32 intmask;
+
+       spin_lock(&host->lock);
+
+       intmask = readl(host->ioaddr + SDHCI_INT_STATUS);
+
+       if (!intmask || intmask == 0xffffffff) {
+               result = IRQ_NONE;
+               goto out;
+       }
+
+       DBG("*** %s got interrupt: 0x%08x\n", host->slot_descr, intmask);
+
+       if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+               writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE),
+                       host->ioaddr + SDHCI_INT_STATUS);
+               tasklet_schedule(&host->card_tasklet);
+       }
+
+       intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
+
+       if (intmask & SDHCI_INT_CMD_MASK) {
+               writel(intmask & SDHCI_INT_CMD_MASK,
+                       host->ioaddr + SDHCI_INT_STATUS);
+               sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
+       }
+
+       if (intmask & SDHCI_INT_DATA_MASK) {
+               writel(intmask & SDHCI_INT_DATA_MASK,
+                       host->ioaddr + SDHCI_INT_STATUS);
+               sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
+       }
+
+       intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
+
+       if (intmask & SDHCI_INT_BUS_POWER) {
+               printk(KERN_ERR "%s: Card is consuming too much power!\n",
+                       mmc_hostname(host->mmc));
+               writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS);
+       }
+
+       intmask &= SDHCI_INT_BUS_POWER;
+
+       if (intmask) {
+               printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
+                       mmc_hostname(host->mmc), intmask);
+               sdhci_dumpregs(host);
+
+               writel(intmask, host->ioaddr + SDHCI_INT_STATUS);
+       }
+
+       result = IRQ_HANDLED;
+
+       mmiowb();
+out:
+       spin_unlock(&host->lock);
+
+       return result;
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Suspend/resume                                                            *
+ *                                                                           *
+\*****************************************************************************/
+
+#ifdef CONFIG_PM
+
+static int sdhci_suspend (struct pci_dev *pdev, pm_message_t state)
+{
+       struct sdhci_chip *chip;
+       int i, ret;
+
+       chip = pci_get_drvdata(pdev);
+       if (!chip)
+               return 0;
+
+       DBG("Suspending...\n");
+
+       for (i = 0;i < chip->num_slots;i++) {
+               if (!chip->hosts[i])
+                       continue;
+               ret = mmc_suspend_host(chip->hosts[i]->mmc, state);
+               if (ret) {
+                       for (i--;i >= 0;i--)
+                               mmc_resume_host(chip->hosts[i]->mmc);
+                       return ret;
+               }
+       }
+
+       pci_save_state(pdev);
+       pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+
+       for (i = 0;i < chip->num_slots;i++) {
+               if (!chip->hosts[i])
+                       continue;
+               free_irq(chip->hosts[i]->irq, chip->hosts[i]);
+       }
+
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+       return 0;
+}
+
+static int sdhci_resume (struct pci_dev *pdev)
+{
+       struct sdhci_chip *chip;
+       int i, ret;
+
+       chip = pci_get_drvdata(pdev);
+       if (!chip)
+               return 0;
+
+       DBG("Resuming...\n");
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+
+       for (i = 0;i < chip->num_slots;i++) {
+               if (!chip->hosts[i])
+                       continue;
+               if (chip->hosts[i]->flags & SDHCI_USE_DMA)
+                       pci_set_master(pdev);
+               ret = request_irq(chip->hosts[i]->irq, sdhci_irq,
+                       IRQF_SHARED, chip->hosts[i]->slot_descr,
+                       chip->hosts[i]);
+               if (ret)
+                       return ret;
+               sdhci_init(chip->hosts[i]);
+               mmiowb();
+               ret = mmc_resume_host(chip->hosts[i]->mmc);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+#else /* CONFIG_PM */
+
+#define sdhci_suspend NULL
+#define sdhci_resume NULL
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************\
+ *                                                                           *
+ * Device probing/removal                                                    *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
+{
+       int ret;
+       unsigned int version;
+       struct sdhci_chip *chip;
+       struct mmc_host *mmc;
+       struct sdhci_host *host;
+
+       u8 first_bar;
+       unsigned int caps;
+
+       chip = pci_get_drvdata(pdev);
+       BUG_ON(!chip);
+
+       ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
+       if (ret)
+               return ret;
+
+       first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
+
+       if (first_bar > 5) {
+               printk(KERN_ERR DRIVER_NAME ": Invalid first BAR. Aborting.\n");
+               return -ENODEV;
+       }
+
+       if (!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)) {
+               printk(KERN_ERR DRIVER_NAME ": BAR is not iomem. Aborting.\n");
+               return -ENODEV;
+       }
+
+       if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
+               printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. "
+                       "You may experience problems.\n");
+       }
+
+       if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
+               printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n");
+               return -ENODEV;
+       }
+
+       if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
+               printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n");
+               return -ENODEV;
+       }
+
+       mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
+       if (!mmc)
+               return -ENOMEM;
+
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+
+       host->chip = chip;
+       chip->hosts[slot] = host;
+
+       host->bar = first_bar + slot;
+
+       host->addr = pci_resource_start(pdev, host->bar);
+       host->irq = pdev->irq;
+
+       DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq);
+
+       snprintf(host->slot_descr, 20, "sdhci:slot%d", slot);
+
+       ret = pci_request_region(pdev, host->bar, host->slot_descr);
+       if (ret)
+               goto free;
+
+       host->ioaddr = ioremap_nocache(host->addr,
+               pci_resource_len(pdev, host->bar));
+       if (!host->ioaddr) {
+               ret = -ENOMEM;
+               goto release;
+       }
+
+       sdhci_reset(host, SDHCI_RESET_ALL);
+
+       version = readw(host->ioaddr + SDHCI_HOST_VERSION);
+       version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
+       if (version != 0) {
+               printk(KERN_ERR "%s: Unknown controller version (%d). "
+                       "You may experience problems.\n", host->slot_descr,
+                       version);
+       }
+
+       caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
+
+       if (debug_nodma)
+               DBG("DMA forced off\n");
+       else if (debug_forcedma) {
+               DBG("DMA forced on\n");
+               host->flags |= SDHCI_USE_DMA;
+       } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
+               host->flags |= SDHCI_USE_DMA;
+       else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
+               DBG("Controller doesn't have DMA interface\n");
+       else if (!(caps & SDHCI_CAN_DO_DMA))
+               DBG("Controller doesn't have DMA capability\n");
+       else
+               host->flags |= SDHCI_USE_DMA;
+
+       if (host->flags & SDHCI_USE_DMA) {
+               if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+                       printk(KERN_WARNING "%s: No suitable DMA available. "
+                               "Falling back to PIO.\n", host->slot_descr);
+                       host->flags &= ~SDHCI_USE_DMA;
+               }
+       }
+
+       if (host->flags & SDHCI_USE_DMA)
+               pci_set_master(pdev);
+       else /* XXX: Hack to get MMC layer to avoid highmem */
+               pdev->dma_mask = 0;
+
+       host->max_clk =
+               (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
+       if (host->max_clk == 0) {
+               printk(KERN_ERR "%s: Hardware doesn't specify base clock "
+                       "frequency.\n", host->slot_descr);
+               ret = -ENODEV;
+               goto unmap;
+       }
+       host->max_clk *= 1000000;
+
+       host->timeout_clk =
+               (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
+       if (host->timeout_clk == 0) {
+               printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
+                       "frequency.\n", host->slot_descr);
+               ret = -ENODEV;
+               goto unmap;
+       }
+       if (caps & SDHCI_TIMEOUT_CLK_UNIT)
+               host->timeout_clk *= 1000;
+
+       /*
+        * Set host parameters.
+        */
+       mmc->ops = &sdhci_ops;
+       mmc->f_min = host->max_clk / 256;
+       mmc->f_max = host->max_clk;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+
+       if (caps & SDHCI_CAN_DO_HISPD)
+               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+
+       mmc->ocr_avail = 0;
+       if (caps & SDHCI_CAN_VDD_330)
+               mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
+       if (caps & SDHCI_CAN_VDD_300)
+               mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
+       if (caps & SDHCI_CAN_VDD_180)
+               mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
+
+       if (mmc->ocr_avail == 0) {
+               printk(KERN_ERR "%s: Hardware doesn't report any "
+                       "support voltages.\n", host->slot_descr);
+               ret = -ENODEV;
+               goto unmap;
+       }
+
+       spin_lock_init(&host->lock);
+
+       /*
+        * Maximum number of segments. Hardware cannot do scatter lists.
+        */
+       if (host->flags & SDHCI_USE_DMA)
+               mmc->max_hw_segs = 1;
+       else
+               mmc->max_hw_segs = 16;
+       mmc->max_phys_segs = 16;
+
+       /*
+        * Maximum number of sectors in one transfer. Limited by DMA boundary
+        * size (512KiB).
+        */
+       mmc->max_req_size = 524288;
+
+       /*
+        * Maximum segment size. Could be one segment with the maximum number
+        * of bytes.
+        */
+       mmc->max_seg_size = mmc->max_req_size;
+
+       /*
+        * Maximum block size. This varies from controller to controller and
+        * is specified in the capabilities register.
+        */
+       mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
+       if (mmc->max_blk_size >= 3) {
+               printk(KERN_ERR "%s: Invalid maximum block size.\n",
+                       host->slot_descr);
+               ret = -ENODEV;
+               goto unmap;
+       }
+       mmc->max_blk_size = 512 << mmc->max_blk_size;
+
+       /*
+        * Maximum block count.
+        */
+       mmc->max_blk_count = 65535;
+
+       /*
+        * Init tasklets.
+        */
+       tasklet_init(&host->card_tasklet,
+               sdhci_tasklet_card, (unsigned long)host);
+       tasklet_init(&host->finish_tasklet,
+               sdhci_tasklet_finish, (unsigned long)host);
+
+       setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
+
+       ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
+               host->slot_descr, host);
+       if (ret)
+               goto untasklet;
+
+       sdhci_init(host);
+
+#ifdef CONFIG_MMC_DEBUG
+       sdhci_dumpregs(host);
+#endif
+
+       mmiowb();
+
+       mmc_add_host(mmc);
+
+       printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", mmc_hostname(mmc),
+               host->addr, host->irq,
+               (host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
+
+       return 0;
+
+untasklet:
+       tasklet_kill(&host->card_tasklet);
+       tasklet_kill(&host->finish_tasklet);
+unmap:
+       iounmap(host->ioaddr);
+release:
+       pci_release_region(pdev, host->bar);
+free:
+       mmc_free_host(mmc);
+
+       return ret;
+}
+
+static void sdhci_remove_slot(struct pci_dev *pdev, int slot)
+{
+       struct sdhci_chip *chip;
+       struct mmc_host *mmc;
+       struct sdhci_host *host;
+
+       chip = pci_get_drvdata(pdev);
+       host = chip->hosts[slot];
+       mmc = host->mmc;
+
+       chip->hosts[slot] = NULL;
+
+       mmc_remove_host(mmc);
+
+       sdhci_reset(host, SDHCI_RESET_ALL);
+
+       free_irq(host->irq, host);
+
+       del_timer_sync(&host->timer);
+
+       tasklet_kill(&host->card_tasklet);
+       tasklet_kill(&host->finish_tasklet);
+
+       iounmap(host->ioaddr);
+
+       pci_release_region(pdev, host->bar);
+
+       mmc_free_host(mmc);
+}
+
+static int __devinit sdhci_probe(struct pci_dev *pdev,
+       const struct pci_device_id *ent)
+{
+       int ret, i;
+       u8 slots, rev;
+       struct sdhci_chip *chip;
+
+       BUG_ON(pdev == NULL);
+       BUG_ON(ent == NULL);
+
+       pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
+
+       printk(KERN_INFO DRIVER_NAME
+               ": SDHCI controller found at %s [%04x:%04x] (rev %x)\n",
+               pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
+               (int)rev);
+
+       ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
+       if (ret)
+               return ret;
+
+       slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
+       DBG("found %d slot(s)\n", slots);
+       if (slots == 0)
+               return -ENODEV;
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+
+       chip = kzalloc(sizeof(struct sdhci_chip) +
+               sizeof(struct sdhci_host*) * slots, GFP_KERNEL);
+       if (!chip) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       chip->pdev = pdev;
+       chip->quirks = ent->driver_data;
+
+       if (debug_quirks)
+               chip->quirks = debug_quirks;
+
+       chip->num_slots = slots;
+       pci_set_drvdata(pdev, chip);
+
+       for (i = 0;i < slots;i++) {
+               ret = sdhci_probe_slot(pdev, i);
+               if (ret) {
+                       for (i--;i >= 0;i--)
+                               sdhci_remove_slot(pdev, i);
+                       goto free;
+               }
+       }
+
+       return 0;
+
+free:
+       pci_set_drvdata(pdev, NULL);
+       kfree(chip);
+
+err:
+       pci_disable_device(pdev);
+       return ret;
+}
+
+static void __devexit sdhci_remove(struct pci_dev *pdev)
+{
+       int i;
+       struct sdhci_chip *chip;
+
+       chip = pci_get_drvdata(pdev);
+
+       if (chip) {
+               for (i = 0;i < chip->num_slots;i++)
+                       sdhci_remove_slot(pdev, i);
+
+               pci_set_drvdata(pdev, NULL);
+
+               kfree(chip);
+       }
+
+       pci_disable_device(pdev);
+}
+
+static struct pci_driver sdhci_driver = {
+       .name =         DRIVER_NAME,
+       .id_table =     pci_ids,
+       .probe =        sdhci_probe,
+       .remove =       __devexit_p(sdhci_remove),
+       .suspend =      sdhci_suspend,
+       .resume =       sdhci_resume,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Driver init/exit                                                          *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __init sdhci_drv_init(void)
+{
+       printk(KERN_INFO DRIVER_NAME
+               ": Secure Digital Host Controller Interface driver\n");
+       printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
+
+       return pci_register_driver(&sdhci_driver);
+}
+
+static void __exit sdhci_drv_exit(void)
+{
+       DBG("Exiting\n");
+
+       pci_unregister_driver(&sdhci_driver);
+}
+
+module_init(sdhci_drv_init);
+module_exit(sdhci_drv_exit);
+
+module_param(debug_nodma, uint, 0444);
+module_param(debug_forcedma, uint, 0444);
+module_param(debug_quirks, uint, 0444);
+
+MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
+MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
+MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)");
+MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
new file mode 100644 (file)
index 0000000..7400f4b
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ *  linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver
+ *
+ *  Copyright (C) 2005-2007 Pierre Ossman, 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+/*
+ * PCI registers
+ */
+
+#define PCI_SDHCI_IFPIO                        0x00
+#define PCI_SDHCI_IFDMA                        0x01
+#define PCI_SDHCI_IFVENDOR             0x02
+
+#define PCI_SLOT_INFO                  0x40    /* 8 bits */
+#define  PCI_SLOT_INFO_SLOTS(x)                ((x >> 4) & 7)
+#define  PCI_SLOT_INFO_FIRST_BAR_MASK  0x07
+
+/*
+ * Controller registers
+ */
+
+#define SDHCI_DMA_ADDRESS      0x00
+
+#define SDHCI_BLOCK_SIZE       0x04
+#define  SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
+
+#define SDHCI_BLOCK_COUNT      0x06
+
+#define SDHCI_ARGUMENT         0x08
+
+#define SDHCI_TRANSFER_MODE    0x0C
+#define  SDHCI_TRNS_DMA                0x01
+#define  SDHCI_TRNS_BLK_CNT_EN 0x02
+#define  SDHCI_TRNS_ACMD12     0x04
+#define  SDHCI_TRNS_READ       0x10
+#define  SDHCI_TRNS_MULTI      0x20
+
+#define SDHCI_COMMAND          0x0E
+#define  SDHCI_CMD_RESP_MASK   0x03
+#define  SDHCI_CMD_CRC         0x08
+#define  SDHCI_CMD_INDEX       0x10
+#define  SDHCI_CMD_DATA                0x20
+
+#define  SDHCI_CMD_RESP_NONE   0x00
+#define  SDHCI_CMD_RESP_LONG   0x01
+#define  SDHCI_CMD_RESP_SHORT  0x02
+#define  SDHCI_CMD_RESP_SHORT_BUSY 0x03
+
+#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
+
+#define SDHCI_RESPONSE         0x10
+
+#define SDHCI_BUFFER           0x20
+
+#define SDHCI_PRESENT_STATE    0x24
+#define  SDHCI_CMD_INHIBIT     0x00000001
+#define  SDHCI_DATA_INHIBIT    0x00000002
+#define  SDHCI_DOING_WRITE     0x00000100
+#define  SDHCI_DOING_READ      0x00000200
+#define  SDHCI_SPACE_AVAILABLE 0x00000400
+#define  SDHCI_DATA_AVAILABLE  0x00000800
+#define  SDHCI_CARD_PRESENT    0x00010000
+#define  SDHCI_WRITE_PROTECT   0x00080000
+
+#define SDHCI_HOST_CONTROL     0x28
+#define  SDHCI_CTRL_LED                0x01
+#define  SDHCI_CTRL_4BITBUS    0x02
+#define  SDHCI_CTRL_HISPD      0x04
+
+#define SDHCI_POWER_CONTROL    0x29
+#define  SDHCI_POWER_ON                0x01
+#define  SDHCI_POWER_180       0x0A
+#define  SDHCI_POWER_300       0x0C
+#define  SDHCI_POWER_330       0x0E
+
+#define SDHCI_BLOCK_GAP_CONTROL        0x2A
+
+#define SDHCI_WALK_UP_CONTROL  0x2B
+
+#define SDHCI_CLOCK_CONTROL    0x2C
+#define  SDHCI_DIVIDER_SHIFT   8
+#define  SDHCI_CLOCK_CARD_EN   0x0004
+#define  SDHCI_CLOCK_INT_STABLE        0x0002
+#define  SDHCI_CLOCK_INT_EN    0x0001
+
+#define SDHCI_TIMEOUT_CONTROL  0x2E
+
+#define SDHCI_SOFTWARE_RESET   0x2F
+#define  SDHCI_RESET_ALL       0x01
+#define  SDHCI_RESET_CMD       0x02
+#define  SDHCI_RESET_DATA      0x04
+
+#define SDHCI_INT_STATUS       0x30
+#define SDHCI_INT_ENABLE       0x34
+#define SDHCI_SIGNAL_ENABLE    0x38
+#define  SDHCI_INT_RESPONSE    0x00000001
+#define  SDHCI_INT_DATA_END    0x00000002
+#define  SDHCI_INT_DMA_END     0x00000008
+#define  SDHCI_INT_SPACE_AVAIL 0x00000010
+#define  SDHCI_INT_DATA_AVAIL  0x00000020
+#define  SDHCI_INT_CARD_INSERT 0x00000040
+#define  SDHCI_INT_CARD_REMOVE 0x00000080
+#define  SDHCI_INT_CARD_INT    0x00000100
+#define  SDHCI_INT_TIMEOUT     0x00010000
+#define  SDHCI_INT_CRC         0x00020000
+#define  SDHCI_INT_END_BIT     0x00040000
+#define  SDHCI_INT_INDEX       0x00080000
+#define  SDHCI_INT_DATA_TIMEOUT        0x00100000
+#define  SDHCI_INT_DATA_CRC    0x00200000
+#define  SDHCI_INT_DATA_END_BIT        0x00400000
+#define  SDHCI_INT_BUS_POWER   0x00800000
+#define  SDHCI_INT_ACMD12ERR   0x01000000
+
+#define  SDHCI_INT_NORMAL_MASK 0x00007FFF
+#define  SDHCI_INT_ERROR_MASK  0xFFFF8000
+
+#define  SDHCI_INT_CMD_MASK    (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
+               SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
+#define  SDHCI_INT_DATA_MASK   (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
+               SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
+               SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
+               SDHCI_INT_DATA_END_BIT)
+
+#define SDHCI_ACMD12_ERR       0x3C
+
+/* 3E-3F reserved */
+
+#define SDHCI_CAPABILITIES     0x40
+#define  SDHCI_TIMEOUT_CLK_MASK        0x0000003F
+#define  SDHCI_TIMEOUT_CLK_SHIFT 0
+#define  SDHCI_TIMEOUT_CLK_UNIT        0x00000080
+#define  SDHCI_CLOCK_BASE_MASK 0x00003F00
+#define  SDHCI_CLOCK_BASE_SHIFT        8
+#define  SDHCI_MAX_BLOCK_MASK  0x00030000
+#define  SDHCI_MAX_BLOCK_SHIFT  16
+#define  SDHCI_CAN_DO_HISPD    0x00200000
+#define  SDHCI_CAN_DO_DMA      0x00400000
+#define  SDHCI_CAN_VDD_330     0x01000000
+#define  SDHCI_CAN_VDD_300     0x02000000
+#define  SDHCI_CAN_VDD_180     0x04000000
+
+/* 44-47 reserved for more caps */
+
+#define SDHCI_MAX_CURRENT      0x48
+
+/* 4C-4F reserved for more max current */
+
+/* 50-FB reserved */
+
+#define SDHCI_SLOT_INT_STATUS  0xFC
+
+#define SDHCI_HOST_VERSION     0xFE
+#define  SDHCI_VENDOR_VER_MASK 0xFF00
+#define  SDHCI_VENDOR_VER_SHIFT        8
+#define  SDHCI_SPEC_VER_MASK   0x00FF
+#define  SDHCI_SPEC_VER_SHIFT  0
+
+struct sdhci_chip;
+
+struct sdhci_host {
+       struct sdhci_chip       *chip;
+       struct mmc_host         *mmc;           /* MMC structure */
+
+       spinlock_t              lock;           /* Mutex */
+
+       int                     flags;          /* Host attributes */
+#define SDHCI_USE_DMA          (1<<0)
+
+       unsigned int            max_clk;        /* Max possible freq (MHz) */
+       unsigned int            timeout_clk;    /* Timeout freq (KHz) */
+
+       unsigned int            clock;          /* Current clock (MHz) */
+       unsigned short          power;          /* Current voltage */
+
+       struct mmc_request      *mrq;           /* Current request */
+       struct mmc_command      *cmd;           /* Current command */
+       struct mmc_data         *data;          /* Current data request */
+
+       struct scatterlist      *cur_sg;        /* We're working on this */
+       int                     num_sg;         /* Entries left */
+       int                     offset;         /* Offset into current sg */
+       int                     remain;         /* Bytes left in current */
+
+       char                    slot_descr[20]; /* Name for reservations */
+
+       int                     irq;            /* Device IRQ */
+       int                     bar;            /* PCI BAR index */
+       unsigned long           addr;           /* Bus address */
+       void __iomem *          ioaddr;         /* Mapped address */
+
+       struct tasklet_struct   card_tasklet;   /* Tasklet structures */
+       struct tasklet_struct   finish_tasklet;
+
+       struct timer_list       timer;          /* Timer for timeouts */
+};
+
+struct sdhci_chip {
+       struct pci_dev          *pdev;
+
+       unsigned long           quirks;
+
+       int                     num_slots;      /* Slots on controller */
+       struct sdhci_host       *hosts[0];      /* Pointers to hosts */
+};
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
new file mode 100644 (file)
index 0000000..b0d77d2
--- /dev/null
@@ -0,0 +1,1102 @@
+/*
+ *  tifm_sd.c - TI FlashMedia driver
+ *
+ *  Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
+ *
+ * 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.
+ *
+ * Special thanks to Brad Campbell for extensive testing of this driver.
+ *
+ */
+
+
+#include <linux/tifm.h>
+#include <linux/mmc/host.h>
+#include <linux/highmem.h>
+#include <linux/scatterlist.h>
+#include <asm/io.h>
+
+#define DRIVER_NAME "tifm_sd"
+#define DRIVER_VERSION "0.8"
+
+static int no_dma = 0;
+static int fixed_timeout = 0;
+module_param(no_dma, bool, 0644);
+module_param(fixed_timeout, bool, 0644);
+
+/* Constants here are mostly from OMAP5912 datasheet */
+#define TIFM_MMCSD_RESET      0x0002
+#define TIFM_MMCSD_CLKMASK    0x03ff
+#define TIFM_MMCSD_POWER      0x0800
+#define TIFM_MMCSD_4BBUS      0x8000
+#define TIFM_MMCSD_RXDE       0x8000   /* rx dma enable */
+#define TIFM_MMCSD_TXDE       0x0080   /* tx dma enable */
+#define TIFM_MMCSD_BUFINT     0x0c00   /* set bits: AE, AF */
+#define TIFM_MMCSD_DPE        0x0020   /* data timeout counted in kilocycles */
+#define TIFM_MMCSD_INAB       0x0080   /* abort / initialize command */
+#define TIFM_MMCSD_READ       0x8000
+
+#define TIFM_MMCSD_ERRMASK    0x01e0   /* set bits: CCRC, CTO, DCRC, DTO */
+#define TIFM_MMCSD_EOC        0x0001   /* end of command phase  */
+#define TIFM_MMCSD_CD         0x0002   /* card detect           */
+#define TIFM_MMCSD_CB         0x0004   /* card enter busy state */
+#define TIFM_MMCSD_BRS        0x0008   /* block received/sent   */
+#define TIFM_MMCSD_EOFB       0x0010   /* card exit busy state  */
+#define TIFM_MMCSD_DTO        0x0020   /* data time-out         */
+#define TIFM_MMCSD_DCRC       0x0040   /* data crc error        */
+#define TIFM_MMCSD_CTO        0x0080   /* command time-out      */
+#define TIFM_MMCSD_CCRC       0x0100   /* command crc error     */
+#define TIFM_MMCSD_AF         0x0400   /* fifo almost full      */
+#define TIFM_MMCSD_AE         0x0800   /* fifo almost empty     */
+#define TIFM_MMCSD_OCRB       0x1000   /* OCR busy              */
+#define TIFM_MMCSD_CIRQ       0x2000   /* card irq (cmd40/sdio) */
+#define TIFM_MMCSD_CERR       0x4000   /* card status error     */
+
+#define TIFM_MMCSD_ODTO       0x0040   /* open drain / extended timeout */
+#define TIFM_MMCSD_CARD_RO    0x0200   /* card is read-only     */
+
+#define TIFM_MMCSD_FIFO_SIZE  0x0020
+
+#define TIFM_MMCSD_RSP_R0     0x0000
+#define TIFM_MMCSD_RSP_R1     0x0100
+#define TIFM_MMCSD_RSP_R2     0x0200
+#define TIFM_MMCSD_RSP_R3     0x0300
+#define TIFM_MMCSD_RSP_R4     0x0400
+#define TIFM_MMCSD_RSP_R5     0x0500
+#define TIFM_MMCSD_RSP_R6     0x0600
+
+#define TIFM_MMCSD_RSP_BUSY   0x0800
+
+#define TIFM_MMCSD_CMD_BC     0x0000
+#define TIFM_MMCSD_CMD_BCR    0x1000
+#define TIFM_MMCSD_CMD_AC     0x2000
+#define TIFM_MMCSD_CMD_ADTC   0x3000
+
+#define TIFM_MMCSD_MAX_BLOCK_SIZE  0x0800UL
+
+enum {
+       CMD_READY    = 0x0001,
+       FIFO_READY   = 0x0002,
+       BRS_READY    = 0x0004,
+       SCMD_ACTIVE  = 0x0008,
+       SCMD_READY   = 0x0010,
+       CARD_BUSY    = 0x0020,
+       DATA_CARRY   = 0x0040
+};
+
+struct tifm_sd {
+       struct tifm_dev       *dev;
+
+       unsigned short        eject:1,
+                             open_drain:1,
+                             no_dma:1;
+       unsigned short        cmd_flags;
+
+       unsigned int          clk_freq;
+       unsigned int          clk_div;
+       unsigned long         timeout_jiffies;
+
+       struct tasklet_struct finish_tasklet;
+       struct timer_list     timer;
+       struct mmc_request    *req;
+
+       int                   sg_len;
+       int                   sg_pos;
+       unsigned int          block_pos;
+       struct scatterlist    bounce_buf;
+       unsigned char         bounce_buf_data[TIFM_MMCSD_MAX_BLOCK_SIZE];
+};
+
+/* for some reason, host won't respond correctly to readw/writew */
+static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
+                             unsigned int off, unsigned int cnt)
+{
+       struct tifm_dev *sock = host->dev;
+       unsigned char *buf;
+       unsigned int pos = 0, val;
+
+       buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + off;
+       if (host->cmd_flags & DATA_CARRY) {
+               buf[pos++] = host->bounce_buf_data[0];
+               host->cmd_flags &= ~DATA_CARRY;
+       }
+
+       while (pos < cnt) {
+               val = readl(sock->addr + SOCK_MMCSD_DATA);
+               buf[pos++] = val & 0xff;
+               if (pos == cnt) {
+                       host->bounce_buf_data[0] = (val >> 8) & 0xff;
+                       host->cmd_flags |= DATA_CARRY;
+                       break;
+               }
+               buf[pos++] = (val >> 8) & 0xff;
+       }
+       kunmap_atomic(buf - off, KM_BIO_DST_IRQ);
+}
+
+static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
+                              unsigned int off, unsigned int cnt)
+{
+       struct tifm_dev *sock = host->dev;
+       unsigned char *buf;
+       unsigned int pos = 0, val;
+
+       buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + off;
+       if (host->cmd_flags & DATA_CARRY) {
+               val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00);
+               writel(val, sock->addr + SOCK_MMCSD_DATA);
+               host->cmd_flags &= ~DATA_CARRY;
+       }
+
+       while (pos < cnt) {
+               val = buf[pos++];
+               if (pos == cnt) {
+                       host->bounce_buf_data[0] = val & 0xff;
+                       host->cmd_flags |= DATA_CARRY;
+                       break;
+               }
+               val |= (buf[pos++] << 8) & 0xff00;
+               writel(val, sock->addr + SOCK_MMCSD_DATA);
+       }
+       kunmap_atomic(buf - off, KM_BIO_SRC_IRQ);
+}
+
+static void tifm_sd_transfer_data(struct tifm_sd *host)
+{
+       struct mmc_data *r_data = host->req->cmd->data;
+       struct scatterlist *sg = r_data->sg;
+       unsigned int off, cnt, t_size = TIFM_MMCSD_FIFO_SIZE * 2;
+       unsigned int p_off, p_cnt;
+       struct page *pg;
+
+       if (host->sg_pos == host->sg_len)
+               return;
+       while (t_size) {
+               cnt = sg[host->sg_pos].length - host->block_pos;
+               if (!cnt) {
+                       host->block_pos = 0;
+                       host->sg_pos++;
+                       if (host->sg_pos == host->sg_len) {
+                               if ((r_data->flags & MMC_DATA_WRITE)
+                                   && DATA_CARRY)
+                                       writel(host->bounce_buf_data[0],
+                                              host->dev->addr
+                                              + SOCK_MMCSD_DATA);
+
+                               return;
+                       }
+                       cnt = sg[host->sg_pos].length;
+               }
+               off = sg[host->sg_pos].offset + host->block_pos;
+
+               pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
+               p_off = offset_in_page(off);
+               p_cnt = PAGE_SIZE - p_off;
+               p_cnt = min(p_cnt, cnt);
+               p_cnt = min(p_cnt, t_size);
+
+               if (r_data->flags & MMC_DATA_READ)
+                       tifm_sd_read_fifo(host, pg, p_off, p_cnt);
+               else if (r_data->flags & MMC_DATA_WRITE)
+                       tifm_sd_write_fifo(host, pg, p_off, p_cnt);
+
+               t_size -= p_cnt;
+               host->block_pos += p_cnt;
+       }
+}
+
+static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off,
+                             struct page *src, unsigned int src_off,
+                             unsigned int count)
+{
+       unsigned char *src_buf = kmap_atomic(src, KM_BIO_SRC_IRQ) + src_off;
+       unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off;
+
+       memcpy(dst_buf, src_buf, count);
+
+       kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ);
+       kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ);
+}
+
+static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data)
+{
+       struct scatterlist *sg = r_data->sg;
+       unsigned int t_size = r_data->blksz;
+       unsigned int off, cnt;
+       unsigned int p_off, p_cnt;
+       struct page *pg;
+
+       dev_dbg(&host->dev->dev, "bouncing block\n");
+       while (t_size) {
+               cnt = sg[host->sg_pos].length - host->block_pos;
+               if (!cnt) {
+                       host->block_pos = 0;
+                       host->sg_pos++;
+                       if (host->sg_pos == host->sg_len)
+                               return;
+                       cnt = sg[host->sg_pos].length;
+               }
+               off = sg[host->sg_pos].offset + host->block_pos;
+
+               pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
+               p_off = offset_in_page(off);
+               p_cnt = PAGE_SIZE - p_off;
+               p_cnt = min(p_cnt, cnt);
+               p_cnt = min(p_cnt, t_size);
+
+               if (r_data->flags & MMC_DATA_WRITE)
+                       tifm_sd_copy_page(host->bounce_buf.page,
+                                         r_data->blksz - t_size,
+                                         pg, p_off, p_cnt);
+               else if (r_data->flags & MMC_DATA_READ)
+                       tifm_sd_copy_page(pg, p_off, host->bounce_buf.page,
+                                         r_data->blksz - t_size, p_cnt);
+
+               t_size -= p_cnt;
+               host->block_pos += p_cnt;
+       }
+}
+
+int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data)
+{
+       struct tifm_dev *sock = host->dev;
+       unsigned int t_size = TIFM_DMA_TSIZE * r_data->blksz;
+       unsigned int dma_len, dma_blk_cnt, dma_off;
+       struct scatterlist *sg = NULL;
+       unsigned long flags;
+
+       if (host->sg_pos == host->sg_len)
+               return 1;
+
+       if (host->cmd_flags & DATA_CARRY) {
+               host->cmd_flags &= ~DATA_CARRY;
+               local_irq_save(flags);
+               tifm_sd_bounce_block(host, r_data);
+               local_irq_restore(flags);
+               if (host->sg_pos == host->sg_len)
+                       return 1;
+       }
+
+       dma_len = sg_dma_len(&r_data->sg[host->sg_pos]) - host->block_pos;
+       if (!dma_len) {
+               host->block_pos = 0;
+               host->sg_pos++;
+               if (host->sg_pos == host->sg_len)
+                       return 1;
+               dma_len = sg_dma_len(&r_data->sg[host->sg_pos]);
+       }
+
+       if (dma_len < t_size) {
+               dma_blk_cnt = dma_len / r_data->blksz;
+               dma_off = host->block_pos;
+               host->block_pos += dma_blk_cnt * r_data->blksz;
+       } else {
+               dma_blk_cnt = TIFM_DMA_TSIZE;
+               dma_off = host->block_pos;
+               host->block_pos += t_size;
+       }
+
+       if (dma_blk_cnt)
+               sg = &r_data->sg[host->sg_pos];
+       else if (dma_len) {
+               if (r_data->flags & MMC_DATA_WRITE) {
+                       local_irq_save(flags);
+                       tifm_sd_bounce_block(host, r_data);
+                       local_irq_restore(flags);
+               } else
+                       host->cmd_flags |= DATA_CARRY;
+
+               sg = &host->bounce_buf;
+               dma_off = 0;
+               dma_blk_cnt = 1;
+       } else
+               return 1;
+
+       dev_dbg(&sock->dev, "setting dma for %d blocks\n", dma_blk_cnt);
+       writel(sg_dma_address(sg) + dma_off, sock->addr + SOCK_DMA_ADDRESS);
+       if (r_data->flags & MMC_DATA_WRITE)
+               writel((dma_blk_cnt << 8) | TIFM_DMA_TX | TIFM_DMA_EN,
+                      sock->addr + SOCK_DMA_CONTROL);
+       else
+               writel((dma_blk_cnt << 8) | TIFM_DMA_EN,
+                      sock->addr + SOCK_DMA_CONTROL);
+
+       return 0;
+}
+
+static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
+{
+       unsigned int rc = 0;
+
+       switch (mmc_resp_type(cmd)) {
+       case MMC_RSP_NONE:
+               rc |= TIFM_MMCSD_RSP_R0;
+               break;
+       case MMC_RSP_R1B:
+               rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through
+       case MMC_RSP_R1:
+               rc |= TIFM_MMCSD_RSP_R1;
+               break;
+       case MMC_RSP_R2:
+               rc |= TIFM_MMCSD_RSP_R2;
+               break;
+       case MMC_RSP_R3:
+               rc |= TIFM_MMCSD_RSP_R3;
+               break;
+       default:
+               BUG();
+       }
+
+       switch (mmc_cmd_type(cmd)) {
+       case MMC_CMD_BC:
+               rc |= TIFM_MMCSD_CMD_BC;
+               break;
+       case MMC_CMD_BCR:
+               rc |= TIFM_MMCSD_CMD_BCR;
+               break;
+       case MMC_CMD_AC:
+               rc |= TIFM_MMCSD_CMD_AC;
+               break;
+       case MMC_CMD_ADTC:
+               rc |= TIFM_MMCSD_CMD_ADTC;
+               break;
+       default:
+               BUG();
+       }
+       return rc;
+}
+
+static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
+{
+       struct tifm_dev *sock = host->dev;
+       unsigned int cmd_mask = tifm_sd_op_flags(cmd);
+
+       if (host->open_drain)
+               cmd_mask |= TIFM_MMCSD_ODTO;
+
+       if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
+               cmd_mask |= TIFM_MMCSD_READ;
+
+       dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
+               cmd->opcode, cmd->arg, cmd_mask);
+
+       writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
+       writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
+       writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND);
+}
+
+static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock)
+{
+       cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16)
+                      | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18);
+       cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16)
+                      | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10);
+       cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16)
+                      | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08);
+       cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16)
+                      | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00);
+}
+
+static void tifm_sd_check_status(struct tifm_sd *host)
+{
+       struct tifm_dev *sock = host->dev;
+       struct mmc_command *cmd = host->req->cmd;
+
+       if (cmd->error != MMC_ERR_NONE)
+               goto finish_request;
+
+       if (!(host->cmd_flags & CMD_READY))
+               return;
+
+       if (cmd->data) {
+               if (cmd->data->error != MMC_ERR_NONE) {
+                       if ((host->cmd_flags & SCMD_ACTIVE)
+                           && !(host->cmd_flags & SCMD_READY))
+                               return;
+
+                       goto finish_request;
+               }
+
+               if (!(host->cmd_flags & BRS_READY))
+                       return;
+
+               if (!(host->no_dma || (host->cmd_flags & FIFO_READY)))
+                       return;
+
+               if (cmd->data->flags & MMC_DATA_WRITE) {
+                       if (host->req->stop) {
+                               if (!(host->cmd_flags & SCMD_ACTIVE)) {
+                                       host->cmd_flags |= SCMD_ACTIVE;
+                                       writel(TIFM_MMCSD_EOFB
+                                              | readl(sock->addr
+                                                      + SOCK_MMCSD_INT_ENABLE),
+                                              sock->addr
+                                              + SOCK_MMCSD_INT_ENABLE);
+                                       tifm_sd_exec(host, host->req->stop);
+                                       return;
+                               } else {
+                                       if (!(host->cmd_flags & SCMD_READY)
+                                           || (host->cmd_flags & CARD_BUSY))
+                                               return;
+                                       writel((~TIFM_MMCSD_EOFB)
+                                              & readl(sock->addr
+                                                      + SOCK_MMCSD_INT_ENABLE),
+                                              sock->addr
+                                              + SOCK_MMCSD_INT_ENABLE);
+                               }
+                       } else {
+                               if (host->cmd_flags & CARD_BUSY)
+                                       return;
+                               writel((~TIFM_MMCSD_EOFB)
+                                      & readl(sock->addr
+                                              + SOCK_MMCSD_INT_ENABLE),
+                                      sock->addr + SOCK_MMCSD_INT_ENABLE);
+                       }
+               } else {
+                       if (host->req->stop) {
+                               if (!(host->cmd_flags & SCMD_ACTIVE)) {
+                                       host->cmd_flags |= SCMD_ACTIVE;
+                                       tifm_sd_exec(host, host->req->stop);
+                                       return;
+                               } else {
+                                       if (!(host->cmd_flags & SCMD_READY))
+                                               return;
+                               }
+                       }
+               }
+       }
+finish_request:
+       tasklet_schedule(&host->finish_tasklet);
+}
+
+/* Called from interrupt handler */
+static void tifm_sd_data_event(struct tifm_dev *sock)
+{
+       struct tifm_sd *host;
+       unsigned int fifo_status = 0;
+       struct mmc_data *r_data = NULL;
+
+       spin_lock(&sock->lock);
+       host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
+       fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
+       dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n",
+               fifo_status, host->cmd_flags);
+
+       if (host->req) {
+               r_data = host->req->cmd->data;
+
+               if (r_data && (fifo_status & TIFM_FIFO_READY)) {
+                       if (tifm_sd_set_dma_data(host, r_data)) {
+                               host->cmd_flags |= FIFO_READY;
+                               tifm_sd_check_status(host);
+                       }
+               }
+       }
+
+       writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
+       spin_unlock(&sock->lock);
+}
+
+/* Called from interrupt handler */
+static void tifm_sd_card_event(struct tifm_dev *sock)
+{
+       struct tifm_sd *host;
+       unsigned int host_status = 0;
+       int cmd_error = MMC_ERR_NONE;
+       struct mmc_command *cmd = NULL;
+       unsigned long flags;
+
+       spin_lock(&sock->lock);
+       host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
+       host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+       dev_dbg(&sock->dev, "host event: host_status %x, flags %x\n",
+               host_status, host->cmd_flags);
+
+       if (host->req) {
+               cmd = host->req->cmd;
+
+               if (host_status & TIFM_MMCSD_ERRMASK) {
+                       writel(host_status & TIFM_MMCSD_ERRMASK,
+                              sock->addr + SOCK_MMCSD_STATUS);
+                       if (host_status & TIFM_MMCSD_CTO)
+                               cmd_error = MMC_ERR_TIMEOUT;
+                       else if (host_status & TIFM_MMCSD_CCRC)
+                               cmd_error = MMC_ERR_BADCRC;
+
+                       if (cmd->data) {
+                               if (host_status & TIFM_MMCSD_DTO)
+                                       cmd->data->error = MMC_ERR_TIMEOUT;
+                               else if (host_status & TIFM_MMCSD_DCRC)
+                                       cmd->data->error = MMC_ERR_BADCRC;
+                       }
+
+                       writel(TIFM_FIFO_INT_SETALL,
+                              sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+                       writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
+
+                       if (host->req->stop) {
+                               if (host->cmd_flags & SCMD_ACTIVE) {
+                                       host->req->stop->error = cmd_error;
+                                       host->cmd_flags |= SCMD_READY;
+                               } else {
+                                       cmd->error = cmd_error;
+                                       host->cmd_flags |= SCMD_ACTIVE;
+                                       tifm_sd_exec(host, host->req->stop);
+                                       goto done;
+                               }
+                       } else
+                               cmd->error = cmd_error;
+               } else {
+                       if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {
+                               if (!(host->cmd_flags & CMD_READY)) {
+                                       host->cmd_flags |= CMD_READY;
+                                       tifm_sd_fetch_resp(cmd, sock);
+                               } else if (host->cmd_flags & SCMD_ACTIVE) {
+                                       host->cmd_flags |= SCMD_READY;
+                                       tifm_sd_fetch_resp(host->req->stop,
+                                                          sock);
+                               }
+                       }
+                       if (host_status & TIFM_MMCSD_BRS)
+                               host->cmd_flags |= BRS_READY;
+               }
+
+               if (host->no_dma && cmd->data) {
+                       if (host_status & TIFM_MMCSD_AE)
+                               writel(host_status & TIFM_MMCSD_AE,
+                                      sock->addr + SOCK_MMCSD_STATUS);
+
+                       if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF
+                                          | TIFM_MMCSD_BRS)) {
+                               local_irq_save(flags);
+                               tifm_sd_transfer_data(host);
+                               local_irq_restore(flags);
+                               host_status &= ~TIFM_MMCSD_AE;
+                       }
+               }
+
+               if (host_status & TIFM_MMCSD_EOFB)
+                       host->cmd_flags &= ~CARD_BUSY;
+               else if (host_status & TIFM_MMCSD_CB)
+                       host->cmd_flags |= CARD_BUSY;
+
+               tifm_sd_check_status(host);
+       }
+done:
+       writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+       spin_unlock(&sock->lock);
+}
+
+static void tifm_sd_set_data_timeout(struct tifm_sd *host,
+                                    struct mmc_data *data)
+{
+       struct tifm_dev *sock = host->dev;
+       unsigned int data_timeout = data->timeout_clks;
+
+       if (fixed_timeout)
+               return;
+
+       data_timeout += data->timeout_ns /
+                       ((1000000000UL / host->clk_freq) * host->clk_div);
+
+       if (data_timeout < 0xffff) {
+               writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+               writel((~TIFM_MMCSD_DPE)
+                      & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+                      sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
+       } else {
+               data_timeout = (data_timeout >> 10) + 1;
+               if (data_timeout > 0xffff)
+                       data_timeout = 0;       /* set to unlimited */
+               writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+               writel(TIFM_MMCSD_DPE
+                      | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+                      sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
+       }
+}
+
+static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct tifm_sd *host = mmc_priv(mmc);
+       struct tifm_dev *sock = host->dev;
+       unsigned long flags;
+       struct mmc_data *r_data = mrq->cmd->data;
+
+       spin_lock_irqsave(&sock->lock, flags);
+       if (host->eject) {
+               spin_unlock_irqrestore(&sock->lock, flags);
+               goto err_out;
+       }
+
+       if (host->req) {
+               printk(KERN_ERR "%s : unfinished request detected\n",
+                      sock->dev.bus_id);
+               spin_unlock_irqrestore(&sock->lock, flags);
+               goto err_out;
+       }
+
+       host->cmd_flags = 0;
+       host->block_pos = 0;
+       host->sg_pos = 0;
+
+       if (r_data) {
+               tifm_sd_set_data_timeout(host, r_data);
+
+               if ((r_data->flags & MMC_DATA_WRITE) && !mrq->stop)
+                        writel(TIFM_MMCSD_EOFB
+                               | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+                               sock->addr + SOCK_MMCSD_INT_ENABLE);
+
+               if (host->no_dma) {
+                       writel(TIFM_MMCSD_BUFINT
+                              | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+                              sock->addr + SOCK_MMCSD_INT_ENABLE);
+                       writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
+                              | (TIFM_MMCSD_FIFO_SIZE - 1),
+                              sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+                       host->sg_len = r_data->sg_len;
+               } else {
+                       sg_init_one(&host->bounce_buf, host->bounce_buf_data,
+                                   r_data->blksz);
+
+                       if(1 != tifm_map_sg(sock, &host->bounce_buf, 1,
+                                           r_data->flags & MMC_DATA_WRITE
+                                           ? PCI_DMA_TODEVICE
+                                           : PCI_DMA_FROMDEVICE)) {
+                               printk(KERN_ERR "%s : scatterlist map failed\n",
+                                      sock->dev.bus_id);
+                               spin_unlock_irqrestore(&sock->lock, flags);
+                               goto err_out;
+                       }
+                       host->sg_len = tifm_map_sg(sock, r_data->sg,
+                                                  r_data->sg_len,
+                                                  r_data->flags
+                                                  & MMC_DATA_WRITE
+                                                  ? PCI_DMA_TODEVICE
+                                                  : PCI_DMA_FROMDEVICE);
+                       if (host->sg_len < 1) {
+                               printk(KERN_ERR "%s : scatterlist map failed\n",
+                                      sock->dev.bus_id);
+                               tifm_unmap_sg(sock, &host->bounce_buf, 1,
+                                             r_data->flags & MMC_DATA_WRITE
+                                             ? PCI_DMA_TODEVICE
+                                             : PCI_DMA_FROMDEVICE);
+                               spin_unlock_irqrestore(&sock->lock, flags);
+                               goto err_out;
+                       }
+
+                       writel(TIFM_FIFO_INT_SETALL,
+                              sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+                       writel(ilog2(r_data->blksz) - 2,
+                              sock->addr + SOCK_FIFO_PAGE_SIZE);
+                       writel(TIFM_FIFO_ENABLE,
+                              sock->addr + SOCK_FIFO_CONTROL);
+                       writel(TIFM_FIFO_INTMASK,
+                              sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+
+                       if (r_data->flags & MMC_DATA_WRITE)
+                               writel(TIFM_MMCSD_TXDE,
+                                      sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+                       else
+                               writel(TIFM_MMCSD_RXDE,
+                                      sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+                       tifm_sd_set_dma_data(host, r_data);
+               }
+
+               writel(r_data->blocks - 1,
+                      sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+               writel(r_data->blksz - 1,
+                      sock->addr + SOCK_MMCSD_BLOCK_LEN);
+       }
+
+       host->req = mrq;
+       mod_timer(&host->timer, jiffies + host->timeout_jiffies);
+       writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
+              sock->addr + SOCK_CONTROL);
+       tifm_sd_exec(host, mrq->cmd);
+       spin_unlock_irqrestore(&sock->lock, flags);
+       return;
+
+err_out:
+       mrq->cmd->error = MMC_ERR_TIMEOUT;
+       mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_end_cmd(unsigned long data)
+{
+       struct tifm_sd *host = (struct tifm_sd*)data;
+       struct tifm_dev *sock = host->dev;
+       struct mmc_host *mmc = tifm_get_drvdata(sock);
+       struct mmc_request *mrq;
+       struct mmc_data *r_data = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sock->lock, flags);
+
+       del_timer(&host->timer);
+       mrq = host->req;
+       host->req = NULL;
+
+       if (!mrq) {
+               printk(KERN_ERR " %s : no request to complete?\n",
+                      sock->dev.bus_id);
+               spin_unlock_irqrestore(&sock->lock, flags);
+               return;
+       }
+
+       r_data = mrq->cmd->data;
+       if (r_data) {
+               if (host->no_dma) {
+                       writel((~TIFM_MMCSD_BUFINT)
+                              & readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+                              sock->addr + SOCK_MMCSD_INT_ENABLE);
+               } else {
+                       tifm_unmap_sg(sock, &host->bounce_buf, 1,
+                                     (r_data->flags & MMC_DATA_WRITE)
+                                     ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+                       tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
+                                     (r_data->flags & MMC_DATA_WRITE)
+                                     ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+               }
+
+               r_data->bytes_xfered = r_data->blocks
+                       - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
+               r_data->bytes_xfered *= r_data->blksz;
+               r_data->bytes_xfered += r_data->blksz
+                       - readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
+       }
+
+       writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
+              sock->addr + SOCK_CONTROL);
+
+       spin_unlock_irqrestore(&sock->lock, flags);
+       mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_abort(unsigned long data)
+{
+       struct tifm_sd *host = (struct tifm_sd*)data;
+
+       printk(KERN_ERR
+              "%s : card failed to respond for a long period of time "
+              "(%x, %x)\n",
+              host->dev->dev.bus_id, host->req->cmd->opcode, host->cmd_flags);
+
+       tifm_eject(host->dev);
+}
+
+static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct tifm_sd *host = mmc_priv(mmc);
+       struct tifm_dev *sock = host->dev;
+       unsigned int clk_div1, clk_div2;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sock->lock, flags);
+
+       dev_dbg(&sock->dev, "ios: clock = %u, vdd = %x, bus_mode = %x, "
+               "chip_select = %x, power_mode = %x, bus_width = %x\n",
+               ios->clock, ios->vdd, ios->bus_mode, ios->chip_select,
+               ios->power_mode, ios->bus_width);
+
+       if (ios->bus_width == MMC_BUS_WIDTH_4) {
+               writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
+                      sock->addr + SOCK_MMCSD_CONFIG);
+       } else {
+               writel((~TIFM_MMCSD_4BBUS)
+                      & readl(sock->addr + SOCK_MMCSD_CONFIG),
+                      sock->addr + SOCK_MMCSD_CONFIG);
+       }
+
+       if (ios->clock) {
+               clk_div1 = 20000000 / ios->clock;
+               if (!clk_div1)
+                       clk_div1 = 1;
+
+               clk_div2 = 24000000 / ios->clock;
+               if (!clk_div2)
+                       clk_div2 = 1;
+
+               if ((20000000 / clk_div1) > ios->clock)
+                       clk_div1++;
+               if ((24000000 / clk_div2) > ios->clock)
+                       clk_div2++;
+               if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
+                       host->clk_freq = 20000000;
+                       host->clk_div = clk_div1;
+                       writel((~TIFM_CTRL_FAST_CLK)
+                              & readl(sock->addr + SOCK_CONTROL),
+                              sock->addr + SOCK_CONTROL);
+               } else {
+                       host->clk_freq = 24000000;
+                       host->clk_div = clk_div2;
+                       writel(TIFM_CTRL_FAST_CLK
+                              | readl(sock->addr + SOCK_CONTROL),
+                              sock->addr + SOCK_CONTROL);
+               }
+       } else {
+               host->clk_div = 0;
+       }
+       host->clk_div &= TIFM_MMCSD_CLKMASK;
+       writel(host->clk_div
+              | ((~TIFM_MMCSD_CLKMASK)
+                 & readl(sock->addr + SOCK_MMCSD_CONFIG)),
+              sock->addr + SOCK_MMCSD_CONFIG);
+
+       host->open_drain = (ios->bus_mode == MMC_BUSMODE_OPENDRAIN);
+
+       /* chip_select : maybe later */
+       //vdd
+       //power is set before probe / after remove
+
+       spin_unlock_irqrestore(&sock->lock, flags);
+}
+
+static int tifm_sd_ro(struct mmc_host *mmc)
+{
+       int rc = 0;
+       struct tifm_sd *host = mmc_priv(mmc);
+       struct tifm_dev *sock = host->dev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sock->lock, flags);
+       if (TIFM_MMCSD_CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE))
+               rc = 1;
+       spin_unlock_irqrestore(&sock->lock, flags);
+       return rc;
+}
+
+static const struct mmc_host_ops tifm_sd_ops = {
+       .request = tifm_sd_request,
+       .set_ios = tifm_sd_ios,
+       .get_ro  = tifm_sd_ro
+};
+
+static int tifm_sd_initialize_host(struct tifm_sd *host)
+{
+       int rc;
+       unsigned int host_status = 0;
+       struct tifm_dev *sock = host->dev;
+
+       writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+       mmiowb();
+       host->clk_div = 61;
+       host->clk_freq = 20000000;
+       writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
+       writel(host->clk_div | TIFM_MMCSD_POWER,
+              sock->addr + SOCK_MMCSD_CONFIG);
+
+       /* wait up to 0.51 sec for reset */
+       for (rc = 32; rc <= 256; rc <<= 1) {
+               if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
+                       rc = 0;
+                       break;
+               }
+               msleep(rc);
+       }
+
+       if (rc) {
+               printk(KERN_ERR "%s : controller failed to reset\n",
+                      sock->dev.bus_id);
+               return -ENODEV;
+       }
+
+       writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+       writel(host->clk_div | TIFM_MMCSD_POWER,
+              sock->addr + SOCK_MMCSD_CONFIG);
+       writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+       // command timeout fixed to 64 clocks for now
+       writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
+       writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
+
+       for (rc = 16; rc <= 64; rc <<= 1) {
+               host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+               writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+               if (!(host_status & TIFM_MMCSD_ERRMASK)
+                   && (host_status & TIFM_MMCSD_EOC)) {
+                       rc = 0;
+                       break;
+               }
+               msleep(rc);
+       }
+
+       if (rc) {
+               printk(KERN_ERR
+                      "%s : card not ready - probe failed on initialization\n",
+                      sock->dev.bus_id);
+               return -ENODEV;
+       }
+
+       writel(TIFM_MMCSD_CERR | TIFM_MMCSD_BRS | TIFM_MMCSD_EOC
+              | TIFM_MMCSD_ERRMASK,
+              sock->addr + SOCK_MMCSD_INT_ENABLE);
+       mmiowb();
+
+       return 0;
+}
+
+static int tifm_sd_probe(struct tifm_dev *sock)
+{
+       struct mmc_host *mmc;
+       struct tifm_sd *host;
+       int rc = -EIO;
+
+       if (!(TIFM_SOCK_STATE_OCCUPIED
+             & readl(sock->addr + SOCK_PRESENT_STATE))) {
+               printk(KERN_WARNING "%s : card gone, unexpectedly\n",
+                      sock->dev.bus_id);
+               return rc;
+       }
+
+       mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev);
+       if (!mmc)
+               return -ENOMEM;
+
+       host = mmc_priv(mmc);
+       host->no_dma = no_dma;
+       tifm_set_drvdata(sock, mmc);
+       host->dev = sock;
+       host->timeout_jiffies = msecs_to_jiffies(1000);
+
+       tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd,
+                    (unsigned long)host);
+       setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
+
+       mmc->ops = &tifm_sd_ops;
+       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
+       mmc->f_min = 20000000 / 60;
+       mmc->f_max = 24000000;
+
+       mmc->max_blk_count = 2048;
+       mmc->max_hw_segs = mmc->max_blk_count;
+       mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE);
+       mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;
+       mmc->max_req_size = mmc->max_seg_size;
+       mmc->max_phys_segs = mmc->max_hw_segs;
+
+       sock->card_event = tifm_sd_card_event;
+       sock->data_event = tifm_sd_data_event;
+       rc = tifm_sd_initialize_host(host);
+
+       if (!rc)
+               rc = mmc_add_host(mmc);
+       if (!rc)
+               return 0;
+
+       mmc_free_host(mmc);
+       return rc;
+}
+
+static void tifm_sd_remove(struct tifm_dev *sock)
+{
+       struct mmc_host *mmc = tifm_get_drvdata(sock);
+       struct tifm_sd *host = mmc_priv(mmc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&sock->lock, flags);
+       host->eject = 1;
+       writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+       mmiowb();
+       spin_unlock_irqrestore(&sock->lock, flags);
+
+       tasklet_kill(&host->finish_tasklet);
+
+       spin_lock_irqsave(&sock->lock, flags);
+       if (host->req) {
+               writel(TIFM_FIFO_INT_SETALL,
+                      sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+               writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+               host->req->cmd->error = MMC_ERR_TIMEOUT;
+               if (host->req->stop)
+                       host->req->stop->error = MMC_ERR_TIMEOUT;
+               tasklet_schedule(&host->finish_tasklet);
+       }
+       spin_unlock_irqrestore(&sock->lock, flags);
+       mmc_remove_host(mmc);
+       dev_dbg(&sock->dev, "after remove\n");
+
+       /* The meaning of the bit majority in this constant is unknown. */
+       writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+              sock->addr + SOCK_CONTROL);
+
+       mmc_free_host(mmc);
+}
+
+#ifdef CONFIG_PM
+
+static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
+{
+       struct mmc_host *mmc = tifm_get_drvdata(sock);
+       int rc;
+
+       rc = mmc_suspend_host(mmc, state);
+       /* The meaning of the bit majority in this constant is unknown. */
+       writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+              sock->addr + SOCK_CONTROL);
+       return rc;
+}
+
+static int tifm_sd_resume(struct tifm_dev *sock)
+{
+       struct mmc_host *mmc = tifm_get_drvdata(sock);
+       struct tifm_sd *host = mmc_priv(mmc);
+       int rc;
+
+       rc = tifm_sd_initialize_host(host);
+       dev_dbg(&sock->dev, "resume initialize %d\n", rc);
+
+       if (rc)
+               host->eject = 1;
+       else
+               rc = mmc_resume_host(mmc);
+
+       return rc;
+}
+
+#else
+
+#define tifm_sd_suspend NULL
+#define tifm_sd_resume NULL
+
+#endif /* CONFIG_PM */
+
+static struct tifm_device_id tifm_sd_id_tbl[] = {
+       { TIFM_TYPE_SD }, { }
+};
+
+static struct tifm_driver tifm_sd_driver = {
+       .driver = {
+               .name  = DRIVER_NAME,
+               .owner = THIS_MODULE
+       },
+       .id_table = tifm_sd_id_tbl,
+       .probe    = tifm_sd_probe,
+       .remove   = tifm_sd_remove,
+       .suspend  = tifm_sd_suspend,
+       .resume   = tifm_sd_resume
+};
+
+static int __init tifm_sd_init(void)
+{
+       return tifm_register_driver(&tifm_sd_driver);
+}
+
+static void __exit tifm_sd_exit(void)
+{
+       tifm_unregister_driver(&tifm_sd_driver);
+}
+
+MODULE_AUTHOR("Alex Dubov");
+MODULE_DESCRIPTION("TI FlashMedia SD driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl);
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(tifm_sd_init);
+module_exit(tifm_sd_exit);
diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c
new file mode 100644 (file)
index 0000000..9f7518b
--- /dev/null
@@ -0,0 +1,2062 @@
+/*
+ *  linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
+ *
+ *  Copyright (C) 2004-2007 Pierre Ossman, 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ *
+ * Warning!
+ *
+ * Changes to the FIFO system should be done with extreme care since
+ * the hardware is full of bugs related to the FIFO. Known issues are:
+ *
+ * - FIFO size field in FSR is always zero.
+ *
+ * - FIFO interrupts tend not to work as they should. Interrupts are
+ *   triggered only for full/empty events, not for threshold values.
+ *
+ * - On APIC systems the FIFO empty interrupt is sometimes lost.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/pnp.h>
+#include <linux/highmem.h>
+#include <linux/mmc/host.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/scatterlist.h>
+
+#include "wbsd.h"
+
+#define DRIVER_NAME "wbsd"
+
+#define DBG(x...) \
+       pr_debug(DRIVER_NAME ": " x)
+#define DBGF(f, x...) \
+       pr_debug(DRIVER_NAME " [%s()]: " f, __func__ , ##x)
+
+/*
+ * Device resources
+ */
+
+#ifdef CONFIG_PNP
+
+static const struct pnp_device_id pnp_dev_table[] = {
+       { "WEC0517", 0 },
+       { "WEC0518", 0 },
+       { "", 0 },
+};
+
+MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
+
+#endif /* CONFIG_PNP */
+
+static const int config_ports[] = { 0x2E, 0x4E };
+static const int unlock_codes[] = { 0x83, 0x87 };
+
+static const int valid_ids[] = {
+       0x7112,
+       };
+
+#ifdef CONFIG_PNP
+static unsigned int nopnp = 0;
+#else
+static const unsigned int nopnp = 1;
+#endif
+static unsigned int io = 0x248;
+static unsigned int irq = 6;
+static int dma = 2;
+
+/*
+ * Basic functions
+ */
+
+static inline void wbsd_unlock_config(struct wbsd_host *host)
+{
+       BUG_ON(host->config == 0);
+
+       outb(host->unlock_code, host->config);
+       outb(host->unlock_code, host->config);
+}
+
+static inline void wbsd_lock_config(struct wbsd_host *host)
+{
+       BUG_ON(host->config == 0);
+
+       outb(LOCK_CODE, host->config);
+}
+
+static inline void wbsd_write_config(struct wbsd_host *host, u8 reg, u8 value)
+{
+       BUG_ON(host->config == 0);
+
+       outb(reg, host->config);
+       outb(value, host->config + 1);
+}
+
+static inline u8 wbsd_read_config(struct wbsd_host *host, u8 reg)
+{
+       BUG_ON(host->config == 0);
+
+       outb(reg, host->config);
+       return inb(host->config + 1);
+}
+
+static inline void wbsd_write_index(struct wbsd_host *host, u8 index, u8 value)
+{
+       outb(index, host->base + WBSD_IDXR);
+       outb(value, host->base + WBSD_DATAR);
+}
+
+static inline u8 wbsd_read_index(struct wbsd_host *host, u8 index)
+{
+       outb(index, host->base + WBSD_IDXR);
+       return inb(host->base + WBSD_DATAR);
+}
+
+/*
+ * Common routines
+ */
+
+static void wbsd_init_device(struct wbsd_host *host)
+{
+       u8 setup, ier;
+
+       /*
+        * Reset chip (SD/MMC part) and fifo.
+        */
+       setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+       setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET;
+       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+
+       /*
+        * Set DAT3 to input
+        */
+       setup &= ~WBSD_DAT3_H;
+       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+       host->flags &= ~WBSD_FIGNORE_DETECT;
+
+       /*
+        * Read back default clock.
+        */
+       host->clk = wbsd_read_index(host, WBSD_IDX_CLK);
+
+       /*
+        * Power down port.
+        */
+       outb(WBSD_POWER_N, host->base + WBSD_CSR);
+
+       /*
+        * Set maximum timeout.
+        */
+       wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F);
+
+       /*
+        * Test for card presence
+        */
+       if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)
+               host->flags |= WBSD_FCARD_PRESENT;
+       else
+               host->flags &= ~WBSD_FCARD_PRESENT;
+
+       /*
+        * Enable interesting interrupts.
+        */
+       ier = 0;
+       ier |= WBSD_EINT_CARD;
+       ier |= WBSD_EINT_FIFO_THRE;
+       ier |= WBSD_EINT_CRC;
+       ier |= WBSD_EINT_TIMEOUT;
+       ier |= WBSD_EINT_TC;
+
+       outb(ier, host->base + WBSD_EIR);
+
+       /*
+        * Clear interrupts.
+        */
+       inb(host->base + WBSD_ISR);
+}
+
+static void wbsd_reset(struct wbsd_host *host)
+{
+       u8 setup;
+
+       printk(KERN_ERR "%s: Resetting chip\n", mmc_hostname(host->mmc));
+
+       /*
+        * Soft reset of chip (SD/MMC part).
+        */
+       setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+       setup |= WBSD_SOFT_RESET;
+       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+}
+
+static void wbsd_request_end(struct wbsd_host *host, struct mmc_request *mrq)
+{
+       unsigned long dmaflags;
+
+       DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode);
+
+       if (host->dma >= 0) {
+               /*
+                * Release ISA DMA controller.
+                */
+               dmaflags = claim_dma_lock();
+               disable_dma(host->dma);
+               clear_dma_ff(host->dma);
+               release_dma_lock(dmaflags);
+
+               /*
+                * Disable DMA on host.
+                */
+               wbsd_write_index(host, WBSD_IDX_DMA, 0);
+       }
+
+       host->mrq = NULL;
+
+       /*
+        * MMC layer might call back into the driver so first unlock.
+        */
+       spin_unlock(&host->lock);
+       mmc_request_done(host->mmc, mrq);
+       spin_lock(&host->lock);
+}
+
+/*
+ * Scatter/gather functions
+ */
+
+static inline void wbsd_init_sg(struct wbsd_host *host, struct mmc_data *data)
+{
+       /*
+        * Get info. about SG list from data structure.
+        */
+       host->cur_sg = data->sg;
+       host->num_sg = data->sg_len;
+
+       host->offset = 0;
+       host->remain = host->cur_sg->length;
+}
+
+static inline int wbsd_next_sg(struct wbsd_host *host)
+{
+       /*
+        * Skip to next SG entry.
+        */
+       host->cur_sg++;
+       host->num_sg--;
+
+       /*
+        * Any entries left?
+        */
+       if (host->num_sg > 0) {
+               host->offset = 0;
+               host->remain = host->cur_sg->length;
+       }
+
+       return host->num_sg;
+}
+
+static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
+{
+       return page_address(host->cur_sg->page) + host->cur_sg->offset;
+}
+
+static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
+{
+       unsigned int len, i;
+       struct scatterlist *sg;
+       char *dmabuf = host->dma_buffer;
+       char *sgbuf;
+
+       sg = data->sg;
+       len = data->sg_len;
+
+       for (i = 0; i < len; i++) {
+               sgbuf = page_address(sg[i].page) + sg[i].offset;
+               memcpy(dmabuf, sgbuf, sg[i].length);
+               dmabuf += sg[i].length;
+       }
+}
+
+static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
+{
+       unsigned int len, i;
+       struct scatterlist *sg;
+       char *dmabuf = host->dma_buffer;
+       char *sgbuf;
+
+       sg = data->sg;
+       len = data->sg_len;
+
+       for (i = 0; i < len; i++) {
+               sgbuf = page_address(sg[i].page) + sg[i].offset;
+               memcpy(sgbuf, dmabuf, sg[i].length);
+               dmabuf += sg[i].length;
+       }
+}
+
+/*
+ * Command handling
+ */
+
+static inline void wbsd_get_short_reply(struct wbsd_host *host,
+                                       struct mmc_command *cmd)
+{
+       /*
+        * Correct response type?
+        */
+       if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) {
+               cmd->error = MMC_ERR_INVALID;
+               return;
+       }
+
+       cmd->resp[0]  = wbsd_read_index(host, WBSD_IDX_RESP12) << 24;
+       cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP13) << 16;
+       cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP14) << 8;
+       cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP15) << 0;
+       cmd->resp[1]  = wbsd_read_index(host, WBSD_IDX_RESP16) << 24;
+}
+
+static inline void wbsd_get_long_reply(struct wbsd_host *host,
+       struct mmc_command *cmd)
+{
+       int i;
+
+       /*
+        * Correct response type?
+        */
+       if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) {
+               cmd->error = MMC_ERR_INVALID;
+               return;
+       }
+
+       for (i = 0; i < 4; i++) {
+               cmd->resp[i] =
+                       wbsd_read_index(host, WBSD_IDX_RESP1 + i * 4) << 24;
+               cmd->resp[i] |=
+                       wbsd_read_index(host, WBSD_IDX_RESP2 + i * 4) << 16;
+               cmd->resp[i] |=
+                       wbsd_read_index(host, WBSD_IDX_RESP3 + i * 4) << 8;
+               cmd->resp[i] |=
+                       wbsd_read_index(host, WBSD_IDX_RESP4 + i * 4) << 0;
+       }
+}
+
+static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
+{
+       int i;
+       u8 status, isr;
+
+       DBGF("Sending cmd (%x)\n", cmd->opcode);
+
+       /*
+        * Clear accumulated ISR. The interrupt routine
+        * will fill this one with events that occur during
+        * transfer.
+        */
+       host->isr = 0;
+
+       /*
+        * Send the command (CRC calculated by host).
+        */
+       outb(cmd->opcode, host->base + WBSD_CMDR);
+       for (i = 3; i >= 0; i--)
+               outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR);
+
+       cmd->error = MMC_ERR_NONE;
+
+       /*
+        * Wait for the request to complete.
+        */
+       do {
+               status = wbsd_read_index(host, WBSD_IDX_STATUS);
+       } while (status & WBSD_CARDTRAFFIC);
+
+       /*
+        * Do we expect a reply?
+        */
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               /*
+                * Read back status.
+                */
+               isr = host->isr;
+
+               /* Card removed? */
+               if (isr & WBSD_INT_CARD)
+                       cmd->error = MMC_ERR_TIMEOUT;
+               /* Timeout? */
+               else if (isr & WBSD_INT_TIMEOUT)
+                       cmd->error = MMC_ERR_TIMEOUT;
+               /* CRC? */
+               else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC))
+                       cmd->error = MMC_ERR_BADCRC;
+               /* All ok */
+               else {
+                       if (cmd->flags & MMC_RSP_136)
+                               wbsd_get_long_reply(host, cmd);
+                       else
+                               wbsd_get_short_reply(host, cmd);
+               }
+       }
+
+       DBGF("Sent cmd (%x), res %d\n", cmd->opcode, cmd->error);
+}
+
+/*
+ * Data functions
+ */
+
+static void wbsd_empty_fifo(struct wbsd_host *host)
+{
+       struct mmc_data *data = host->mrq->cmd->data;
+       char *buffer;
+       int i, fsr, fifo;
+
+       /*
+        * Handle excessive data.
+        */
+       if (host->num_sg == 0)
+               return;
+
+       buffer = wbsd_sg_to_buffer(host) + host->offset;
+
+       /*
+        * Drain the fifo. This has a tendency to loop longer
+        * than the FIFO length (usually one block).
+        */
+       while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY)) {
+               /*
+                * The size field in the FSR is broken so we have to
+                * do some guessing.
+                */
+               if (fsr & WBSD_FIFO_FULL)
+                       fifo = 16;
+               else if (fsr & WBSD_FIFO_FUTHRE)
+                       fifo = 8;
+               else
+                       fifo = 1;
+
+               for (i = 0; i < fifo; i++) {
+                       *buffer = inb(host->base + WBSD_DFR);
+                       buffer++;
+                       host->offset++;
+                       host->remain--;
+
+                       data->bytes_xfered++;
+
+                       /*
+                        * End of scatter list entry?
+                        */
+                       if (host->remain == 0) {
+                               /*
+                                * Get next entry. Check if last.
+                                */
+                               if (!wbsd_next_sg(host))
+                                       return;
+
+                               buffer = wbsd_sg_to_buffer(host);
+                       }
+               }
+       }
+
+       /*
+        * This is a very dirty hack to solve a
+        * hardware problem. The chip doesn't trigger
+        * FIFO threshold interrupts properly.
+        */
+       if ((data->blocks * data->blksz - data->bytes_xfered) < 16)
+               tasklet_schedule(&host->fifo_tasklet);
+}
+
+static void wbsd_fill_fifo(struct wbsd_host *host)
+{
+       struct mmc_data *data = host->mrq->cmd->data;
+       char *buffer;
+       int i, fsr, fifo;
+
+       /*
+        * Check that we aren't being called after the
+        * entire buffer has been transfered.
+        */
+       if (host->num_sg == 0)
+               return;
+
+       buffer = wbsd_sg_to_buffer(host) + host->offset;
+
+       /*
+        * Fill the fifo. This has a tendency to loop longer
+        * than the FIFO length (usually one block).
+        */
+       while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL)) {
+               /*
+                * The size field in the FSR is broken so we have to
+                * do some guessing.
+                */
+               if (fsr & WBSD_FIFO_EMPTY)
+                       fifo = 0;
+               else if (fsr & WBSD_FIFO_EMTHRE)
+                       fifo = 8;
+               else
+                       fifo = 15;
+
+               for (i = 16; i > fifo; i--) {
+                       outb(*buffer, host->base + WBSD_DFR);
+                       buffer++;
+                       host->offset++;
+                       host->remain--;
+
+                       data->bytes_xfered++;
+
+                       /*
+                        * End of scatter list entry?
+                        */
+                       if (host->remain == 0) {
+                               /*
+                                * Get next entry. Check if last.
+                                */
+                               if (!wbsd_next_sg(host))
+                                       return;
+
+                               buffer = wbsd_sg_to_buffer(host);
+                       }
+               }
+       }
+
+       /*
+        * The controller stops sending interrupts for
+        * 'FIFO empty' under certain conditions. So we
+        * need to be a bit more pro-active.
+        */
+       tasklet_schedule(&host->fifo_tasklet);
+}
+
+static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
+{
+       u16 blksize;
+       u8 setup;
+       unsigned long dmaflags;
+       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.
+        */
+       size = data->blocks * data->blksz;
+
+       /*
+        * Check timeout values for overflow.
+        * (Yes, some cards cause this value to overflow).
+        */
+       if (data->timeout_ns > 127000000)
+               wbsd_write_index(host, WBSD_IDX_TAAC, 127);
+       else {
+               wbsd_write_index(host, WBSD_IDX_TAAC,
+                       data->timeout_ns / 1000000);
+       }
+
+       if (data->timeout_clks > 255)
+               wbsd_write_index(host, WBSD_IDX_NSAC, 255);
+       else
+               wbsd_write_index(host, WBSD_IDX_NSAC, data->timeout_clks);
+
+       /*
+        * Inform the chip of how large blocks will be
+        * sent. It needs this to determine when to
+        * calculate CRC.
+        *
+        * Space for CRC must be included in the size.
+        * Two bytes are needed for each data line.
+        */
+       if (host->bus_width == MMC_BUS_WIDTH_1) {
+               blksize = data->blksz + 2;
+
+               wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
+               wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+       } else if (host->bus_width == MMC_BUS_WIDTH_4) {
+               blksize = data->blksz + 2 * 4;
+
+               wbsd_write_index(host, WBSD_IDX_PBSMSB,
+                       ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH);
+               wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+       } else {
+               data->error = MMC_ERR_INVALID;
+               return;
+       }
+
+       /*
+        * Clear the FIFO. This is needed even for DMA
+        * transfers since the chip still uses the FIFO
+        * internally.
+        */
+       setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+       setup |= WBSD_FIFO_RESET;
+       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+
+       /*
+        * DMA transfer?
+        */
+       if (host->dma >= 0) {
+               /*
+                * The buffer for DMA is only 64 kB.
+                */
+               BUG_ON(size > 0x10000);
+               if (size > 0x10000) {
+                       data->error = MMC_ERR_INVALID;
+                       return;
+               }
+
+               /*
+                * Transfer data from the SG list to
+                * the DMA buffer.
+                */
+               if (data->flags & MMC_DATA_WRITE)
+                       wbsd_sg_to_dma(host, data);
+
+               /*
+                * Initialise the ISA DMA controller.
+                */
+               dmaflags = claim_dma_lock();
+               disable_dma(host->dma);
+               clear_dma_ff(host->dma);
+               if (data->flags & MMC_DATA_READ)
+                       set_dma_mode(host->dma, DMA_MODE_READ & ~0x40);
+               else
+                       set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40);
+               set_dma_addr(host->dma, host->dma_addr);
+               set_dma_count(host->dma, size);
+
+               enable_dma(host->dma);
+               release_dma_lock(dmaflags);
+
+               /*
+                * Enable DMA on the host.
+                */
+               wbsd_write_index(host, WBSD_IDX_DMA, WBSD_DMA_ENABLE);
+       } else {
+               /*
+                * This flag is used to keep printk
+                * output to a minimum.
+                */
+               host->firsterr = 1;
+
+               /*
+                * Initialise the SG list.
+                */
+               wbsd_init_sg(host, data);
+
+               /*
+                * Turn off DMA.
+                */
+               wbsd_write_index(host, WBSD_IDX_DMA, 0);
+
+               /*
+                * Set up FIFO threshold levels (and fill
+                * buffer if doing a write).
+                */
+               if (data->flags & MMC_DATA_READ) {
+                       wbsd_write_index(host, WBSD_IDX_FIFOEN,
+                               WBSD_FIFOEN_FULL | 8);
+               } else {
+                       wbsd_write_index(host, WBSD_IDX_FIFOEN,
+                               WBSD_FIFOEN_EMPTY | 8);
+                       wbsd_fill_fifo(host);
+               }
+       }
+
+       data->error = MMC_ERR_NONE;
+}
+
+static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
+{
+       unsigned long dmaflags;
+       int count;
+       u8 status;
+
+       WARN_ON(host->mrq == NULL);
+
+       /*
+        * Send a stop command if needed.
+        */
+       if (data->stop)
+               wbsd_send_command(host, data->stop);
+
+       /*
+        * Wait for the controller to leave data
+        * transfer state.
+        */
+       do {
+               status = wbsd_read_index(host, WBSD_IDX_STATUS);
+       } while (status & (WBSD_BLOCK_READ | WBSD_BLOCK_WRITE));
+
+       /*
+        * DMA transfer?
+        */
+       if (host->dma >= 0) {
+               /*
+                * Disable DMA on the host.
+                */
+               wbsd_write_index(host, WBSD_IDX_DMA, 0);
+
+               /*
+                * Turn of ISA DMA controller.
+                */
+               dmaflags = claim_dma_lock();
+               disable_dma(host->dma);
+               clear_dma_ff(host->dma);
+               count = get_dma_residue(host->dma);
+               release_dma_lock(dmaflags);
+
+               data->bytes_xfered = host->mrq->data->blocks *
+                       host->mrq->data->blksz - count;
+               data->bytes_xfered -= data->bytes_xfered % data->blksz;
+
+               /*
+                * Any leftover data?
+                */
+               if (count) {
+                       printk(KERN_ERR "%s: Incomplete DMA transfer. "
+                               "%d bytes left.\n",
+                               mmc_hostname(host->mmc), count);
+
+                       if (data->error == MMC_ERR_NONE)
+                               data->error = MMC_ERR_FAILED;
+               } else {
+                       /*
+                        * Transfer data from DMA buffer to
+                        * SG list.
+                        */
+                       if (data->flags & MMC_DATA_READ)
+                               wbsd_dma_to_sg(host, data);
+               }
+
+               if (data->error != MMC_ERR_NONE) {
+                       if (data->bytes_xfered)
+                               data->bytes_xfered -= data->blksz;
+               }
+       }
+
+       DBGF("Ending data transfer (%d bytes)\n", data->bytes_xfered);
+
+       wbsd_request_end(host, host->mrq);
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * MMC layer callbacks                                                       *
+ *                                                                           *
+\*****************************************************************************/
+
+static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct wbsd_host *host = mmc_priv(mmc);
+       struct mmc_command *cmd;
+
+       /*
+        * Disable tasklets to avoid a deadlock.
+        */
+       spin_lock_bh(&host->lock);
+
+       BUG_ON(host->mrq != NULL);
+
+       cmd = mrq->cmd;
+
+       host->mrq = mrq;
+
+       /*
+        * If there is no card in the slot then
+        * timeout immediatly.
+        */
+       if (!(host->flags & WBSD_FCARD_PRESENT)) {
+               cmd->error = MMC_ERR_TIMEOUT;
+               goto done;
+       }
+
+       /*
+        * Does the request include data?
+        */
+       if (cmd->data) {
+               wbsd_prepare_data(host, cmd->data);
+
+               if (cmd->data->error != MMC_ERR_NONE)
+                       goto done;
+       }
+
+       wbsd_send_command(host, cmd);
+
+       /*
+        * If this is a data transfer the request
+        * will be finished after the data has
+        * transfered.
+        */
+       if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
+               /*
+                * The hardware is so delightfully stupid that it has a list
+                * of "data" commands. If a command isn't on this list, it'll
+                * just go back to the idle state and won't send any data
+                * interrupts.
+                */
+               switch (cmd->opcode) {
+               case 11:
+               case 17:
+               case 18:
+               case 20:
+               case 24:
+               case 25:
+               case 26:
+               case 27:
+               case 30:
+               case 42:
+               case 56:
+                       break;
+
+               /* ACMDs. We don't keep track of state, so we just treat them
+                * like any other command. */
+               case 51:
+                       break;
+
+               default:
+#ifdef CONFIG_MMC_DEBUG
+                       printk(KERN_WARNING "%s: Data command %d is not "
+                               "supported by this controller.\n",
+                               mmc_hostname(host->mmc), cmd->opcode);
+#endif
+                       cmd->data->error = MMC_ERR_INVALID;
+
+                       if (cmd->data->stop)
+                               wbsd_send_command(host, cmd->data->stop);
+
+                       goto done;
+               };
+
+               /*
+                * Dirty fix for hardware bug.
+                */
+               if (host->dma == -1)
+                       tasklet_schedule(&host->fifo_tasklet);
+
+               spin_unlock_bh(&host->lock);
+
+               return;
+       }
+
+done:
+       wbsd_request_end(host, mrq);
+
+       spin_unlock_bh(&host->lock);
+}
+
+static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct wbsd_host *host = mmc_priv(mmc);
+       u8 clk, setup, pwr;
+
+       spin_lock_bh(&host->lock);
+
+       /*
+        * Reset the chip on each power off.
+        * Should clear out any weird states.
+        */
+       if (ios->power_mode == MMC_POWER_OFF)
+               wbsd_init_device(host);
+
+       if (ios->clock >= 24000000)
+               clk = WBSD_CLK_24M;
+       else if (ios->clock >= 16000000)
+               clk = WBSD_CLK_16M;
+       else if (ios->clock >= 12000000)
+               clk = WBSD_CLK_12M;
+       else
+               clk = WBSD_CLK_375K;
+
+       /*
+        * Only write to the clock register when
+        * there is an actual change.
+        */
+       if (clk != host->clk) {
+               wbsd_write_index(host, WBSD_IDX_CLK, clk);
+               host->clk = clk;
+       }
+
+       /*
+        * Power up card.
+        */
+       if (ios->power_mode != MMC_POWER_OFF) {
+               pwr = inb(host->base + WBSD_CSR);
+               pwr &= ~WBSD_POWER_N;
+               outb(pwr, host->base + WBSD_CSR);
+       }
+
+       /*
+        * MMC cards need to have pin 1 high during init.
+        * It wreaks havoc with the card detection though so
+        * that needs to be disabled.
+        */
+       setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+       if (ios->chip_select == MMC_CS_HIGH) {
+               BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1);
+               setup |= WBSD_DAT3_H;
+               host->flags |= WBSD_FIGNORE_DETECT;
+       } else {
+               if (setup & WBSD_DAT3_H) {
+                       setup &= ~WBSD_DAT3_H;
+
+                       /*
+                        * We cannot resume card detection immediatly
+                        * because of capacitance and delays in the chip.
+                        */
+                       mod_timer(&host->ignore_timer, jiffies + HZ / 100);
+               }
+       }
+       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+
+       /*
+        * Store bus width for later. Will be used when
+        * setting up the data transfer.
+        */
+       host->bus_width = ios->bus_width;
+
+       spin_unlock_bh(&host->lock);
+}
+
+static int wbsd_get_ro(struct mmc_host *mmc)
+{
+       struct wbsd_host *host = mmc_priv(mmc);
+       u8 csr;
+
+       spin_lock_bh(&host->lock);
+
+       csr = inb(host->base + WBSD_CSR);
+       csr |= WBSD_MSLED;
+       outb(csr, host->base + WBSD_CSR);
+
+       mdelay(1);
+
+       csr = inb(host->base + WBSD_CSR);
+       csr &= ~WBSD_MSLED;
+       outb(csr, host->base + WBSD_CSR);
+
+       spin_unlock_bh(&host->lock);
+
+       return csr & WBSD_WRPT;
+}
+
+static const struct mmc_host_ops wbsd_ops = {
+       .request        = wbsd_request,
+       .set_ios        = wbsd_set_ios,
+       .get_ro         = wbsd_get_ro,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Interrupt handling                                                        *
+ *                                                                           *
+\*****************************************************************************/
+
+/*
+ * Helper function to reset detection ignore
+ */
+
+static void wbsd_reset_ignore(unsigned long data)
+{
+       struct wbsd_host *host = (struct wbsd_host *)data;
+
+       BUG_ON(host == NULL);
+
+       DBG("Resetting card detection ignore\n");
+
+       spin_lock_bh(&host->lock);
+
+       host->flags &= ~WBSD_FIGNORE_DETECT;
+
+       /*
+        * Card status might have changed during the
+        * blackout.
+        */
+       tasklet_schedule(&host->card_tasklet);
+
+       spin_unlock_bh(&host->lock);
+}
+
+/*
+ * Tasklets
+ */
+
+static inline struct mmc_data *wbsd_get_data(struct wbsd_host *host)
+{
+       WARN_ON(!host->mrq);
+       if (!host->mrq)
+               return NULL;
+
+       WARN_ON(!host->mrq->cmd);
+       if (!host->mrq->cmd)
+               return NULL;
+
+       WARN_ON(!host->mrq->cmd->data);
+       if (!host->mrq->cmd->data)
+               return NULL;
+
+       return host->mrq->cmd->data;
+}
+
+static void wbsd_tasklet_card(unsigned long param)
+{
+       struct wbsd_host *host = (struct wbsd_host *)param;
+       u8 csr;
+       int delay = -1;
+
+       spin_lock(&host->lock);
+
+       if (host->flags & WBSD_FIGNORE_DETECT) {
+               spin_unlock(&host->lock);
+               return;
+       }
+
+       csr = inb(host->base + WBSD_CSR);
+       WARN_ON(csr == 0xff);
+
+       if (csr & WBSD_CARDPRESENT) {
+               if (!(host->flags & WBSD_FCARD_PRESENT)) {
+                       DBG("Card inserted\n");
+                       host->flags |= WBSD_FCARD_PRESENT;
+
+                       delay = 500;
+               }
+       } else if (host->flags & WBSD_FCARD_PRESENT) {
+               DBG("Card removed\n");
+               host->flags &= ~WBSD_FCARD_PRESENT;
+
+               if (host->mrq) {
+                       printk(KERN_ERR "%s: Card removed during transfer!\n",
+                               mmc_hostname(host->mmc));
+                       wbsd_reset(host);
+
+                       host->mrq->cmd->error = MMC_ERR_FAILED;
+                       tasklet_schedule(&host->finish_tasklet);
+               }
+
+               delay = 0;
+       }
+
+       /*
+        * Unlock first since we might get a call back.
+        */
+
+       spin_unlock(&host->lock);
+
+       if (delay != -1)
+               mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
+}
+
+static void wbsd_tasklet_fifo(unsigned long param)
+{
+       struct wbsd_host *host = (struct wbsd_host *)param;
+       struct mmc_data *data;
+
+       spin_lock(&host->lock);
+
+       if (!host->mrq)
+               goto end;
+
+       data = wbsd_get_data(host);
+       if (!data)
+               goto end;
+
+       if (data->flags & MMC_DATA_WRITE)
+               wbsd_fill_fifo(host);
+       else
+               wbsd_empty_fifo(host);
+
+       /*
+        * Done?
+        */
+       if (host->num_sg == 0) {
+               wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
+               tasklet_schedule(&host->finish_tasklet);
+       }
+
+end:
+       spin_unlock(&host->lock);
+}
+
+static void wbsd_tasklet_crc(unsigned long param)
+{
+       struct wbsd_host *host = (struct wbsd_host *)param;
+       struct mmc_data *data;
+
+       spin_lock(&host->lock);
+
+       if (!host->mrq)
+               goto end;
+
+       data = wbsd_get_data(host);
+       if (!data)
+               goto end;
+
+       DBGF("CRC error\n");
+
+       data->error = MMC_ERR_BADCRC;
+
+       tasklet_schedule(&host->finish_tasklet);
+
+end:
+       spin_unlock(&host->lock);
+}
+
+static void wbsd_tasklet_timeout(unsigned long param)
+{
+       struct wbsd_host *host = (struct wbsd_host *)param;
+       struct mmc_data *data;
+
+       spin_lock(&host->lock);
+
+       if (!host->mrq)
+               goto end;
+
+       data = wbsd_get_data(host);
+       if (!data)
+               goto end;
+
+       DBGF("Timeout\n");
+
+       data->error = MMC_ERR_TIMEOUT;
+
+       tasklet_schedule(&host->finish_tasklet);
+
+end:
+       spin_unlock(&host->lock);
+}
+
+static void wbsd_tasklet_finish(unsigned long param)
+{
+       struct wbsd_host *host = (struct wbsd_host *)param;
+       struct mmc_data *data;
+
+       spin_lock(&host->lock);
+
+       WARN_ON(!host->mrq);
+       if (!host->mrq)
+               goto end;
+
+       data = wbsd_get_data(host);
+       if (!data)
+               goto end;
+
+       wbsd_finish_data(host, data);
+
+end:
+       spin_unlock(&host->lock);
+}
+
+/*
+ * Interrupt handling
+ */
+
+static irqreturn_t wbsd_irq(int irq, void *dev_id)
+{
+       struct wbsd_host *host = dev_id;
+       int isr;
+
+       isr = inb(host->base + WBSD_ISR);
+
+       /*
+        * Was it actually our hardware that caused the interrupt?
+        */
+       if (isr == 0xff || isr == 0x00)
+               return IRQ_NONE;
+
+       host->isr |= isr;
+
+       /*
+        * Schedule tasklets as needed.
+        */
+       if (isr & WBSD_INT_CARD)
+               tasklet_schedule(&host->card_tasklet);
+       if (isr & WBSD_INT_FIFO_THRE)
+               tasklet_schedule(&host->fifo_tasklet);
+       if (isr & WBSD_INT_CRC)
+               tasklet_hi_schedule(&host->crc_tasklet);
+       if (isr & WBSD_INT_TIMEOUT)
+               tasklet_hi_schedule(&host->timeout_tasklet);
+       if (isr & WBSD_INT_TC)
+               tasklet_schedule(&host->finish_tasklet);
+
+       return IRQ_HANDLED;
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Device initialisation and shutdown                                        *
+ *                                                                           *
+\*****************************************************************************/
+
+/*
+ * Allocate/free MMC structure.
+ */
+
+static int __devinit wbsd_alloc_mmc(struct device *dev)
+{
+       struct mmc_host *mmc;
+       struct wbsd_host *host;
+
+       /*
+        * Allocate MMC structure.
+        */
+       mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
+       if (!mmc)
+               return -ENOMEM;
+
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+
+       host->dma = -1;
+
+       /*
+        * Set host parameters.
+        */
+       mmc->ops = &wbsd_ops;
+       mmc->f_min = 375000;
+       mmc->f_max = 24000000;
+       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+
+       spin_lock_init(&host->lock);
+
+       /*
+        * Set up timers
+        */
+       init_timer(&host->ignore_timer);
+       host->ignore_timer.data = (unsigned long)host;
+       host->ignore_timer.function = wbsd_reset_ignore;
+
+       /*
+        * Maximum number of segments. Worst case is one sector per segment
+        * so this will be 64kB/512.
+        */
+       mmc->max_hw_segs = 128;
+       mmc->max_phys_segs = 128;
+
+       /*
+        * Maximum request size. Also limited by 64KiB buffer.
+        */
+       mmc->max_req_size = 65536;
+
+       /*
+        * Maximum segment size. Could be one segment with the maximum number
+        * of bytes.
+        */
+       mmc->max_seg_size = mmc->max_req_size;
+
+       /*
+        * Maximum block size. We have 12 bits (= 4095) but have to subtract
+        * space for CRC. So the maximum is 4095 - 4*2 = 4087.
+        */
+       mmc->max_blk_size = 4087;
+
+       /*
+        * Maximum block count. There is no real limit so the maximum
+        * request size will be the only restriction.
+        */
+       mmc->max_blk_count = mmc->max_req_size;
+
+       dev_set_drvdata(dev, mmc);
+
+       return 0;
+}
+
+static void __devexit wbsd_free_mmc(struct device *dev)
+{
+       struct mmc_host *mmc;
+       struct wbsd_host *host;
+
+       mmc = dev_get_drvdata(dev);
+       if (!mmc)
+               return;
+
+       host = mmc_priv(mmc);
+       BUG_ON(host == NULL);
+
+       del_timer_sync(&host->ignore_timer);
+
+       mmc_free_host(mmc);
+
+       dev_set_drvdata(dev, NULL);
+}
+
+/*
+ * Scan for known chip id:s
+ */
+
+static int __devinit wbsd_scan(struct wbsd_host *host)
+{
+       int i, j, k;
+       int id;
+
+       /*
+        * Iterate through all ports, all codes to
+        * find hardware that is in our known list.
+        */
+       for (i = 0; i < ARRAY_SIZE(config_ports); i++) {
+               if (!request_region(config_ports[i], 2, DRIVER_NAME))
+                       continue;
+
+               for (j = 0; j < ARRAY_SIZE(unlock_codes); j++) {
+                       id = 0xFFFF;
+
+                       host->config = config_ports[i];
+                       host->unlock_code = unlock_codes[j];
+
+                       wbsd_unlock_config(host);
+
+                       outb(WBSD_CONF_ID_HI, config_ports[i]);
+                       id = inb(config_ports[i] + 1) << 8;
+
+                       outb(WBSD_CONF_ID_LO, config_ports[i]);
+                       id |= inb(config_ports[i] + 1);
+
+                       wbsd_lock_config(host);
+
+                       for (k = 0; k < ARRAY_SIZE(valid_ids); k++) {
+                               if (id == valid_ids[k]) {
+                                       host->chip_id = id;
+
+                                       return 0;
+                               }
+                       }
+
+                       if (id != 0xFFFF) {
+                               DBG("Unknown hardware (id %x) found at %x\n",
+                                       id, config_ports[i]);
+                       }
+               }
+
+               release_region(config_ports[i], 2);
+       }
+
+       host->config = 0;
+       host->unlock_code = 0;
+
+       return -ENODEV;
+}
+
+/*
+ * Allocate/free io port ranges
+ */
+
+static int __devinit wbsd_request_region(struct wbsd_host *host, int base)
+{
+       if (base & 0x7)
+               return -EINVAL;
+
+       if (!request_region(base, 8, DRIVER_NAME))
+               return -EIO;
+
+       host->base = base;
+
+       return 0;
+}
+
+static void __devexit wbsd_release_regions(struct wbsd_host *host)
+{
+       if (host->base)
+               release_region(host->base, 8);
+
+       host->base = 0;
+
+       if (host->config)
+               release_region(host->config, 2);
+
+       host->config = 0;
+}
+
+/*
+ * Allocate/free DMA port and buffer
+ */
+
+static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma)
+{
+       if (dma < 0)
+               return;
+
+       if (request_dma(dma, DRIVER_NAME))
+               goto err;
+
+       /*
+        * We need to allocate a special buffer in
+        * order for ISA to be able to DMA to it.
+        */
+       host->dma_buffer = kmalloc(WBSD_DMA_SIZE,
+               GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN);
+       if (!host->dma_buffer)
+               goto free;
+
+       /*
+        * Translate the address to a physical address.
+        */
+       host->dma_addr = dma_map_single(mmc_dev(host->mmc), host->dma_buffer,
+               WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
+
+       /*
+        * ISA DMA must be aligned on a 64k basis.
+        */
+       if ((host->dma_addr & 0xffff) != 0)
+               goto kfree;
+       /*
+        * ISA cannot access memory above 16 MB.
+        */
+       else if (host->dma_addr >= 0x1000000)
+               goto kfree;
+
+       host->dma = dma;
+
+       return;
+
+kfree:
+       /*
+        * If we've gotten here then there is some kind of alignment bug
+        */
+       BUG_ON(1);
+
+       dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
+               WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
+       host->dma_addr = (dma_addr_t)NULL;
+
+       kfree(host->dma_buffer);
+       host->dma_buffer = NULL;
+
+free:
+       free_dma(dma);
+
+err:
+       printk(KERN_WARNING DRIVER_NAME ": Unable to allocate DMA %d. "
+               "Falling back on FIFO.\n", dma);
+}
+
+static void __devexit wbsd_release_dma(struct wbsd_host *host)
+{
+       if (host->dma_addr) {
+               dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
+                       WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
+       }
+       kfree(host->dma_buffer);
+       if (host->dma >= 0)
+               free_dma(host->dma);
+
+       host->dma = -1;
+       host->dma_buffer = NULL;
+       host->dma_addr = (dma_addr_t)NULL;
+}
+
+/*
+ * Allocate/free IRQ.
+ */
+
+static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
+{
+       int ret;
+
+       /*
+        * Allocate interrupt.
+        */
+
+       ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
+       if (ret)
+               return ret;
+
+       host->irq = irq;
+
+       /*
+        * Set up tasklets.
+        */
+       tasklet_init(&host->card_tasklet, wbsd_tasklet_card,
+                       (unsigned long)host);
+       tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo,
+                       (unsigned long)host);
+       tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc,
+                       (unsigned long)host);
+       tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout,
+                       (unsigned long)host);
+       tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,
+                       (unsigned long)host);
+
+       return 0;
+}
+
+static void __devexit wbsd_release_irq(struct wbsd_host *host)
+{
+       if (!host->irq)
+               return;
+
+       free_irq(host->irq, host);
+
+       host->irq = 0;
+
+       tasklet_kill(&host->card_tasklet);
+       tasklet_kill(&host->fifo_tasklet);
+       tasklet_kill(&host->crc_tasklet);
+       tasklet_kill(&host->timeout_tasklet);
+       tasklet_kill(&host->finish_tasklet);
+}
+
+/*
+ * Allocate all resources for the host.
+ */
+
+static int __devinit wbsd_request_resources(struct wbsd_host *host,
+       int base, int irq, int dma)
+{
+       int ret;
+
+       /*
+        * Allocate I/O ports.
+        */
+       ret = wbsd_request_region(host, base);
+       if (ret)
+               return ret;
+
+       /*
+        * Allocate interrupt.
+        */
+       ret = wbsd_request_irq(host, irq);
+       if (ret)
+               return ret;
+
+       /*
+        * Allocate DMA.
+        */
+       wbsd_request_dma(host, dma);
+
+       return 0;
+}
+
+/*
+ * Release all resources for the host.
+ */
+
+static void __devexit wbsd_release_resources(struct wbsd_host *host)
+{
+       wbsd_release_dma(host);
+       wbsd_release_irq(host);
+       wbsd_release_regions(host);
+}
+
+/*
+ * Configure the resources the chip should use.
+ */
+
+static void wbsd_chip_config(struct wbsd_host *host)
+{
+       wbsd_unlock_config(host);
+
+       /*
+        * Reset the chip.
+        */
+       wbsd_write_config(host, WBSD_CONF_SWRST, 1);
+       wbsd_write_config(host, WBSD_CONF_SWRST, 0);
+
+       /*
+        * Select SD/MMC function.
+        */
+       wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
+
+       /*
+        * Set up card detection.
+        */
+       wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11);
+
+       /*
+        * Configure chip
+        */
+       wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8);
+       wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff);
+
+       wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
+
+       if (host->dma >= 0)
+               wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
+
+       /*
+        * Enable and power up chip.
+        */
+       wbsd_write_config(host, WBSD_CONF_ENABLE, 1);
+       wbsd_write_config(host, WBSD_CONF_POWER, 0x20);
+
+       wbsd_lock_config(host);
+}
+
+/*
+ * Check that configured resources are correct.
+ */
+
+static int wbsd_chip_validate(struct wbsd_host *host)
+{
+       int base, irq, dma;
+
+       wbsd_unlock_config(host);
+
+       /*
+        * Select SD/MMC function.
+        */
+       wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
+
+       /*
+        * Read configuration.
+        */
+       base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8;
+       base |= wbsd_read_config(host, WBSD_CONF_PORT_LO);
+
+       irq = wbsd_read_config(host, WBSD_CONF_IRQ);
+
+       dma = wbsd_read_config(host, WBSD_CONF_DRQ);
+
+       wbsd_lock_config(host);
+
+       /*
+        * Validate against given configuration.
+        */
+       if (base != host->base)
+               return 0;
+       if (irq != host->irq)
+               return 0;
+       if ((dma != host->dma) && (host->dma != -1))
+               return 0;
+
+       return 1;
+}
+
+/*
+ * Powers down the SD function
+ */
+
+static void wbsd_chip_poweroff(struct wbsd_host *host)
+{
+       wbsd_unlock_config(host);
+
+       wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
+       wbsd_write_config(host, WBSD_CONF_ENABLE, 0);
+
+       wbsd_lock_config(host);
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Devices setup and shutdown                                                *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma,
+       int pnp)
+{
+       struct wbsd_host *host = NULL;
+       struct mmc_host *mmc = NULL;
+       int ret;
+
+       ret = wbsd_alloc_mmc(dev);
+       if (ret)
+               return ret;
+
+       mmc = dev_get_drvdata(dev);
+       host = mmc_priv(mmc);
+
+       /*
+        * Scan for hardware.
+        */
+       ret = wbsd_scan(host);
+       if (ret) {
+               if (pnp && (ret == -ENODEV)) {
+                       printk(KERN_WARNING DRIVER_NAME
+                               ": Unable to confirm device presence. You may "
+                               "experience lock-ups.\n");
+               } else {
+                       wbsd_free_mmc(dev);
+                       return ret;
+               }
+       }
+
+       /*
+        * Request resources.
+        */
+       ret = wbsd_request_resources(host, base, irq, dma);
+       if (ret) {
+               wbsd_release_resources(host);
+               wbsd_free_mmc(dev);
+               return ret;
+       }
+
+       /*
+        * See if chip needs to be configured.
+        */
+       if (pnp) {
+               if ((host->config != 0) && !wbsd_chip_validate(host)) {
+                       printk(KERN_WARNING DRIVER_NAME
+                               ": PnP active but chip not configured! "
+                               "You probably have a buggy BIOS. "
+                               "Configuring chip manually.\n");
+                       wbsd_chip_config(host);
+               }
+       } else
+               wbsd_chip_config(host);
+
+       /*
+        * Power Management stuff. No idea how this works.
+        * Not tested.
+        */
+#ifdef CONFIG_PM
+       if (host->config) {
+               wbsd_unlock_config(host);
+               wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
+               wbsd_lock_config(host);
+       }
+#endif
+       /*
+        * Allow device to initialise itself properly.
+        */
+       mdelay(5);
+
+       /*
+        * Reset the chip into a known state.
+        */
+       wbsd_init_device(host);
+
+       mmc_add_host(mmc);
+
+       printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc));
+       if (host->chip_id != 0)
+               printk(" id %x", (int)host->chip_id);
+       printk(" at 0x%x irq %d", (int)host->base, (int)host->irq);
+       if (host->dma >= 0)
+               printk(" dma %d", (int)host->dma);
+       else
+               printk(" FIFO");
+       if (pnp)
+               printk(" PnP");
+       printk("\n");
+
+       return 0;
+}
+
+static void __devexit wbsd_shutdown(struct device *dev, int pnp)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct wbsd_host *host;
+
+       if (!mmc)
+               return;
+
+       host = mmc_priv(mmc);
+
+       mmc_remove_host(mmc);
+
+       /*
+        * Power down the SD/MMC function.
+        */
+       if (!pnp)
+               wbsd_chip_poweroff(host);
+
+       wbsd_release_resources(host);
+
+       wbsd_free_mmc(dev);
+}
+
+/*
+ * Non-PnP
+ */
+
+static int __devinit wbsd_probe(struct platform_device *dev)
+{
+       /* Use the module parameters for resources */
+       return wbsd_init(&dev->dev, io, irq, dma, 0);
+}
+
+static int __devexit wbsd_remove(struct platform_device *dev)
+{
+       wbsd_shutdown(&dev->dev, 0);
+
+       return 0;
+}
+
+/*
+ * PnP
+ */
+
+#ifdef CONFIG_PNP
+
+static int __devinit
+wbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id)
+{
+       int io, irq, dma;
+
+       /*
+        * Get resources from PnP layer.
+        */
+       io = pnp_port_start(pnpdev, 0);
+       irq = pnp_irq(pnpdev, 0);
+       if (pnp_dma_valid(pnpdev, 0))
+               dma = pnp_dma(pnpdev, 0);
+       else
+               dma = -1;
+
+       DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma);
+
+       return wbsd_init(&pnpdev->dev, io, irq, dma, 1);
+}
+
+static void __devexit wbsd_pnp_remove(struct pnp_dev *dev)
+{
+       wbsd_shutdown(&dev->dev, 1);
+}
+
+#endif /* CONFIG_PNP */
+
+/*
+ * Power management
+ */
+
+#ifdef CONFIG_PM
+
+static int wbsd_suspend(struct wbsd_host *host, pm_message_t state)
+{
+       BUG_ON(host == NULL);
+
+       return mmc_suspend_host(host->mmc, state);
+}
+
+static int wbsd_resume(struct wbsd_host *host)
+{
+       BUG_ON(host == NULL);
+
+       wbsd_init_device(host);
+
+       return mmc_resume_host(host->mmc);
+}
+
+static int wbsd_platform_suspend(struct platform_device *dev,
+                                pm_message_t state)
+{
+       struct mmc_host *mmc = platform_get_drvdata(dev);
+       struct wbsd_host *host;
+       int ret;
+
+       if (mmc == NULL)
+               return 0;
+
+       DBGF("Suspending...\n");
+
+       host = mmc_priv(mmc);
+
+       ret = wbsd_suspend(host, state);
+       if (ret)
+               return ret;
+
+       wbsd_chip_poweroff(host);
+
+       return 0;
+}
+
+static int wbsd_platform_resume(struct platform_device *dev)
+{
+       struct mmc_host *mmc = platform_get_drvdata(dev);
+       struct wbsd_host *host;
+
+       if (mmc == NULL)
+               return 0;
+
+       DBGF("Resuming...\n");
+
+       host = mmc_priv(mmc);
+
+       wbsd_chip_config(host);
+
+       /*
+        * Allow device to initialise itself properly.
+        */
+       mdelay(5);
+
+       return wbsd_resume(host);
+}
+
+#ifdef CONFIG_PNP
+
+static int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
+{
+       struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
+       struct wbsd_host *host;
+
+       if (mmc == NULL)
+               return 0;
+
+       DBGF("Suspending...\n");
+
+       host = mmc_priv(mmc);
+
+       return wbsd_suspend(host, state);
+}
+
+static int wbsd_pnp_resume(struct pnp_dev *pnp_dev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
+       struct wbsd_host *host;
+
+       if (mmc == NULL)
+               return 0;
+
+       DBGF("Resuming...\n");
+
+       host = mmc_priv(mmc);
+
+       /*
+        * See if chip needs to be configured.
+        */
+       if (host->config != 0) {
+               if (!wbsd_chip_validate(host)) {
+                       printk(KERN_WARNING DRIVER_NAME
+                               ": PnP active but chip not configured! "
+                               "You probably have a buggy BIOS. "
+                               "Configuring chip manually.\n");
+                       wbsd_chip_config(host);
+               }
+       }
+
+       /*
+        * Allow device to initialise itself properly.
+        */
+       mdelay(5);
+
+       return wbsd_resume(host);
+}
+
+#endif /* CONFIG_PNP */
+
+#else /* CONFIG_PM */
+
+#define wbsd_platform_suspend NULL
+#define wbsd_platform_resume NULL
+
+#define wbsd_pnp_suspend NULL
+#define wbsd_pnp_resume NULL
+
+#endif /* CONFIG_PM */
+
+static struct platform_device *wbsd_device;
+
+static struct platform_driver wbsd_driver = {
+       .probe          = wbsd_probe,
+       .remove         = __devexit_p(wbsd_remove),
+
+       .suspend        = wbsd_platform_suspend,
+       .resume         = wbsd_platform_resume,
+       .driver         = {
+               .name   = DRIVER_NAME,
+       },
+};
+
+#ifdef CONFIG_PNP
+
+static struct pnp_driver wbsd_pnp_driver = {
+       .name           = DRIVER_NAME,
+       .id_table       = pnp_dev_table,
+       .probe          = wbsd_pnp_probe,
+       .remove         = __devexit_p(wbsd_pnp_remove),
+
+       .suspend        = wbsd_pnp_suspend,
+       .resume         = wbsd_pnp_resume,
+};
+
+#endif /* CONFIG_PNP */
+
+/*
+ * Module loading/unloading
+ */
+
+static int __init wbsd_drv_init(void)
+{
+       int result;
+
+       printk(KERN_INFO DRIVER_NAME
+               ": Winbond W83L51xD SD/MMC card interface driver\n");
+       printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
+
+#ifdef CONFIG_PNP
+
+       if (!nopnp) {
+               result = pnp_register_driver(&wbsd_pnp_driver);
+               if (result < 0)
+                       return result;
+       }
+#endif /* CONFIG_PNP */
+
+       if (nopnp) {
+               result = platform_driver_register(&wbsd_driver);
+               if (result < 0)
+                       return result;
+
+               wbsd_device = platform_device_alloc(DRIVER_NAME, -1);
+               if (!wbsd_device) {
+                       platform_driver_unregister(&wbsd_driver);
+                       return -ENOMEM;
+               }
+
+               result = platform_device_add(wbsd_device);
+               if (result) {
+                       platform_device_put(wbsd_device);
+                       platform_driver_unregister(&wbsd_driver);
+                       return result;
+               }
+       }
+
+       return 0;
+}
+
+static void __exit wbsd_drv_exit(void)
+{
+#ifdef CONFIG_PNP
+
+       if (!nopnp)
+               pnp_unregister_driver(&wbsd_pnp_driver);
+
+#endif /* CONFIG_PNP */
+
+       if (nopnp) {
+               platform_device_unregister(wbsd_device);
+
+               platform_driver_unregister(&wbsd_driver);
+       }
+
+       DBG("unloaded\n");
+}
+
+module_init(wbsd_drv_init);
+module_exit(wbsd_drv_exit);
+#ifdef CONFIG_PNP
+module_param(nopnp, uint, 0444);
+#endif
+module_param(io, uint, 0444);
+module_param(irq, uint, 0444);
+module_param(dma, int, 0444);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
+MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
+
+#ifdef CONFIG_PNP
+MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)");
+#endif
+MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)");
+MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)");
+MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)");
diff --git a/drivers/mmc/host/wbsd.h b/drivers/mmc/host/wbsd.h
new file mode 100644 (file)
index 0000000..873bda1
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ *  linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver
+ *
+ *  Copyright (C) 2004-2007 Pierre Ossman, 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#define LOCK_CODE              0xAA
+
+#define WBSD_CONF_SWRST                0x02
+#define WBSD_CONF_DEVICE       0x07
+#define WBSD_CONF_ID_HI                0x20
+#define WBSD_CONF_ID_LO                0x21
+#define WBSD_CONF_POWER                0x22
+#define WBSD_CONF_PME          0x23
+#define WBSD_CONF_PMES         0x24
+
+#define WBSD_CONF_ENABLE       0x30
+#define WBSD_CONF_PORT_HI      0x60
+#define WBSD_CONF_PORT_LO      0x61
+#define WBSD_CONF_IRQ          0x70
+#define WBSD_CONF_DRQ          0x74
+
+#define WBSD_CONF_PINS         0xF0
+
+#define DEVICE_SD              0x03
+
+#define WBSD_PINS_DAT3_HI      0x20
+#define WBSD_PINS_DAT3_OUT     0x10
+#define WBSD_PINS_GP11_HI      0x04
+#define WBSD_PINS_DETECT_GP11  0x02
+#define WBSD_PINS_DETECT_DAT3  0x01
+
+#define WBSD_CMDR              0x00
+#define WBSD_DFR               0x01
+#define WBSD_EIR               0x02
+#define WBSD_ISR               0x03
+#define WBSD_FSR               0x04
+#define WBSD_IDXR              0x05
+#define WBSD_DATAR             0x06
+#define WBSD_CSR               0x07
+
+#define WBSD_EINT_CARD         0x40
+#define WBSD_EINT_FIFO_THRE    0x20
+#define WBSD_EINT_CRC          0x10
+#define WBSD_EINT_TIMEOUT      0x08
+#define WBSD_EINT_PROGEND      0x04
+#define WBSD_EINT_BUSYEND      0x02
+#define WBSD_EINT_TC           0x01
+
+#define WBSD_INT_PENDING       0x80
+#define WBSD_INT_CARD          0x40
+#define WBSD_INT_FIFO_THRE     0x20
+#define WBSD_INT_CRC           0x10
+#define WBSD_INT_TIMEOUT       0x08
+#define WBSD_INT_PROGEND       0x04
+#define WBSD_INT_BUSYEND       0x02
+#define WBSD_INT_TC            0x01
+
+#define WBSD_FIFO_EMPTY                0x80
+#define WBSD_FIFO_FULL         0x40
+#define WBSD_FIFO_EMTHRE       0x20
+#define WBSD_FIFO_FUTHRE       0x10
+#define WBSD_FIFO_SZMASK       0x0F
+
+#define WBSD_MSLED             0x20
+#define WBSD_POWER_N           0x10
+#define WBSD_WRPT              0x04
+#define WBSD_CARDPRESENT       0x01
+
+#define WBSD_IDX_CLK           0x01
+#define WBSD_IDX_PBSMSB                0x02
+#define WBSD_IDX_TAAC          0x03
+#define WBSD_IDX_NSAC          0x04
+#define WBSD_IDX_PBSLSB                0x05
+#define WBSD_IDX_SETUP         0x06
+#define WBSD_IDX_DMA           0x07
+#define WBSD_IDX_FIFOEN                0x08
+#define WBSD_IDX_STATUS                0x10
+#define WBSD_IDX_RSPLEN                0x1E
+#define WBSD_IDX_RESP0         0x1F
+#define WBSD_IDX_RESP1         0x20
+#define WBSD_IDX_RESP2         0x21
+#define WBSD_IDX_RESP3         0x22
+#define WBSD_IDX_RESP4         0x23
+#define WBSD_IDX_RESP5         0x24
+#define WBSD_IDX_RESP6         0x25
+#define WBSD_IDX_RESP7         0x26
+#define WBSD_IDX_RESP8         0x27
+#define WBSD_IDX_RESP9         0x28
+#define WBSD_IDX_RESP10                0x29
+#define WBSD_IDX_RESP11                0x2A
+#define WBSD_IDX_RESP12                0x2B
+#define WBSD_IDX_RESP13                0x2C
+#define WBSD_IDX_RESP14                0x2D
+#define WBSD_IDX_RESP15                0x2E
+#define WBSD_IDX_RESP16                0x2F
+#define WBSD_IDX_CRCSTATUS     0x30
+#define WBSD_IDX_ISR           0x3F
+
+#define WBSD_CLK_375K          0x00
+#define WBSD_CLK_12M           0x01
+#define WBSD_CLK_16M           0x02
+#define WBSD_CLK_24M           0x03
+
+#define WBSD_DATA_WIDTH                0x01
+
+#define WBSD_DAT3_H            0x08
+#define WBSD_FIFO_RESET                0x04
+#define WBSD_SOFT_RESET                0x02
+#define WBSD_INC_INDEX         0x01
+
+#define WBSD_DMA_SINGLE                0x02
+#define WBSD_DMA_ENABLE                0x01
+
+#define WBSD_FIFOEN_EMPTY      0x20
+#define WBSD_FIFOEN_FULL       0x10
+#define WBSD_FIFO_THREMASK     0x0F
+
+#define WBSD_BLOCK_READ                0x80
+#define WBSD_BLOCK_WRITE       0x40
+#define WBSD_BUSY              0x20
+#define WBSD_CARDTRAFFIC       0x04
+#define WBSD_SENDCMD           0x02
+#define WBSD_RECVRES           0x01
+
+#define WBSD_RSP_SHORT         0x00
+#define WBSD_RSP_LONG          0x01
+
+#define WBSD_CRC_MASK          0x1F
+#define WBSD_CRC_OK            0x05 /* S010E (00101) */
+#define WBSD_CRC_FAIL          0x0B /* S101E (01011) */
+
+#define WBSD_DMA_SIZE          65536
+
+struct wbsd_host
+{
+       struct mmc_host*        mmc;            /* MMC structure */
+
+       spinlock_t              lock;           /* Mutex */
+
+       int                     flags;          /* Driver states */
+
+#define WBSD_FCARD_PRESENT     (1<<0)          /* Card is present */
+#define WBSD_FIGNORE_DETECT    (1<<1)          /* Ignore card detection */
+
+       struct mmc_request*     mrq;            /* Current request */
+
+       u8                      isr;            /* Accumulated ISR */
+
+       struct scatterlist*     cur_sg;         /* Current SG entry */
+       unsigned int            num_sg;         /* Number of entries left */
+
+       unsigned int            offset;         /* Offset into current entry */
+       unsigned int            remain;         /* Data left in curren entry */
+
+       char*                   dma_buffer;     /* ISA DMA buffer */
+       dma_addr_t              dma_addr;       /* Physical address for same */
+
+       int                     firsterr;       /* See fifo functions */
+
+       u8                      clk;            /* Current clock speed */
+       unsigned char           bus_width;      /* Current bus width */
+
+       int                     config;         /* Config port */
+       u8                      unlock_code;    /* Code to unlock config */
+
+       int                     chip_id;        /* ID of controller */
+
+       int                     base;           /* I/O port base */
+       int                     irq;            /* Interrupt */
+       int                     dma;            /* DMA channel */
+
+       struct tasklet_struct   card_tasklet;   /* Tasklet structures */
+       struct tasklet_struct   fifo_tasklet;
+       struct tasklet_struct   crc_tasklet;
+       struct tasklet_struct   timeout_tasklet;
+       struct tasklet_struct   finish_tasklet;
+
+       struct timer_list       ignore_timer;   /* Ignore detection timer */
+};
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
deleted file mode 100644 (file)
index 7ee2045..0000000
+++ /dev/null
@@ -1,1137 +0,0 @@
-/*
- *  linux/drivers/mmc/imxmmc.c - Motorola i.MX MMCI driver
- *
- *  Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de>
- *  Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
- *
- *  derived from pxamci.c by Russell King
- *
- * 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.
- *
- *  2005-04-17 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             Changed to conform redesigned i.MX scatter gather DMA interface
- *
- *  2005-11-04 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             Updated for 2.6.14 kernel
- *
- *  2005-12-13 Jay Monkman <jtm@smoothsmoothie.com>
- *             Found and corrected problems in the write path
- *
- *  2005-12-30 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             The event handling rewritten right way in softirq.
- *             Added many ugly hacks and delays to overcome SDHC
- *             deficiencies
- *
- */
-
-#ifdef CONFIG_MMC_DEBUG
-#define DEBUG
-#else
-#undef  DEBUG
-#endif
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/dma-mapping.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/delay.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/sizes.h>
-#include <asm/arch/mmc.h>
-#include <asm/arch/imx-dma.h>
-
-#include "imxmmc.h"
-
-#define DRIVER_NAME "imx-mmc"
-
-#define IMXMCI_INT_MASK_DEFAULT (INT_MASK_BUF_READY | INT_MASK_DATA_TRAN | \
-                     INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \
-                     INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO)
-
-struct imxmci_host {
-       struct mmc_host         *mmc;
-       spinlock_t              lock;
-       struct resource         *res;
-       int                     irq;
-       imx_dmach_t             dma;
-       unsigned int            clkrt;
-       unsigned int            cmdat;
-       volatile unsigned int   imask;
-       unsigned int            power_mode;
-       unsigned int            present;
-       struct imxmmc_platform_data *pdata;
-
-       struct mmc_request      *req;
-       struct mmc_command      *cmd;
-       struct mmc_data         *data;
-
-       struct timer_list       timer;
-       struct tasklet_struct   tasklet;
-       unsigned int            status_reg;
-       unsigned long           pending_events;
-       /* Next to fields are there for CPU driven transfers to overcome SDHC deficiencies */
-       u16                     *data_ptr;
-       unsigned int            data_cnt;
-       atomic_t                stuck_timeout;
-
-       unsigned int            dma_nents;
-       unsigned int            dma_size;
-       unsigned int            dma_dir;
-       int                     dma_allocated;
-
-       unsigned char           actual_bus_width;
-
-       int                     prev_cmd_code;
-};
-
-#define IMXMCI_PEND_IRQ_b      0
-#define IMXMCI_PEND_DMA_END_b  1
-#define IMXMCI_PEND_DMA_ERR_b  2
-#define IMXMCI_PEND_WAIT_RESP_b        3
-#define IMXMCI_PEND_DMA_DATA_b 4
-#define IMXMCI_PEND_CPU_DATA_b 5
-#define IMXMCI_PEND_CARD_XCHG_b        6
-#define IMXMCI_PEND_SET_INIT_b 7
-#define IMXMCI_PEND_STARTED_b  8
-
-#define IMXMCI_PEND_IRQ_m      (1 << IMXMCI_PEND_IRQ_b)
-#define IMXMCI_PEND_DMA_END_m  (1 << IMXMCI_PEND_DMA_END_b)
-#define IMXMCI_PEND_DMA_ERR_m  (1 << IMXMCI_PEND_DMA_ERR_b)
-#define IMXMCI_PEND_WAIT_RESP_m        (1 << IMXMCI_PEND_WAIT_RESP_b)
-#define IMXMCI_PEND_DMA_DATA_m (1 << IMXMCI_PEND_DMA_DATA_b)
-#define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b)
-#define IMXMCI_PEND_CARD_XCHG_m        (1 << IMXMCI_PEND_CARD_XCHG_b)
-#define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b)
-#define IMXMCI_PEND_STARTED_m  (1 << IMXMCI_PEND_STARTED_b)
-
-static void imxmci_stop_clock(struct imxmci_host *host)
-{
-       int i = 0;
-       MMC_STR_STP_CLK &= ~STR_STP_CLK_START_CLK;
-       while(i < 0x1000) {
-               if(!(i & 0x7f))
-                       MMC_STR_STP_CLK |= STR_STP_CLK_STOP_CLK;
-
-               if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)) {
-                       /* Check twice before cut */
-                       if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN))
-                               return;
-               }
-
-               i++;
-       }
-       dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n");
-}
-
-static int imxmci_start_clock(struct imxmci_host *host)
-{
-       unsigned int trials = 0;
-       unsigned int delay_limit = 128;
-       unsigned long flags;
-
-       MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK;
-
-       clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
-
-       /*
-        * Command start of the clock, this usually succeeds in less
-        * then 6 delay loops, but during card detection (low clockrate)
-        * it takes up to 5000 delay loops and sometimes fails for the first time
-        */
-       MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
-
-       do {
-               unsigned int delay = delay_limit;
-
-               while(delay--){
-                       if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
-                               /* Check twice before cut */
-                               if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
-                                       return 0;
-
-                       if(test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
-                               return 0;
-               }
-
-               local_irq_save(flags);
-               /*
-                * Ensure, that request is not doubled under all possible circumstances.
-                * It is possible, that cock running state is missed, because some other
-                * IRQ or schedule delays this function execution and the clocks has
-                * been already stopped by other means (response processing, SDHC HW)
-                */
-               if(!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
-                       MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
-               local_irq_restore(flags);
-
-       } while(++trials<256);
-
-       dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n");
-
-       return -1;
-}
-
-static void imxmci_softreset(void)
-{
-       /* reset sequence */
-       MMC_STR_STP_CLK = 0x8;
-       MMC_STR_STP_CLK = 0xD;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-
-       MMC_RES_TO = 0xff;
-       MMC_BLK_LEN = 512;
-       MMC_NOB = 1;
-}
-
-static int imxmci_busy_wait_for_status(struct imxmci_host *host,
-                       unsigned int *pstat, unsigned int stat_mask,
-                       int timeout, const char *where)
-{
-       int loops=0;
-       while(!(*pstat & stat_mask)) {
-               loops+=2;
-               if(loops >= timeout) {
-                       dev_dbg(mmc_dev(host->mmc), "busy wait timeout in %s, STATUS = 0x%x (0x%x)\n",
-                               where, *pstat, stat_mask);
-                       return -1;
-               }
-               udelay(2);
-               *pstat |= MMC_STATUS;
-       }
-       if(!loops)
-               return 0;
-
-       /* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */
-       if(!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock>=8000000))
-               dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n",
-                       loops, where, *pstat, stat_mask);
-       return loops;
-}
-
-static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
-{
-       unsigned int nob = data->blocks;
-       unsigned int blksz = data->blksz;
-       unsigned int datasz = nob * blksz;
-       int i;
-
-       if (data->flags & MMC_DATA_STREAM)
-               nob = 0xffff;
-
-       host->data = data;
-       data->bytes_xfered = 0;
-
-       MMC_NOB = nob;
-       MMC_BLK_LEN = blksz;
-
-       /*
-        * DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise.
-        * We are in big troubles for non-512 byte transfers according to note in the paragraph
-        * 20.6.7 of User Manual anyway, but we need to be able to transfer SCR at least.
-        * The situation is even more complex in reality. The SDHC in not able to handle wll
-        * partial FIFO fills and reads. The length has to be rounded up to burst size multiple.
-        * This is required for SCR read at least.
-        */
-       if (datasz < 512) {
-               host->dma_size = datasz;
-               if (data->flags & MMC_DATA_READ) {
-                       host->dma_dir = DMA_FROM_DEVICE;
-
-                       /* Hack to enable read SCR */
-                       MMC_NOB = 1;
-                       MMC_BLK_LEN = 512;
-               } else {
-                       host->dma_dir = DMA_TO_DEVICE;
-               }
-
-               /* Convert back to virtual address */
-               host->data_ptr = (u16*)(page_address(data->sg->page) + data->sg->offset);
-               host->data_cnt = 0;
-
-               clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
-               set_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
-
-               return;
-       }
-
-       if (data->flags & MMC_DATA_READ) {
-               host->dma_dir = DMA_FROM_DEVICE;
-               host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
-                                               data->sg_len,  host->dma_dir);
-
-               imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
-                       host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_READ);
-
-               /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/
-               CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN;
-       } else {
-               host->dma_dir = DMA_TO_DEVICE;
-
-               host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
-                                               data->sg_len,  host->dma_dir);
-
-               imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
-                       host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_WRITE);
-
-               /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/
-               CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN;
-       }
-
-#if 1  /* This code is there only for consistency checking and can be disabled in future */
-       host->dma_size = 0;
-       for(i=0; i<host->dma_nents; i++)
-               host->dma_size+=data->sg[i].length;
-
-       if (datasz > host->dma_size) {
-               dev_err(mmc_dev(host->mmc), "imxmci_setup_data datasz 0x%x > 0x%x dm_size\n",
-                      datasz, host->dma_size);
-       }
-#endif
-
-       host->dma_size = datasz;
-
-       wmb();
-
-       if(host->actual_bus_width == MMC_BUS_WIDTH_4)
-               BLR(host->dma) = 0;     /* burst 64 byte read / 64 bytes write */
-       else
-               BLR(host->dma) = 16;    /* burst 16 byte read / 16 bytes write */
-
-       RSSR(host->dma) = DMA_REQ_SDHC;
-
-       set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
-       clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
-
-       /* start DMA engine for read, write is delayed after initial response */
-       if (host->dma_dir == DMA_FROM_DEVICE) {
-               imx_dma_enable(host->dma);
-       }
-}
-
-static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat)
-{
-       unsigned long flags;
-       u32 imask;
-
-       WARN_ON(host->cmd != NULL);
-       host->cmd = cmd;
-
-       /* Ensure, that clock are stopped else command programming and start fails */
-       imxmci_stop_clock(host);
-
-       if (cmd->flags & MMC_RSP_BUSY)
-               cmdat |= CMD_DAT_CONT_BUSY;
-
-       switch (mmc_resp_type(cmd)) {
-       case MMC_RSP_R1: /* short CRC, OPCODE */
-       case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */
-               cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1;
-               break;
-       case MMC_RSP_R2: /* long 136 bit + CRC */
-               cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2;
-               break;
-       case MMC_RSP_R3: /* short */
-               cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3;
-               break;
-       default:
-               break;
-       }
-
-       if ( test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events) )
-               cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */
-
-       if ( host->actual_bus_width == MMC_BUS_WIDTH_4 )
-               cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
-
-       MMC_CMD = cmd->opcode;
-       MMC_ARGH = cmd->arg >> 16;
-       MMC_ARGL = cmd->arg & 0xffff;
-       MMC_CMD_DAT_CONT = cmdat;
-
-       atomic_set(&host->stuck_timeout, 0);
-       set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events);
-
-
-       imask = IMXMCI_INT_MASK_DEFAULT;
-       imask &= ~INT_MASK_END_CMD_RES;
-       if ( cmdat & CMD_DAT_CONT_DATA_ENABLE ) {
-               /*imask &= ~INT_MASK_BUF_READY;*/
-               imask &= ~INT_MASK_DATA_TRAN;
-               if ( cmdat & CMD_DAT_CONT_WRITE )
-                       imask &= ~INT_MASK_WRITE_OP_DONE;
-               if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
-                       imask &= ~INT_MASK_BUF_READY;
-       }
-
-       spin_lock_irqsave(&host->lock, flags);
-       host->imask = imask;
-       MMC_INT_MASK = host->imask;
-       spin_unlock_irqrestore(&host->lock, flags);
-
-       dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n",
-               cmd->opcode, cmd->opcode, imask);
-
-       imxmci_start_clock(host);
-}
-
-static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *req)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&host->lock, flags);
-
-       host->pending_events &= ~(IMXMCI_PEND_WAIT_RESP_m | IMXMCI_PEND_DMA_END_m |
-                       IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m);
-
-       host->imask = IMXMCI_INT_MASK_DEFAULT;
-       MMC_INT_MASK = host->imask;
-
-       spin_unlock_irqrestore(&host->lock, flags);
-
-       if(req && req->cmd)
-               host->prev_cmd_code = req->cmd->opcode;
-
-       host->req = NULL;
-       host->cmd = NULL;
-       host->data = NULL;
-       mmc_request_done(host->mmc, req);
-}
-
-static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat)
-{
-       struct mmc_data *data = host->data;
-       int data_error;
-
-       if(test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)){
-               imx_dma_disable(host->dma);
-               dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents,
-                            host->dma_dir);
-       }
-
-       if ( stat & STATUS_ERR_MASK ) {
-               dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat);
-               if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR))
-                       data->error = MMC_ERR_BADCRC;
-               else if(stat & STATUS_TIME_OUT_READ)
-                       data->error = MMC_ERR_TIMEOUT;
-               else
-                       data->error = MMC_ERR_FAILED;
-       } else {
-               data->bytes_xfered = host->dma_size;
-       }
-
-       data_error = data->error;
-
-       host->data = NULL;
-
-       return data_error;
-}
-
-static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
-{
-       struct mmc_command *cmd = host->cmd;
-       int i;
-       u32 a,b,c;
-       struct mmc_data *data = host->data;
-
-       if (!cmd)
-               return 0;
-
-       host->cmd = NULL;
-
-       if (stat & STATUS_TIME_OUT_RESP) {
-               dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n");
-               cmd->error = MMC_ERR_TIMEOUT;
-       } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
-               dev_dbg(mmc_dev(host->mmc), "cmd crc error\n");
-               cmd->error = MMC_ERR_BADCRC;
-       }
-
-       if(cmd->flags & MMC_RSP_PRESENT) {
-               if(cmd->flags & MMC_RSP_136) {
-                       for (i = 0; i < 4; i++) {
-                               u32 a = MMC_RES_FIFO & 0xffff;
-                               u32 b = MMC_RES_FIFO & 0xffff;
-                               cmd->resp[i] = a<<16 | b;
-                       }
-               } else {
-                       a = MMC_RES_FIFO & 0xffff;
-                       b = MMC_RES_FIFO & 0xffff;
-                       c = MMC_RES_FIFO & 0xffff;
-                       cmd->resp[0] = a<<24 | b<<8 | c>>8;
-               }
-       }
-
-       dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n",
-               cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error);
-
-       if (data && (cmd->error == MMC_ERR_NONE) && !(stat & STATUS_ERR_MASK)) {
-               if (host->req->data->flags & MMC_DATA_WRITE) {
-
-                       /* Wait for FIFO to be empty before starting DMA write */
-
-                       stat = MMC_STATUS;
-                       if(imxmci_busy_wait_for_status(host, &stat,
-                               STATUS_APPL_BUFF_FE,
-                               40, "imxmci_cmd_done DMA WR") < 0) {
-                               cmd->error = MMC_ERR_FIFO;
-                               imxmci_finish_data(host, stat);
-                               if(host->req)
-                                       imxmci_finish_request(host, host->req);
-                               dev_warn(mmc_dev(host->mmc), "STATUS = 0x%04x\n",
-                                      stat);
-                               return 0;
-                       }
-
-                       if(test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
-                               imx_dma_enable(host->dma);
-                       }
-               }
-       } else {
-               struct mmc_request *req;
-               imxmci_stop_clock(host);
-               req = host->req;
-
-               if(data)
-                       imxmci_finish_data(host, stat);
-
-               if( req ) {
-                       imxmci_finish_request(host, req);
-               } else {
-                       dev_warn(mmc_dev(host->mmc), "imxmci_cmd_done: no request to finish\n");
-               }
-       }
-
-       return 1;
-}
-
-static int imxmci_data_done(struct imxmci_host *host, unsigned int stat)
-{
-       struct mmc_data *data = host->data;
-       int data_error;
-
-       if (!data)
-               return 0;
-
-       data_error = imxmci_finish_data(host, stat);
-
-       if (host->req->stop) {
-               imxmci_stop_clock(host);
-               imxmci_start_cmd(host, host->req->stop, 0);
-       } else {
-               struct mmc_request *req;
-               req = host->req;
-               if( req ) {
-                       imxmci_finish_request(host, req);
-               } else {
-                       dev_warn(mmc_dev(host->mmc), "imxmci_data_done: no request to finish\n");
-               }
-       }
-
-       return 1;
-}
-
-static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
-{
-       int i;
-       int burst_len;
-       int trans_done = 0;
-       unsigned int stat = *pstat;
-
-       if(host->actual_bus_width != MMC_BUS_WIDTH_4)
-               burst_len = 16;
-       else
-               burst_len = 64;
-
-       /* This is unfortunately required */
-       dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data running STATUS = 0x%x\n",
-               stat);
-
-       udelay(20);     /* required for clocks < 8MHz*/
-
-       if(host->dma_dir == DMA_FROM_DEVICE) {
-               imxmci_busy_wait_for_status(host, &stat,
-                               STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE |
-                               STATUS_TIME_OUT_READ,
-                               50, "imxmci_cpu_driven_data read");
-
-               while((stat & (STATUS_APPL_BUFF_FF |  STATUS_DATA_TRANS_DONE)) &&
-                     !(stat & STATUS_TIME_OUT_READ) &&
-                     (host->data_cnt < 512)) {
-
-                       udelay(20);     /* required for clocks < 8MHz*/
-
-                       for(i = burst_len; i>=2 ; i-=2) {
-                               u16 data;
-                               data = MMC_BUFFER_ACCESS;
-                               udelay(10);     /* required for clocks < 8MHz*/
-                               if(host->data_cnt+2 <= host->dma_size) {
-                                       *(host->data_ptr++) = data;
-                               } else {
-                                       if(host->data_cnt < host->dma_size)
-                                               *(u8*)(host->data_ptr) = data;
-                               }
-                               host->data_cnt += 2;
-                       }
-
-                       stat = MMC_STATUS;
-
-                       dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read %d burst %d STATUS = 0x%x\n",
-                               host->data_cnt, burst_len, stat);
-               }
-
-               if((stat & STATUS_DATA_TRANS_DONE) && (host->data_cnt >= 512))
-                       trans_done = 1;
-
-               if(host->dma_size & 0x1ff)
-                       stat &= ~STATUS_CRC_READ_ERR;
-
-               if(stat & STATUS_TIME_OUT_READ) {
-                       dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read timeout STATUS = 0x%x\n",
-                               stat);
-                       trans_done = -1;
-               }
-
-       } else {
-               imxmci_busy_wait_for_status(host, &stat,
-                               STATUS_APPL_BUFF_FE,
-                               20, "imxmci_cpu_driven_data write");
-
-               while((stat & STATUS_APPL_BUFF_FE) &&
-                     (host->data_cnt < host->dma_size)) {
-                       if(burst_len >= host->dma_size - host->data_cnt) {
-                               burst_len = host->dma_size - host->data_cnt;
-                               host->data_cnt = host->dma_size;
-                               trans_done = 1;
-                       } else {
-                               host->data_cnt += burst_len;
-                       }
-
-                       for(i = burst_len; i>0 ; i-=2)
-                               MMC_BUFFER_ACCESS = *(host->data_ptr++);
-
-                       stat = MMC_STATUS;
-
-                       dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n",
-                               burst_len, stat);
-               }
-       }
-
-       *pstat = stat;
-
-       return trans_done;
-}
-
-static void imxmci_dma_irq(int dma, void *devid)
-{
-       struct imxmci_host *host = devid;
-       uint32_t stat = MMC_STATUS;
-
-       atomic_set(&host->stuck_timeout, 0);
-       host->status_reg = stat;
-       set_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
-       tasklet_schedule(&host->tasklet);
-}
-
-static irqreturn_t imxmci_irq(int irq, void *devid)
-{
-       struct imxmci_host *host = devid;
-       uint32_t stat = MMC_STATUS;
-       int handled = 1;
-
-       MMC_INT_MASK = host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT;
-
-       atomic_set(&host->stuck_timeout, 0);
-       host->status_reg = stat;
-       set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
-       set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
-       tasklet_schedule(&host->tasklet);
-
-       return IRQ_RETVAL(handled);;
-}
-
-static void imxmci_tasklet_fnc(unsigned long data)
-{
-       struct imxmci_host *host = (struct imxmci_host *)data;
-       u32 stat;
-       unsigned int data_dir_mask = 0; /* STATUS_WR_CRC_ERROR_CODE_MASK */
-       int timeout = 0;
-
-       if(atomic_read(&host->stuck_timeout) > 4) {
-               char *what;
-               timeout = 1;
-               stat = MMC_STATUS;
-               host->status_reg = stat;
-               if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
-                       if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
-                               what = "RESP+DMA";
-                       else
-                               what = "RESP";
-               else
-                       if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
-                               if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events))
-                                       what = "DATA";
-                               else
-                                       what = "DMA";
-                       else
-                               what = "???";
-
-               dev_err(mmc_dev(host->mmc), "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n",
-                      what, stat, MMC_INT_MASK);
-               dev_err(mmc_dev(host->mmc), "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n",
-                      MMC_CMD_DAT_CONT, MMC_BLK_LEN, MMC_NOB, CCR(host->dma));
-               dev_err(mmc_dev(host->mmc), "CMD%d, prevCMD%d, bus %d-bit, dma_size = 0x%x\n",
-                      host->cmd?host->cmd->opcode:0, host->prev_cmd_code, 1<<host->actual_bus_width, host->dma_size);
-       }
-
-       if(!host->present || timeout)
-               host->status_reg = STATUS_TIME_OUT_RESP | STATUS_TIME_OUT_READ |
-                                   STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR;
-
-       if(test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) {
-               clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
-
-               stat = MMC_STATUS;
-               /*
-                * This is not required in theory, but there is chance to miss some flag
-                * which clears automatically by mask write, FreeScale original code keeps
-                * stat from IRQ time so do I
-                */
-               stat |= host->status_reg;
-
-               if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
-                       stat &= ~STATUS_CRC_READ_ERR;
-
-               if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
-                       imxmci_busy_wait_for_status(host, &stat,
-                                       STATUS_END_CMD_RESP | STATUS_ERR_MASK,
-                                       20, "imxmci_tasklet_fnc resp (ERRATUM #4)");
-               }
-
-               if(stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) {
-                       if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
-                               imxmci_cmd_done(host, stat);
-                       if(host->data && (stat & STATUS_ERR_MASK))
-                               imxmci_data_done(host, stat);
-               }
-
-               if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) {
-                       stat |= MMC_STATUS;
-                       if(imxmci_cpu_driven_data(host, &stat)){
-                               if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
-                                       imxmci_cmd_done(host, stat);
-                               atomic_clear_mask(IMXMCI_PEND_IRQ_m|IMXMCI_PEND_CPU_DATA_m,
-                                                       &host->pending_events);
-                               imxmci_data_done(host, stat);
-                       }
-               }
-       }
-
-       if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) &&
-          !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
-
-               stat = MMC_STATUS;
-               /* Same as above */
-               stat |= host->status_reg;
-
-               if(host->dma_dir == DMA_TO_DEVICE) {
-                       data_dir_mask = STATUS_WRITE_OP_DONE;
-               } else {
-                       data_dir_mask = STATUS_DATA_TRANS_DONE;
-               }
-
-               if(stat & data_dir_mask) {
-                       clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
-                       imxmci_data_done(host, stat);
-               }
-       }
-
-       if(test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) {
-
-               if(host->cmd)
-                       imxmci_cmd_done(host, STATUS_TIME_OUT_RESP);
-
-               if(host->data)
-                       imxmci_data_done(host, STATUS_TIME_OUT_READ |
-                                        STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR);
-
-               if(host->req)
-                       imxmci_finish_request(host, host->req);
-
-               mmc_detect_change(host->mmc, msecs_to_jiffies(100));
-
-       }
-}
-
-static void imxmci_request(struct mmc_host *mmc, struct mmc_request *req)
-{
-       struct imxmci_host *host = mmc_priv(mmc);
-       unsigned int cmdat;
-
-       WARN_ON(host->req != NULL);
-
-       host->req = req;
-
-       cmdat = 0;
-
-       if (req->data) {
-               imxmci_setup_data(host, req->data);
-
-               cmdat |= CMD_DAT_CONT_DATA_ENABLE;
-
-               if (req->data->flags & MMC_DATA_WRITE)
-                       cmdat |= CMD_DAT_CONT_WRITE;
-
-               if (req->data->flags & MMC_DATA_STREAM) {
-                       cmdat |= CMD_DAT_CONT_STREAM_BLOCK;
-               }
-       }
-
-       imxmci_start_cmd(host, req->cmd, cmdat);
-}
-
-#define CLK_RATE 19200000
-
-static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-       struct imxmci_host *host = mmc_priv(mmc);
-       int prescaler;
-
-       if( ios->bus_width==MMC_BUS_WIDTH_4 ) {
-               host->actual_bus_width = MMC_BUS_WIDTH_4;
-               imx_gpio_mode(PB11_PF_SD_DAT3);
-       }else{
-               host->actual_bus_width = MMC_BUS_WIDTH_1;
-               imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
-       }
-
-       if ( host->power_mode != ios->power_mode ) {
-               switch (ios->power_mode) {
-               case MMC_POWER_OFF:
-                       break;
-               case MMC_POWER_UP:
-                       set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
-                       break;
-               case MMC_POWER_ON:
-                       break;
-               }
-               host->power_mode = ios->power_mode;
-       }
-
-       if ( ios->clock ) {
-               unsigned int clk;
-
-               /* The prescaler is 5 for PERCLK2 equal to 96MHz
-                * then 96MHz / 5 = 19.2 MHz
-                */
-               clk=imx_get_perclk2();
-               prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE;
-               switch(prescaler) {
-               case 0:
-               case 1: prescaler = 0;
-                       break;
-               case 2: prescaler = 1;
-                       break;
-               case 3: prescaler = 2;
-                       break;
-               case 4: prescaler = 4;
-                       break;
-               default:
-               case 5: prescaler = 5;
-                       break;
-               }
-
-               dev_dbg(mmc_dev(host->mmc), "PERCLK2 %d MHz -> prescaler %d\n",
-                       clk, prescaler);
-
-               for(clk=0; clk<8; clk++) {
-                       int x;
-                       x = CLK_RATE / (1<<clk);
-                       if( x <= ios->clock)
-                               break;
-               }
-
-               MMC_STR_STP_CLK |= STR_STP_CLK_ENABLE; /* enable controller */
-
-               imxmci_stop_clock(host);
-               MMC_CLK_RATE = (prescaler<<3) | clk;
-               /*
-                * Under my understanding, clock should not be started there, because it would
-                * initiate SDHC sequencer and send last or random command into card
-                */
-               /*imxmci_start_clock(host);*/
-
-               dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE);
-       } else {
-               imxmci_stop_clock(host);
-       }
-}
-
-static const struct mmc_host_ops imxmci_ops = {
-       .request        = imxmci_request,
-       .set_ios        = imxmci_set_ios,
-};
-
-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() != host->present ) {
-               host->present ^= 1;
-               dev_info(mmc_dev(host->mmc), "card %s\n",
-                     host->present ? "inserted" : "removed");
-
-               set_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events);
-               tasklet_schedule(&host->tasklet);
-       }
-
-       if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) ||
-          test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
-               atomic_inc(&host->stuck_timeout);
-               if(atomic_read(&host->stuck_timeout) > 4)
-                       tasklet_schedule(&host->tasklet);
-       } else {
-               atomic_set(&host->stuck_timeout, 0);
-
-       }
-
-       mod_timer(&host->timer, jiffies + (HZ>>1));
-}
-
-static int imxmci_probe(struct platform_device *pdev)
-{
-       struct mmc_host *mmc;
-       struct imxmci_host *host = NULL;
-       struct resource *r;
-       int ret = 0, irq;
-
-       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)
-               return -ENXIO;
-
-       r = request_mem_region(r->start, 0x100, "IMXMCI");
-       if (!r)
-               return -EBUSY;
-
-       mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev);
-       if (!mmc) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       mmc->ops = &imxmci_ops;
-       mmc->f_min = 150000;
-       mmc->f_max = CLK_RATE/2;
-       mmc->ocr_avail = MMC_VDD_32_33;
-       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_BYTEBLOCK;
-
-       /* MMC core transfer sizes tunable parameters */
-       mmc->max_hw_segs = 64;
-       mmc->max_phys_segs = 64;
-       mmc->max_seg_size = 64*512;     /* default PAGE_CACHE_SIZE */
-       mmc->max_req_size = 64*512;     /* default PAGE_CACHE_SIZE */
-       mmc->max_blk_size = 2048;
-       mmc->max_blk_count = 65535;
-
-       host = mmc_priv(mmc);
-       host->mmc = mmc;
-       host->dma_allocated = 0;
-       host->pdata = pdev->dev.platform_data;
-
-       spin_lock_init(&host->lock);
-       host->res = r;
-       host->irq = irq;
-
-       imx_gpio_mode(PB8_PF_SD_DAT0);
-       imx_gpio_mode(PB9_PF_SD_DAT1);
-       imx_gpio_mode(PB10_PF_SD_DAT2);
-       /* Configured as GPIO with pull-up to ensure right MCC card mode */
-       /* Switched to PB11_PF_SD_DAT3 if 4 bit bus is configured */
-       imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
-       /* imx_gpio_mode(PB11_PF_SD_DAT3); */
-       imx_gpio_mode(PB12_PF_SD_CLK);
-       imx_gpio_mode(PB13_PF_SD_CMD);
-
-       imxmci_softreset();
-
-       if ( MMC_REV_NO != 0x390 ) {
-               dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
-                       MMC_REV_NO);
-               goto out;
-       }
-
-       MMC_READ_TO = 0x2db4; /* recommended in data sheet */
-
-       host->imask = IMXMCI_INT_MASK_DEFAULT;
-       MMC_INT_MASK = host->imask;
-
-
-       if(imx_dma_request_by_prio(&host->dma, DRIVER_NAME, DMA_PRIO_LOW)<0){
-               dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n");
-               ret = -EBUSY;
-               goto out;
-       }
-       host->dma_allocated=1;
-       imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host);
-
-       tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host);
-       host->status_reg=0;
-       host->pending_events=0;
-
-       ret = request_irq(host->irq, imxmci_irq, 0, DRIVER_NAME, host);
-       if (ret)
-               goto out;
-
-       host->present = host->pdata->card_present();
-       init_timer(&host->timer);
-       host->timer.data = (unsigned long)host;
-       host->timer.function = imxmci_check_status;
-       add_timer(&host->timer);
-       mod_timer(&host->timer, jiffies + (HZ>>1));
-
-       platform_set_drvdata(pdev, mmc);
-
-       mmc_add_host(mmc);
-
-       return 0;
-
-out:
-       if (host) {
-               if(host->dma_allocated){
-                       imx_dma_free(host->dma);
-                       host->dma_allocated=0;
-               }
-       }
-       if (mmc)
-               mmc_free_host(mmc);
-       release_resource(r);
-       return ret;
-}
-
-static int imxmci_remove(struct platform_device *pdev)
-{
-       struct mmc_host *mmc = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (mmc) {
-               struct imxmci_host *host = mmc_priv(mmc);
-
-               tasklet_disable(&host->tasklet);
-
-               del_timer_sync(&host->timer);
-               mmc_remove_host(mmc);
-
-               free_irq(host->irq, host);
-               if(host->dma_allocated){
-                       imx_dma_free(host->dma);
-                       host->dma_allocated=0;
-               }
-
-               tasklet_kill(&host->tasklet);
-
-               release_resource(host->res);
-
-               mmc_free_host(mmc);
-       }
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int imxmci_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct mmc_host *mmc = platform_get_drvdata(dev);
-       int ret = 0;
-
-       if (mmc)
-               ret = mmc_suspend_host(mmc, state);
-
-       return ret;
-}
-
-static int imxmci_resume(struct platform_device *dev)
-{
-       struct mmc_host *mmc = platform_get_drvdata(dev);
-       struct imxmci_host *host;
-       int ret = 0;
-
-       if (mmc) {
-               host = mmc_priv(mmc);
-               if(host)
-                       set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
-               ret = mmc_resume_host(mmc);
-       }
-
-       return ret;
-}
-#else
-#define imxmci_suspend  NULL
-#define imxmci_resume   NULL
-#endif /* CONFIG_PM */
-
-static struct platform_driver imxmci_driver = {
-       .probe          = imxmci_probe,
-       .remove         = imxmci_remove,
-       .suspend        = imxmci_suspend,
-       .resume         = imxmci_resume,
-       .driver         = {
-               .name           = DRIVER_NAME,
-       }
-};
-
-static int __init imxmci_init(void)
-{
-       return platform_driver_register(&imxmci_driver);
-}
-
-static void __exit imxmci_exit(void)
-{
-       platform_driver_unregister(&imxmci_driver);
-}
-
-module_init(imxmci_init);
-module_exit(imxmci_exit);
-
-MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");
-MODULE_AUTHOR("Sascha Hauer, Pengutronix");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/imxmmc.h b/drivers/mmc/imxmmc.h
deleted file mode 100644 (file)
index e5339e3..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-
-# define __REG16(x)    (*((volatile u16 *)IO_ADDRESS(x)))
-
-#define MMC_STR_STP_CLK  __REG16(IMX_MMC_BASE + 0x00)
-#define MMC_STATUS       __REG16(IMX_MMC_BASE + 0x04)
-#define MMC_CLK_RATE     __REG16(IMX_MMC_BASE + 0x08)
-#define MMC_CMD_DAT_CONT __REG16(IMX_MMC_BASE + 0x0C)
-#define MMC_RES_TO       __REG16(IMX_MMC_BASE + 0x10)
-#define MMC_READ_TO      __REG16(IMX_MMC_BASE + 0x14)
-#define MMC_BLK_LEN      __REG16(IMX_MMC_BASE + 0x18)
-#define MMC_NOB          __REG16(IMX_MMC_BASE + 0x1C)
-#define MMC_REV_NO       __REG16(IMX_MMC_BASE + 0x20)
-#define MMC_INT_MASK     __REG16(IMX_MMC_BASE + 0x24)
-#define MMC_CMD          __REG16(IMX_MMC_BASE + 0x28)
-#define MMC_ARGH         __REG16(IMX_MMC_BASE + 0x2C)
-#define MMC_ARGL         __REG16(IMX_MMC_BASE + 0x30)
-#define MMC_RES_FIFO     __REG16(IMX_MMC_BASE + 0x34)
-#define MMC_BUFFER_ACCESS __REG16(IMX_MMC_BASE + 0x38)
-#define MMC_BUFFER_ACCESS_OFS 0x38
-
-
-#define STR_STP_CLK_ENDIAN              (1<<5)
-#define STR_STP_CLK_RESET               (1<<3)
-#define STR_STP_CLK_ENABLE              (1<<2)
-#define STR_STP_CLK_START_CLK           (1<<1)
-#define STR_STP_CLK_STOP_CLK            (1<<0)
-#define STATUS_CARD_PRESENCE            (1<<15)
-#define STATUS_SDIO_INT_ACTIVE          (1<<14)
-#define STATUS_END_CMD_RESP             (1<<13)
-#define STATUS_WRITE_OP_DONE            (1<<12)
-#define STATUS_DATA_TRANS_DONE          (1<<11)
-#define STATUS_WR_CRC_ERROR_CODE_MASK   (3<<10)
-#define STATUS_CARD_BUS_CLK_RUN         (1<<8)
-#define STATUS_APPL_BUFF_FF             (1<<7)
-#define STATUS_APPL_BUFF_FE             (1<<6)
-#define STATUS_RESP_CRC_ERR             (1<<5)
-#define STATUS_CRC_READ_ERR             (1<<3)
-#define STATUS_CRC_WRITE_ERR            (1<<2)
-#define STATUS_TIME_OUT_RESP            (1<<1)
-#define STATUS_TIME_OUT_READ            (1<<0)
-#define STATUS_ERR_MASK                 0x2f
-#define CLK_RATE_PRESCALER(x)           ((x) & 0x7)
-#define CLK_RATE_CLK_RATE(x)            (((x) & 0x7) << 3)
-#define CMD_DAT_CONT_CMD_RESP_LONG_OFF  (1<<12)
-#define CMD_DAT_CONT_STOP_READWAIT      (1<<11)
-#define CMD_DAT_CONT_START_READWAIT     (1<<10)
-#define CMD_DAT_CONT_BUS_WIDTH_1        (0<<8)
-#define CMD_DAT_CONT_BUS_WIDTH_4        (2<<8)
-#define CMD_DAT_CONT_INIT               (1<<7)
-#define CMD_DAT_CONT_BUSY               (1<<6)
-#define CMD_DAT_CONT_STREAM_BLOCK       (1<<5)
-#define CMD_DAT_CONT_WRITE              (1<<4)
-#define CMD_DAT_CONT_DATA_ENABLE        (1<<3)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R1 (1)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R2 (2)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R3 (3)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R4 (4)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R5 (5)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R6 (6)
-#define INT_MASK_AUTO_CARD_DETECT       (1<<6)
-#define INT_MASK_DAT0_EN                (1<<5)
-#define INT_MASK_SDIO                   (1<<4)
-#define INT_MASK_BUF_READY              (1<<3)
-#define INT_MASK_END_CMD_RES            (1<<2)
-#define INT_MASK_WRITE_OP_DONE          (1<<1)
-#define INT_MASK_DATA_TRAN              (1<<0)
-#define INT_ALL                         (0x7f)
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
deleted file mode 100644 (file)
index d11c2d2..0000000
+++ /dev/null
@@ -1,702 +0,0 @@
-/*
- *  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/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/highmem.h>
-#include <linux/mmc/host.h>
-#include <linux/amba/bus.h>
-#include <linux/clk.h>
-
-#include <asm/cacheflush.h>
-#include <asm/div64.h>
-#include <asm/io.h>
-#include <asm/scatterlist.h>
-#include <asm/sizes.h>
-#include <asm/mach/mmc.h>
-
-#include "mmci.h"
-
-#define DRIVER_NAME "mmci-pl18x"
-
-#define DBG(host,fmt,args...)  \
-       pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
-
-static unsigned int fmax = 515633;
-
-static void
-mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
-{
-       writel(0, host->base + MMCICOMMAND);
-
-       BUG_ON(host->data);
-
-       host->mrq = NULL;
-       host->cmd = NULL;
-
-       if (mrq->data)
-               mrq->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, mrq);
-       spin_lock(&host->lock);
-}
-
-static void mmci_stop_data(struct mmci_host *host)
-{
-       writel(0, host->base + MMCIDATACTRL);
-       writel(0, host->base + MMCIMASK1);
-       host->data = NULL;
-}
-
-static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
-{
-       unsigned int datactrl, timeout, irqmask;
-       unsigned long long clks;
-       void __iomem *base;
-       int blksz_bits;
-
-       DBG(host, "blksz %04x blks %04x flags %08x\n",
-           data->blksz, data->blocks, data->flags);
-
-       host->data = data;
-       host->size = data->blksz;
-       host->data_xfered = 0;
-
-       mmci_init_sg(host, data);
-
-       clks = (unsigned long long)data->timeout_ns * host->cclk;
-       do_div(clks, 1000000000UL);
-
-       timeout = data->timeout_clks + (unsigned int)clks;
-
-       base = host->base;
-       writel(timeout, base + MMCIDATATIMER);
-       writel(host->size, base + MMCIDATALENGTH);
-
-       blksz_bits = ffs(data->blksz) - 1;
-       BUG_ON(1 << blksz_bits != data->blksz);
-
-       datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
-       if (data->flags & MMC_DATA_READ) {
-               datactrl |= MCI_DPSM_DIRECTION;
-               irqmask = MCI_RXFIFOHALFFULLMASK;
-
-               /*
-                * If we have less than a FIFOSIZE of bytes to transfer,
-                * trigger a PIO interrupt as soon as any data is available.
-                */
-               if (host->size < MCI_FIFOSIZE)
-                       irqmask |= MCI_RXDATAAVLBLMASK;
-       } else {
-               /*
-                * We don't actually need to include "FIFO empty" here
-                * since its implicit in "FIFO half empty".
-                */
-               irqmask = MCI_TXFIFOHALFEMPTYMASK;
-       }
-
-       writel(datactrl, base + MMCIDATACTRL);
-       writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
-       writel(irqmask, base + MMCIMASK1);
-}
-
-static void
-mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
-{
-       void __iomem *base = host->base;
-
-       DBG(host, "op %02x arg %08x flags %08x\n",
-           cmd->opcode, cmd->arg, cmd->flags);
-
-       if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
-               writel(0, base + MMCICOMMAND);
-               udelay(1);
-       }
-
-       c |= cmd->opcode | MCI_CPSM_ENABLE;
-       if (cmd->flags & MMC_RSP_PRESENT) {
-               if (cmd->flags & MMC_RSP_136)
-                       c |= MCI_CPSM_LONGRSP;
-               c |= MCI_CPSM_RESPONSE;
-       }
-       if (/*interrupt*/0)
-               c |= MCI_CPSM_INTERRUPT;
-
-       host->cmd = cmd;
-
-       writel(cmd->arg, base + MMCIARGUMENT);
-       writel(c, 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 += data->blksz;
-       }
-       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;
-
-               /*
-                * We hit an error condition.  Ensure that any data
-                * partially written to a page is properly coherent.
-                */
-               if (host->sg_len && data->flags & MMC_DATA_READ)
-                       flush_dcache_page(host->sg_ptr->page);
-       }
-       if (status & MCI_DATAEND) {
-               mmci_stop_data(host);
-
-               if (!data->stop) {
-                       mmci_request_end(host, data->mrq);
-               } else {
-                       mmci_start_command(host, data->stop, 0);
-               }
-       }
-}
-
-static void
-mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
-            unsigned int status)
-{
-       void __iomem *base = host->base;
-
-       host->cmd = NULL;
-
-       cmd->resp[0] = readl(base + MMCIRESPONSE0);
-       cmd->resp[1] = readl(base + MMCIRESPONSE1);
-       cmd->resp[2] = readl(base + MMCIRESPONSE2);
-       cmd->resp[3] = readl(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) {
-               if (host->data)
-                       mmci_stop_data(host);
-               mmci_request_end(host, cmd->mrq);
-       } else if (!(cmd->data->flags & MMC_DATA_READ)) {
-               mmci_start_data(host, cmd->data);
-       }
-}
-
-static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain)
-{
-       void __iomem *base = host->base;
-       char *ptr = buffer;
-       u32 status;
-
-       do {
-               int count = host->size - (readl(base + MMCIFIFOCNT) << 2);
-
-               if (count > remain)
-                       count = remain;
-
-               if (count <= 0)
-                       break;
-
-               readsl(base + MMCIFIFO, ptr, count >> 2);
-
-               ptr += count;
-               remain -= count;
-
-               if (remain == 0)
-                       break;
-
-               status = readl(base + MMCISTATUS);
-       } while (status & MCI_RXDATAAVLBL);
-
-       return ptr - buffer;
-}
-
-static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status)
-{
-       void __iomem *base = host->base;
-       char *ptr = buffer;
-
-       do {
-               unsigned int count, maxcnt;
-
-               maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
-               count = min(remain, maxcnt);
-
-               writesl(base + MMCIFIFO, ptr, count >> 2);
-
-               ptr += count;
-               remain -= count;
-
-               if (remain == 0)
-                       break;
-
-               status = readl(base + MMCISTATUS);
-       } while (status & MCI_TXFIFOHALFEMPTY);
-
-       return ptr - buffer;
-}
-
-/*
- * PIO data transfer IRQ handler.
- */
-static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
-{
-       struct mmci_host *host = dev_id;
-       void __iomem *base = host->base;
-       u32 status;
-
-       status = readl(base + MMCISTATUS);
-
-       DBG(host, "irq1 %08x\n", status);
-
-       do {
-               unsigned long flags;
-               unsigned int remain, len;
-               char *buffer;
-
-               /*
-                * For write, we only need to test the half-empty flag
-                * here - if the FIFO is completely empty, then by
-                * definition it is more than half empty.
-                *
-                * For read, check for data available.
-                */
-               if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)))
-                       break;
-
-               /*
-                * Map the current scatter buffer.
-                */
-               buffer = mmci_kmap_atomic(host, &flags) + host->sg_off;
-               remain = host->sg_ptr->length - host->sg_off;
-
-               len = 0;
-               if (status & MCI_RXACTIVE)
-                       len = mmci_pio_read(host, buffer, remain);
-               if (status & MCI_TXACTIVE)
-                       len = mmci_pio_write(host, buffer, remain, status);
-
-               /*
-                * Unmap the buffer.
-                */
-               mmci_kunmap_atomic(host, buffer, &flags);
-
-               host->sg_off += len;
-               host->size -= len;
-               remain -= len;
-
-               if (remain)
-                       break;
-
-               /*
-                * If we were reading, and we have completed this
-                * page, ensure that the data cache is coherent.
-                */
-               if (status & MCI_RXACTIVE)
-                       flush_dcache_page(host->sg_ptr->page);
-
-               if (!mmci_next_sg(host))
-                       break;
-
-               status = readl(base + MMCISTATUS);
-       } while (1);
-
-       /*
-        * If we're nearing the end of the read, switch to
-        * "any data available" mode.
-        */
-       if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE)
-               writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
-
-       /*
-        * If we run out of data, disable the data IRQs; this
-        * prevents a race where the FIFO becomes empty before
-        * the chip itself has disabled the data path, and
-        * stops us racing with our data end IRQ.
-        */
-       if (host->size == 0) {
-               writel(0, base + MMCIMASK1);
-               writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0);
-       }
-
-       return IRQ_HANDLED;
-}
-
-/*
- * Handle completion of command and data transfers.
- */
-static irqreturn_t mmci_irq(int irq, void *dev_id)
-{
-       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);
-               status &= readl(host->base + MMCIMASK0);
-               writel(status, host->base + MMCICLEAR);
-
-               DBG(host, "irq0 %08x\n", status);
-
-               data = host->data;
-               if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
-                             MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data)
-                       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 *mrq)
-{
-       struct mmci_host *host = mmc_priv(mmc);
-
-       WARN_ON(host->mrq != NULL);
-
-       spin_lock_irq(&host->lock);
-
-       host->mrq = mrq;
-
-       if (mrq->data && mrq->data->flags & MMC_DATA_READ)
-               mmci_start_data(host, mrq->data);
-
-       mmci_start_command(host, mrq->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;
-
-       if (ios->clock) {
-               if (ios->clock >= host->mclk) {
-                       clk = MCI_CLK_BYPASS;
-                       host->cclk = host->mclk;
-               } else {
-                       clk = host->mclk / (2 * ios->clock) - 1;
-                       if (clk > 256)
-                               clk = 255;
-                       host->cclk = host->mclk / (2 * (clk + 1));
-               }
-               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 const 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, 0);
-
-       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;
-       struct mmc_host *mmc;
-       int ret;
-
-       /* must have platform data */
-       if (!plat) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       ret = amba_request_regions(dev, DRIVER_NAME);
-       if (ret)
-               goto out;
-
-       mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
-       if (!mmc) {
-               ret = -ENOMEM;
-               goto rel_regions;
-       }
-
-       host = mmc_priv(mmc);
-       host->clk = clk_get(&dev->dev, "MCLK");
-       if (IS_ERR(host->clk)) {
-               ret = PTR_ERR(host->clk);
-               host->clk = NULL;
-               goto host_free;
-       }
-
-       ret = clk_enable(host->clk);
-       if (ret)
-               goto clk_free;
-
-       host->plat = plat;
-       host->mclk = clk_get_rate(host->clk);
-       host->mmc = mmc;
-       host->base = ioremap(dev->res.start, SZ_4K);
-       if (!host->base) {
-               ret = -ENOMEM;
-               goto clk_disable;
-       }
-
-       mmc->ops = &mmci_ops;
-       mmc->f_min = (host->mclk + 511) / 512;
-       mmc->f_max = min(host->mclk, fmax);
-       mmc->ocr_avail = plat->ocr_mask;
-       mmc->caps = MMC_CAP_MULTIWRITE;
-
-       /*
-        * We can do SGIO
-        */
-       mmc->max_hw_segs = 16;
-       mmc->max_phys_segs = NR_SG;
-
-       /*
-        * Since we only have a 16-bit data length register, we must
-        * ensure that we don't exceed 2^16-1 bytes in a single request.
-        */
-       mmc->max_req_size = 65535;
-
-       /*
-        * Set the maximum segment size.  Since we aren't doing DMA
-        * (yet) we are only limited by the data length register.
-        */
-       mmc->max_seg_size = mmc->max_req_size;
-
-       /*
-        * Block size can be up to 2048 bytes, but must be a power of two.
-        */
-       mmc->max_blk_size = 2048;
-
-       /*
-        * No limit on the number of blocks transferred.
-        */
-       mmc->max_blk_count = mmc->max_req_size;
-
-       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, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
-       if (ret)
-               goto unmap;
-
-       ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host);
-       if (ret)
-               goto irq0_free;
-
-       writel(MCI_IRQENABLE, host->base + MMCIMASK0);
-
-       amba_set_drvdata(dev, mmc);
-
-       mmc_add_host(mmc);
-
-       printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
-               mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
-               (unsigned long long)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;
-
- irq0_free:
-       free_irq(dev->irq[0], host);
- unmap:
-       iounmap(host->base);
- clk_disable:
-       clk_disable(host->clk);
- clk_free:
-       clk_put(host->clk);
- host_free:
-       mmc_free_host(mmc);
- rel_regions:
-       amba_release_regions(dev);
- out:
-       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);
-               clk_disable(host->clk);
-               clk_put(host->clk);
-
-               mmc_free_host(mmc);
-
-               amba_release_regions(dev);
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int mmci_suspend(struct amba_device *dev, pm_message_t 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 --git a/drivers/mmc/mmci.h b/drivers/mmc/mmci.h
deleted file mode 100644 (file)
index 6d7eadc..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- *  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_CLK_PWRSAVE                (1 << 9)
-#define MCI_CLK_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_IRQENABLE  \
-       (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK|     \
-       MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|       \
-       MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
-
-/*
- * The size of the FIFO in bytes.
- */
-#define MCI_FIFOSIZE   (16*4)
-       
-#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
-
-#define NR_SG          16
-
-struct clk;
-
-struct mmci_host {
-       void __iomem            *base;
-       struct mmc_request      *mrq;
-       struct mmc_command      *cmd;
-       struct mmc_data         *data;
-       struct mmc_host         *mmc;
-       struct clk              *clk;
-
-       unsigned int            data_xfered;
-
-       spinlock_t              lock;
-
-       unsigned int            mclk;
-       unsigned int            cclk;
-       u32                     pwr;
-       struct mmc_platform_data *plat;
-
-       struct timer_list       timer;
-       unsigned int            oldstat;
-
-       unsigned int            sg_len;
-
-       /* pio stuff */
-       struct scatterlist      *sg_ptr;
-       unsigned int            sg_off;
-       unsigned int            size;
-};
-
-static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
-{
-       /*
-        * Ideally, we want the higher levels to pass us a scatter list.
-        */
-       host->sg_len = data->sg_len;
-       host->sg_ptr = data->sg;
-       host->sg_off = 0;
-}
-
-static inline int mmci_next_sg(struct mmci_host *host)
-{
-       host->sg_ptr++;
-       host->sg_off = 0;
-       return --host->sg_len;
-}
-
-static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags)
-{
-       struct scatterlist *sg = host->sg_ptr;
-
-       local_irq_save(*flags);
-       return kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
-}
-
-static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags)
-{
-       kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
-       local_irq_restore(*flags);
-}
diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c
deleted file mode 100644 (file)
index e851384..0000000
+++ /dev/null
@@ -1,1288 +0,0 @@
-/*
- *  linux/drivers/media/mmc/omap.c
- *
- *  Copyright (C) 2004 Nokia Corporation
- *  Written by Tuukka Tikkanen and Juha Yrjölä<juha.yrjola@nokia.com>
- *  Misc hacks here and there by Tony Lindgren <tony@atomide.com>
- *  Other hacks (DMA, SD, etc) by David Brownell
- *
- * 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/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/clk.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/scatterlist.h>
-#include <asm/mach-types.h>
-
-#include <asm/arch/board.h>
-#include <asm/arch/gpio.h>
-#include <asm/arch/dma.h>
-#include <asm/arch/mux.h>
-#include <asm/arch/fpga.h>
-#include <asm/arch/tps65010.h>
-
-#define        OMAP_MMC_REG_CMD        0x00
-#define        OMAP_MMC_REG_ARGL       0x04
-#define        OMAP_MMC_REG_ARGH       0x08
-#define        OMAP_MMC_REG_CON        0x0c
-#define        OMAP_MMC_REG_STAT       0x10
-#define        OMAP_MMC_REG_IE         0x14
-#define        OMAP_MMC_REG_CTO        0x18
-#define        OMAP_MMC_REG_DTO        0x1c
-#define        OMAP_MMC_REG_DATA       0x20
-#define        OMAP_MMC_REG_BLEN       0x24
-#define        OMAP_MMC_REG_NBLK       0x28
-#define        OMAP_MMC_REG_BUF        0x2c
-#define OMAP_MMC_REG_SDIO      0x34
-#define        OMAP_MMC_REG_REV        0x3c
-#define        OMAP_MMC_REG_RSP0       0x40
-#define        OMAP_MMC_REG_RSP1       0x44
-#define        OMAP_MMC_REG_RSP2       0x48
-#define        OMAP_MMC_REG_RSP3       0x4c
-#define        OMAP_MMC_REG_RSP4       0x50
-#define        OMAP_MMC_REG_RSP5       0x54
-#define        OMAP_MMC_REG_RSP6       0x58
-#define        OMAP_MMC_REG_RSP7       0x5c
-#define        OMAP_MMC_REG_IOSR       0x60
-#define        OMAP_MMC_REG_SYSC       0x64
-#define        OMAP_MMC_REG_SYSS       0x68
-
-#define        OMAP_MMC_STAT_CARD_ERR          (1 << 14)
-#define        OMAP_MMC_STAT_CARD_IRQ          (1 << 13)
-#define        OMAP_MMC_STAT_OCR_BUSY          (1 << 12)
-#define        OMAP_MMC_STAT_A_EMPTY           (1 << 11)
-#define        OMAP_MMC_STAT_A_FULL            (1 << 10)
-#define        OMAP_MMC_STAT_CMD_CRC           (1 <<  8)
-#define        OMAP_MMC_STAT_CMD_TOUT          (1 <<  7)
-#define        OMAP_MMC_STAT_DATA_CRC          (1 <<  6)
-#define        OMAP_MMC_STAT_DATA_TOUT         (1 <<  5)
-#define        OMAP_MMC_STAT_END_BUSY          (1 <<  4)
-#define        OMAP_MMC_STAT_END_OF_DATA       (1 <<  3)
-#define        OMAP_MMC_STAT_CARD_BUSY         (1 <<  2)
-#define        OMAP_MMC_STAT_END_OF_CMD        (1 <<  0)
-
-#define OMAP_MMC_READ(host, reg)       __raw_readw((host)->virt_base + OMAP_MMC_REG_##reg)
-#define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG_##reg)
-
-/*
- * Command types
- */
-#define OMAP_MMC_CMDTYPE_BC    0
-#define OMAP_MMC_CMDTYPE_BCR   1
-#define OMAP_MMC_CMDTYPE_AC    2
-#define OMAP_MMC_CMDTYPE_ADTC  3
-
-
-#define DRIVER_NAME "mmci-omap"
-
-/* Specifies how often in millisecs to poll for card status changes
- * when the cover switch is open */
-#define OMAP_MMC_SWITCH_POLL_DELAY     500
-
-static int mmc_omap_enable_poll = 1;
-
-struct mmc_omap_host {
-       int                     initialized;
-       int                     suspended;
-       struct mmc_request *    mrq;
-       struct mmc_command *    cmd;
-       struct mmc_data *       data;
-       struct mmc_host *       mmc;
-       struct device *         dev;
-       unsigned char           id; /* 16xx chips have 2 MMC blocks */
-       struct clk *            iclk;
-       struct clk *            fclk;
-       struct resource         *mem_res;
-       void __iomem            *virt_base;
-       unsigned int            phys_base;
-       int                     irq;
-       unsigned char           bus_mode;
-       unsigned char           hw_bus_mode;
-
-       unsigned int            sg_len;
-       int                     sg_idx;
-       u16 *                   buffer;
-       u32                     buffer_bytes_left;
-       u32                     total_bytes_left;
-
-       unsigned                use_dma:1;
-       unsigned                brs_received:1, dma_done:1;
-       unsigned                dma_is_read:1;
-       unsigned                dma_in_use:1;
-       int                     dma_ch;
-       spinlock_t              dma_lock;
-       struct timer_list       dma_timer;
-       unsigned                dma_len;
-
-       short                   power_pin;
-       short                   wp_pin;
-
-       int                     switch_pin;
-       struct work_struct      switch_work;
-       struct timer_list       switch_timer;
-       int                     switch_last_state;
-};
-
-static inline int
-mmc_omap_cover_is_open(struct mmc_omap_host *host)
-{
-       if (host->switch_pin < 0)
-               return 0;
-       return omap_get_gpio_datain(host->switch_pin);
-}
-
-static ssize_t
-mmc_omap_show_cover_switch(struct device *dev,
-       struct device_attribute *attr, char *buf)
-{
-       struct mmc_omap_host *host = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%s\n", mmc_omap_cover_is_open(host) ? "open" :
-                       "closed");
-}
-
-static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);
-
-static ssize_t
-mmc_omap_show_enable_poll(struct device *dev,
-       struct device_attribute *attr, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%d\n", mmc_omap_enable_poll);
-}
-
-static ssize_t
-mmc_omap_store_enable_poll(struct device *dev,
-       struct device_attribute *attr, const char *buf,
-       size_t size)
-{
-       int enable_poll;
-
-       if (sscanf(buf, "%10d", &enable_poll) != 1)
-               return -EINVAL;
-
-       if (enable_poll != mmc_omap_enable_poll) {
-               struct mmc_omap_host *host = dev_get_drvdata(dev);
-
-               mmc_omap_enable_poll = enable_poll;
-               if (enable_poll && host->switch_pin >= 0)
-                       schedule_work(&host->switch_work);
-       }
-       return size;
-}
-
-static DEVICE_ATTR(enable_poll, 0664,
-                  mmc_omap_show_enable_poll, mmc_omap_store_enable_poll);
-
-static void
-mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
-{
-       u32 cmdreg;
-       u32 resptype;
-       u32 cmdtype;
-
-       host->cmd = cmd;
-
-       resptype = 0;
-       cmdtype = 0;
-
-       /* Our hardware needs to know exact type */
-       switch (mmc_resp_type(cmd)) {
-       case MMC_RSP_NONE:
-               break;
-       case MMC_RSP_R1:
-       case MMC_RSP_R1B:
-               /* resp 1, 1b, 6, 7 */
-               resptype = 1;
-               break;
-       case MMC_RSP_R2:
-               resptype = 2;
-               break;
-       case MMC_RSP_R3:
-               resptype = 3;
-               break;
-       default:
-               dev_err(mmc_dev(host->mmc), "Invalid response type: %04x\n", mmc_resp_type(cmd));
-               break;
-       }
-
-       if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) {
-               cmdtype = OMAP_MMC_CMDTYPE_ADTC;
-       } else if (mmc_cmd_type(cmd) == MMC_CMD_BC) {
-               cmdtype = OMAP_MMC_CMDTYPE_BC;
-       } else if (mmc_cmd_type(cmd) == MMC_CMD_BCR) {
-               cmdtype = OMAP_MMC_CMDTYPE_BCR;
-       } else {
-               cmdtype = OMAP_MMC_CMDTYPE_AC;
-       }
-
-       cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12);
-
-       if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
-               cmdreg |= 1 << 6;
-
-       if (cmd->flags & MMC_RSP_BUSY)
-               cmdreg |= 1 << 11;
-
-       if (host->data && !(host->data->flags & MMC_DATA_WRITE))
-               cmdreg |= 1 << 15;
-
-       clk_enable(host->fclk);
-
-       OMAP_MMC_WRITE(host, CTO, 200);
-       OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
-       OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16);
-       OMAP_MMC_WRITE(host, IE,
-                      OMAP_MMC_STAT_A_EMPTY    | OMAP_MMC_STAT_A_FULL    |
-                      OMAP_MMC_STAT_CMD_CRC    | OMAP_MMC_STAT_CMD_TOUT  |
-                      OMAP_MMC_STAT_DATA_CRC   | OMAP_MMC_STAT_DATA_TOUT |
-                      OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR  |
-                      OMAP_MMC_STAT_END_OF_DATA);
-       OMAP_MMC_WRITE(host, CMD, cmdreg);
-}
-
-static void
-mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
-{
-       if (host->dma_in_use) {
-               enum dma_data_direction dma_data_dir;
-
-               BUG_ON(host->dma_ch < 0);
-               if (data->error != MMC_ERR_NONE)
-                       omap_stop_dma(host->dma_ch);
-               /* Release DMA channel lazily */
-               mod_timer(&host->dma_timer, jiffies + HZ);
-               if (data->flags & MMC_DATA_WRITE)
-                       dma_data_dir = DMA_TO_DEVICE;
-               else
-                       dma_data_dir = DMA_FROM_DEVICE;
-               dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
-                            dma_data_dir);
-       }
-       host->data = NULL;
-       host->sg_len = 0;
-       clk_disable(host->fclk);
-
-       /* NOTE:  MMC layer will sometimes poll-wait CMD13 next, issuing
-        * dozens of requests until the card finishes writing data.
-        * It'd be cheaper to just wait till an EOFB interrupt arrives...
-        */
-
-       if (!data->stop) {
-               host->mrq = NULL;
-               mmc_request_done(host->mmc, data->mrq);
-               return;
-       }
-
-       mmc_omap_start_command(host, data->stop);
-}
-
-static void
-mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data)
-{
-       unsigned long flags;
-       int done;
-
-       if (!host->dma_in_use) {
-               mmc_omap_xfer_done(host, data);
-               return;
-       }
-       done = 0;
-       spin_lock_irqsave(&host->dma_lock, flags);
-       if (host->dma_done)
-               done = 1;
-       else
-               host->brs_received = 1;
-       spin_unlock_irqrestore(&host->dma_lock, flags);
-       if (done)
-               mmc_omap_xfer_done(host, data);
-}
-
-static void
-mmc_omap_dma_timer(unsigned long data)
-{
-       struct mmc_omap_host *host = (struct mmc_omap_host *) data;
-
-       BUG_ON(host->dma_ch < 0);
-       omap_free_dma(host->dma_ch);
-       host->dma_ch = -1;
-}
-
-static void
-mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data)
-{
-       unsigned long flags;
-       int done;
-
-       done = 0;
-       spin_lock_irqsave(&host->dma_lock, flags);
-       if (host->brs_received)
-               done = 1;
-       else
-               host->dma_done = 1;
-       spin_unlock_irqrestore(&host->dma_lock, flags);
-       if (done)
-               mmc_omap_xfer_done(host, data);
-}
-
-static void
-mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
-{
-       host->cmd = NULL;
-
-       if (cmd->flags & MMC_RSP_PRESENT) {
-               if (cmd->flags & MMC_RSP_136) {
-                       /* response type 2 */
-                       cmd->resp[3] =
-                               OMAP_MMC_READ(host, RSP0) |
-                               (OMAP_MMC_READ(host, RSP1) << 16);
-                       cmd->resp[2] =
-                               OMAP_MMC_READ(host, RSP2) |
-                               (OMAP_MMC_READ(host, RSP3) << 16);
-                       cmd->resp[1] =
-                               OMAP_MMC_READ(host, RSP4) |
-                               (OMAP_MMC_READ(host, RSP5) << 16);
-                       cmd->resp[0] =
-                               OMAP_MMC_READ(host, RSP6) |
-                               (OMAP_MMC_READ(host, RSP7) << 16);
-               } else {
-                       /* response types 1, 1b, 3, 4, 5, 6 */
-                       cmd->resp[0] =
-                               OMAP_MMC_READ(host, RSP6) |
-                               (OMAP_MMC_READ(host, RSP7) << 16);
-               }
-       }
-
-       if (host->data == NULL || cmd->error != MMC_ERR_NONE) {
-               host->mrq = NULL;
-               clk_disable(host->fclk);
-               mmc_request_done(host->mmc, cmd->mrq);
-       }
-}
-
-/* PIO only */
-static void
-mmc_omap_sg_to_buf(struct mmc_omap_host *host)
-{
-       struct scatterlist *sg;
-
-       sg = host->data->sg + host->sg_idx;
-       host->buffer_bytes_left = sg->length;
-       host->buffer = page_address(sg->page) + sg->offset;
-       if (host->buffer_bytes_left > host->total_bytes_left)
-               host->buffer_bytes_left = host->total_bytes_left;
-}
-
-/* PIO only */
-static void
-mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
-{
-       int n;
-
-       if (host->buffer_bytes_left == 0) {
-               host->sg_idx++;
-               BUG_ON(host->sg_idx == host->sg_len);
-               mmc_omap_sg_to_buf(host);
-       }
-       n = 64;
-       if (n > host->buffer_bytes_left)
-               n = host->buffer_bytes_left;
-       host->buffer_bytes_left -= n;
-       host->total_bytes_left -= n;
-       host->data->bytes_xfered += n;
-
-       if (write) {
-               __raw_writesw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
-       } else {
-               __raw_readsw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
-       }
-}
-
-static inline void mmc_omap_report_irq(u16 status)
-{
-       static const char *mmc_omap_status_bits[] = {
-               "EOC", "CD", "CB", "BRS", "EOFB", "DTO", "DCRC", "CTO",
-               "CCRC", "CRW", "AF", "AE", "OCRB", "CIRQ", "CERR"
-       };
-       int i, c = 0;
-
-       for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++)
-               if (status & (1 << i)) {
-                       if (c)
-                               printk(" ");
-                       printk("%s", mmc_omap_status_bits[i]);
-                       c++;
-               }
-}
-
-static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
-{
-       struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id;
-       u16 status;
-       int end_command;
-       int end_transfer;
-       int transfer_error;
-
-       if (host->cmd == NULL && host->data == NULL) {
-               status = OMAP_MMC_READ(host, STAT);
-               dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status);
-               if (status != 0) {
-                       OMAP_MMC_WRITE(host, STAT, status);
-                       OMAP_MMC_WRITE(host, IE, 0);
-               }
-               return IRQ_HANDLED;
-       }
-
-       end_command = 0;
-       end_transfer = 0;
-       transfer_error = 0;
-
-       while ((status = OMAP_MMC_READ(host, STAT)) != 0) {
-               OMAP_MMC_WRITE(host, STAT, status);
-#ifdef CONFIG_MMC_DEBUG
-               dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ",
-                       status, host->cmd != NULL ? host->cmd->opcode : -1);
-               mmc_omap_report_irq(status);
-               printk("\n");
-#endif
-               if (host->total_bytes_left) {
-                       if ((status & OMAP_MMC_STAT_A_FULL) ||
-                           (status & OMAP_MMC_STAT_END_OF_DATA))
-                               mmc_omap_xfer_data(host, 0);
-                       if (status & OMAP_MMC_STAT_A_EMPTY)
-                               mmc_omap_xfer_data(host, 1);
-               }
-
-               if (status & OMAP_MMC_STAT_END_OF_DATA) {
-                       end_transfer = 1;
-               }
-
-               if (status & OMAP_MMC_STAT_DATA_TOUT) {
-                       dev_dbg(mmc_dev(host->mmc), "data timeout\n");
-                       if (host->data) {
-                               host->data->error |= MMC_ERR_TIMEOUT;
-                               transfer_error = 1;
-                       }
-               }
-
-               if (status & OMAP_MMC_STAT_DATA_CRC) {
-                       if (host->data) {
-                               host->data->error |= MMC_ERR_BADCRC;
-                               dev_dbg(mmc_dev(host->mmc),
-                                        "data CRC error, bytes left %d\n",
-                                       host->total_bytes_left);
-                               transfer_error = 1;
-                       } else {
-                               dev_dbg(mmc_dev(host->mmc), "data CRC error\n");
-                       }
-               }
-
-               if (status & OMAP_MMC_STAT_CMD_TOUT) {
-                       /* Timeouts are routine with some commands */
-                       if (host->cmd) {
-                               if (host->cmd->opcode != MMC_ALL_SEND_CID &&
-                                               host->cmd->opcode !=
-                                               MMC_SEND_OP_COND &&
-                                               host->cmd->opcode !=
-                                               MMC_APP_CMD &&
-                                               !mmc_omap_cover_is_open(host))
-                                       dev_err(mmc_dev(host->mmc),
-                                               "command timeout, CMD %d\n",
-                                               host->cmd->opcode);
-                               host->cmd->error = MMC_ERR_TIMEOUT;
-                               end_command = 1;
-                       }
-               }
-
-               if (status & OMAP_MMC_STAT_CMD_CRC) {
-                       if (host->cmd) {
-                               dev_err(mmc_dev(host->mmc),
-                                       "command CRC error (CMD%d, arg 0x%08x)\n",
-                                       host->cmd->opcode, host->cmd->arg);
-                               host->cmd->error = MMC_ERR_BADCRC;
-                               end_command = 1;
-                       } else
-                               dev_err(mmc_dev(host->mmc),
-                                       "command CRC error without cmd?\n");
-               }
-
-               if (status & OMAP_MMC_STAT_CARD_ERR) {
-                       if (host->cmd && host->cmd->opcode == MMC_STOP_TRANSMISSION) {
-                               u32 response = OMAP_MMC_READ(host, RSP6)
-                                       | (OMAP_MMC_READ(host, RSP7) << 16);
-                               /* STOP sometimes sets must-ignore bits */
-                               if (!(response & (R1_CC_ERROR
-                                                               | R1_ILLEGAL_COMMAND
-                                                               | R1_COM_CRC_ERROR))) {
-                                       end_command = 1;
-                                       continue;
-                               }
-                       }
-
-                       dev_dbg(mmc_dev(host->mmc), "card status error (CMD%d)\n",
-                               host->cmd->opcode);
-                       if (host->cmd) {
-                               host->cmd->error = MMC_ERR_FAILED;
-                               end_command = 1;
-                       }
-                       if (host->data) {
-                               host->data->error = MMC_ERR_FAILED;
-                               transfer_error = 1;
-                       }
-               }
-
-               /*
-                * NOTE: On 1610 the END_OF_CMD may come too early when
-                * starting a write 
-                */
-               if ((status & OMAP_MMC_STAT_END_OF_CMD) &&
-                   (!(status & OMAP_MMC_STAT_A_EMPTY))) {
-                       end_command = 1;
-               }
-       }
-
-       if (end_command) {
-               mmc_omap_cmd_done(host, host->cmd);
-       }
-       if (transfer_error)
-               mmc_omap_xfer_done(host, host->data);
-       else if (end_transfer)
-               mmc_omap_end_of_data(host, host->data);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id)
-{
-       struct mmc_omap_host *host = (struct mmc_omap_host *) dev_id;
-
-       schedule_work(&host->switch_work);
-
-       return IRQ_HANDLED;
-}
-
-static void mmc_omap_switch_timer(unsigned long arg)
-{
-       struct mmc_omap_host *host = (struct mmc_omap_host *) arg;
-
-       schedule_work(&host->switch_work);
-}
-
-static void mmc_omap_switch_handler(struct work_struct *work)
-{
-       struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, switch_work);
-       struct mmc_card *card;
-       static int complained = 0;
-       int cards = 0, cover_open;
-
-       if (host->switch_pin == -1)
-               return;
-       cover_open = mmc_omap_cover_is_open(host);
-       if (cover_open != host->switch_last_state) {
-               kobject_uevent(&host->dev->kobj, KOBJ_CHANGE);
-               host->switch_last_state = cover_open;
-       }
-       mmc_detect_change(host->mmc, 0);
-       list_for_each_entry(card, &host->mmc->cards, node) {
-               if (mmc_card_present(card))
-                       cards++;
-       }
-       if (mmc_omap_cover_is_open(host)) {
-               if (!complained) {
-                       dev_info(mmc_dev(host->mmc), "cover is open");
-                       complained = 1;
-               }
-               if (mmc_omap_enable_poll)
-                       mod_timer(&host->switch_timer, jiffies +
-                               msecs_to_jiffies(OMAP_MMC_SWITCH_POLL_DELAY));
-       } else {
-               complained = 0;
-       }
-}
-
-/* Prepare to transfer the next segment of a scatterlist */
-static void
-mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
-{
-       int dma_ch = host->dma_ch;
-       unsigned long data_addr;
-       u16 buf, frame;
-       u32 count;
-       struct scatterlist *sg = &data->sg[host->sg_idx];
-       int src_port = 0;
-       int dst_port = 0;
-       int sync_dev = 0;
-
-       data_addr = host->phys_base + OMAP_MMC_REG_DATA;
-       frame = data->blksz;
-       count = sg_dma_len(sg);
-
-       if ((data->blocks == 1) && (count > data->blksz))
-               count = frame;
-
-       host->dma_len = count;
-
-       /* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx.
-        * Use 16 or 32 word frames when the blocksize is at least that large.
-        * Blocksize is usually 512 bytes; but not for some SD reads.
-        */
-       if (cpu_is_omap15xx() && frame > 32)
-               frame = 32;
-       else if (frame > 64)
-               frame = 64;
-       count /= frame;
-       frame >>= 1;
-
-       if (!(data->flags & MMC_DATA_WRITE)) {
-               buf = 0x800f | ((frame - 1) << 8);
-
-               if (cpu_class_is_omap1()) {
-                       src_port = OMAP_DMA_PORT_TIPB;
-                       dst_port = OMAP_DMA_PORT_EMIFF;
-               }
-               if (cpu_is_omap24xx())
-                       sync_dev = OMAP24XX_DMA_MMC1_RX;
-
-               omap_set_dma_src_params(dma_ch, src_port,
-                                       OMAP_DMA_AMODE_CONSTANT,
-                                       data_addr, 0, 0);
-               omap_set_dma_dest_params(dma_ch, dst_port,
-                                        OMAP_DMA_AMODE_POST_INC,
-                                        sg_dma_address(sg), 0, 0);
-               omap_set_dma_dest_data_pack(dma_ch, 1);
-               omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
-       } else {
-               buf = 0x0f80 | ((frame - 1) << 0);
-
-               if (cpu_class_is_omap1()) {
-                       src_port = OMAP_DMA_PORT_EMIFF;
-                       dst_port = OMAP_DMA_PORT_TIPB;
-               }
-               if (cpu_is_omap24xx())
-                       sync_dev = OMAP24XX_DMA_MMC1_TX;
-
-               omap_set_dma_dest_params(dma_ch, dst_port,
-                                        OMAP_DMA_AMODE_CONSTANT,
-                                        data_addr, 0, 0);
-               omap_set_dma_src_params(dma_ch, src_port,
-                                       OMAP_DMA_AMODE_POST_INC,
-                                       sg_dma_address(sg), 0, 0);
-               omap_set_dma_src_data_pack(dma_ch, 1);
-               omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
-       }
-
-       /* Max limit for DMA frame count is 0xffff */
-       BUG_ON(count > 0xffff);
-
-       OMAP_MMC_WRITE(host, BUF, buf);
-       omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16,
-                                    frame, count, OMAP_DMA_SYNC_FRAME,
-                                    sync_dev, 0);
-}
-
-/* A scatterlist segment completed */
-static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
-{
-       struct mmc_omap_host *host = (struct mmc_omap_host *) data;
-       struct mmc_data *mmcdat = host->data;
-
-       if (unlikely(host->dma_ch < 0)) {
-               dev_err(mmc_dev(host->mmc),
-                       "DMA callback while DMA not enabled\n");
-               return;
-       }
-       /* FIXME: We really should do something to _handle_ the errors */
-       if (ch_status & OMAP1_DMA_TOUT_IRQ) {
-               dev_err(mmc_dev(host->mmc),"DMA timeout\n");
-               return;
-       }
-       if (ch_status & OMAP_DMA_DROP_IRQ) {
-               dev_err(mmc_dev(host->mmc), "DMA sync error\n");
-               return;
-       }
-       if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) {
-               return;
-       }
-       mmcdat->bytes_xfered += host->dma_len;
-       host->sg_idx++;
-       if (host->sg_idx < host->sg_len) {
-               mmc_omap_prepare_dma(host, host->data);
-               omap_start_dma(host->dma_ch);
-       } else
-               mmc_omap_dma_done(host, host->data);
-}
-
-static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data)
-{
-       const char *dev_name;
-       int sync_dev, dma_ch, is_read, r;
-
-       is_read = !(data->flags & MMC_DATA_WRITE);
-       del_timer_sync(&host->dma_timer);
-       if (host->dma_ch >= 0) {
-               if (is_read == host->dma_is_read)
-                       return 0;
-               omap_free_dma(host->dma_ch);
-               host->dma_ch = -1;
-       }
-
-       if (is_read) {
-               if (host->id == 1) {
-                       sync_dev = OMAP_DMA_MMC_RX;
-                       dev_name = "MMC1 read";
-               } else {
-                       sync_dev = OMAP_DMA_MMC2_RX;
-                       dev_name = "MMC2 read";
-               }
-       } else {
-               if (host->id == 1) {
-                       sync_dev = OMAP_DMA_MMC_TX;
-                       dev_name = "MMC1 write";
-               } else {
-                       sync_dev = OMAP_DMA_MMC2_TX;
-                       dev_name = "MMC2 write";
-               }
-       }
-       r = omap_request_dma(sync_dev, dev_name, mmc_omap_dma_cb,
-                            host, &dma_ch);
-       if (r != 0) {
-               dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r);
-               return r;
-       }
-       host->dma_ch = dma_ch;
-       host->dma_is_read = is_read;
-
-       return 0;
-}
-
-static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req)
-{
-       u16 reg;
-
-       reg = OMAP_MMC_READ(host, SDIO);
-       reg &= ~(1 << 5);
-       OMAP_MMC_WRITE(host, SDIO, reg);
-       /* Set maximum timeout */
-       OMAP_MMC_WRITE(host, CTO, 0xff);
-}
-
-static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req)
-{
-       int timeout;
-       u16 reg;
-
-       /* Convert ns to clock cycles by assuming 20MHz frequency
-        * 1 cycle at 20MHz = 500 ns
-        */
-       timeout = req->data->timeout_clks + req->data->timeout_ns / 500;
-
-       /* Check if we need to use timeout multiplier register */
-       reg = OMAP_MMC_READ(host, SDIO);
-       if (timeout > 0xffff) {
-               reg |= (1 << 5);
-               timeout /= 1024;
-       } else
-               reg &= ~(1 << 5);
-       OMAP_MMC_WRITE(host, SDIO, reg);
-       OMAP_MMC_WRITE(host, DTO, timeout);
-}
-
-static void
-mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
-{
-       struct mmc_data *data = req->data;
-       int i, use_dma, block_size;
-       unsigned sg_len;
-
-       host->data = data;
-       if (data == NULL) {
-               OMAP_MMC_WRITE(host, BLEN, 0);
-               OMAP_MMC_WRITE(host, NBLK, 0);
-               OMAP_MMC_WRITE(host, BUF, 0);
-               host->dma_in_use = 0;
-               set_cmd_timeout(host, req);
-               return;
-       }
-
-       block_size = data->blksz;
-
-       OMAP_MMC_WRITE(host, NBLK, data->blocks - 1);
-       OMAP_MMC_WRITE(host, BLEN, block_size - 1);
-       set_data_timeout(host, req);
-
-       /* cope with calling layer confusion; it issues "single
-        * block" writes using multi-block scatterlists.
-        */
-       sg_len = (data->blocks == 1) ? 1 : data->sg_len;
-
-       /* Only do DMA for entire blocks */
-       use_dma = host->use_dma;
-       if (use_dma) {
-               for (i = 0; i < sg_len; i++) {
-                       if ((data->sg[i].length % block_size) != 0) {
-                               use_dma = 0;
-                               break;
-                       }
-               }
-       }
-
-       host->sg_idx = 0;
-       if (use_dma) {
-               if (mmc_omap_get_dma_channel(host, data) == 0) {
-                       enum dma_data_direction dma_data_dir;
-
-                       if (data->flags & MMC_DATA_WRITE)
-                               dma_data_dir = DMA_TO_DEVICE;
-                       else
-                               dma_data_dir = DMA_FROM_DEVICE;
-
-                       host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
-                                               sg_len, dma_data_dir);
-                       host->total_bytes_left = 0;
-                       mmc_omap_prepare_dma(host, req->data);
-                       host->brs_received = 0;
-                       host->dma_done = 0;
-                       host->dma_in_use = 1;
-               } else
-                       use_dma = 0;
-       }
-
-       /* Revert to PIO? */
-       if (!use_dma) {
-               OMAP_MMC_WRITE(host, BUF, 0x1f1f);
-               host->total_bytes_left = data->blocks * block_size;
-               host->sg_len = sg_len;
-               mmc_omap_sg_to_buf(host);
-               host->dma_in_use = 0;
-       }
-}
-
-static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req)
-{
-       struct mmc_omap_host *host = mmc_priv(mmc);
-
-       WARN_ON(host->mrq != NULL);
-
-       host->mrq = req;
-
-       /* only touch fifo AFTER the controller readies it */
-       mmc_omap_prepare_data(host, req);
-       mmc_omap_start_command(host, req->cmd);
-       if (host->dma_in_use)
-               omap_start_dma(host->dma_ch);
-}
-
-static void innovator_fpga_socket_power(int on)
-{
-#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX)
-       if (on) {
-               fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3),
-                    OMAP1510_FPGA_POWER);
-       } else {
-               fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~(1 << 3),
-                    OMAP1510_FPGA_POWER);
-       }
-#endif
-}
-
-/*
- * Turn the socket power on/off. Innovator uses FPGA, most boards
- * probably use GPIO.
- */
-static void mmc_omap_power(struct mmc_omap_host *host, int on)
-{
-       if (on) {
-               if (machine_is_omap_innovator())
-                       innovator_fpga_socket_power(1);
-               else if (machine_is_omap_h2())
-                       tps65010_set_gpio_out_value(GPIO3, HIGH);
-               else if (machine_is_omap_h3())
-                       /* GPIO 4 of TPS65010 sends SD_EN signal */
-                       tps65010_set_gpio_out_value(GPIO4, HIGH);
-               else if (cpu_is_omap24xx()) {
-                       u16 reg = OMAP_MMC_READ(host, CON);
-                       OMAP_MMC_WRITE(host, CON, reg | (1 << 11));
-               } else
-                       if (host->power_pin >= 0)
-                               omap_set_gpio_dataout(host->power_pin, 1);
-       } else {
-               if (machine_is_omap_innovator())
-                       innovator_fpga_socket_power(0);
-               else if (machine_is_omap_h2())
-                       tps65010_set_gpio_out_value(GPIO3, LOW);
-               else if (machine_is_omap_h3())
-                       tps65010_set_gpio_out_value(GPIO4, LOW);
-               else if (cpu_is_omap24xx()) {
-                       u16 reg = OMAP_MMC_READ(host, CON);
-                       OMAP_MMC_WRITE(host, CON, reg & ~(1 << 11));
-               } else
-                       if (host->power_pin >= 0)
-                               omap_set_gpio_dataout(host->power_pin, 0);
-       }
-}
-
-static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-       struct mmc_omap_host *host = mmc_priv(mmc);
-       int dsor;
-       int realclock, i;
-
-       realclock = ios->clock;
-
-       if (ios->clock == 0)
-               dsor = 0;
-       else {
-               int func_clk_rate = clk_get_rate(host->fclk);
-
-               dsor = func_clk_rate / realclock;
-               if (dsor < 1)
-                       dsor = 1;
-
-               if (func_clk_rate / dsor > realclock)
-                       dsor++;
-
-               if (dsor > 250)
-                       dsor = 250;
-               dsor++;
-
-               if (ios->bus_width == MMC_BUS_WIDTH_4)
-                       dsor |= 1 << 15;
-       }
-
-       switch (ios->power_mode) {
-       case MMC_POWER_OFF:
-               mmc_omap_power(host, 0);
-               break;
-       case MMC_POWER_UP:
-       case MMC_POWER_ON:
-               mmc_omap_power(host, 1);
-               dsor |= 1 << 11;
-               break;
-       }
-
-       host->bus_mode = ios->bus_mode;
-       host->hw_bus_mode = host->bus_mode;
-
-       clk_enable(host->fclk);
-
-       /* On insanely high arm_per frequencies something sometimes
-        * goes somehow out of sync, and the POW bit is not being set,
-        * which results in the while loop below getting stuck.
-        * Writing to the CON register twice seems to do the trick. */
-       for (i = 0; i < 2; i++)
-               OMAP_MMC_WRITE(host, CON, dsor);
-       if (ios->power_mode == MMC_POWER_UP) {
-               /* Send clock cycles, poll completion */
-               OMAP_MMC_WRITE(host, IE, 0);
-               OMAP_MMC_WRITE(host, STAT, 0xffff);
-               OMAP_MMC_WRITE(host, CMD, 1 << 7);
-               while ((OMAP_MMC_READ(host, STAT) & 1) == 0);
-               OMAP_MMC_WRITE(host, STAT, 1);
-       }
-       clk_disable(host->fclk);
-}
-
-static int mmc_omap_get_ro(struct mmc_host *mmc)
-{
-       struct mmc_omap_host *host = mmc_priv(mmc);
-
-       return host->wp_pin && omap_get_gpio_datain(host->wp_pin);
-}
-
-static const struct mmc_host_ops mmc_omap_ops = {
-       .request        = mmc_omap_request,
-       .set_ios        = mmc_omap_set_ios,
-       .get_ro         = mmc_omap_get_ro,
-};
-
-static int __init mmc_omap_probe(struct platform_device *pdev)
-{
-       struct omap_mmc_conf *minfo = pdev->dev.platform_data;
-       struct mmc_host *mmc;
-       struct mmc_omap_host *host = NULL;
-       struct resource *res;
-       int ret = 0;
-       int irq;
-
-       if (minfo == NULL) {
-               dev_err(&pdev->dev, "platform data missing\n");
-               return -ENXIO;
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       irq = platform_get_irq(pdev, 0);
-       if (res == NULL || irq < 0)
-               return -ENXIO;
-
-       res = request_mem_region(res->start, res->end - res->start + 1,
-                                pdev->name);
-       if (res == NULL)
-               return -EBUSY;
-
-       mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev);
-       if (mmc == NULL) {
-               ret = -ENOMEM;
-               goto err_free_mem_region;
-       }
-
-       host = mmc_priv(mmc);
-       host->mmc = mmc;
-
-       spin_lock_init(&host->dma_lock);
-       init_timer(&host->dma_timer);
-       host->dma_timer.function = mmc_omap_dma_timer;
-       host->dma_timer.data = (unsigned long) host;
-
-       host->id = pdev->id;
-       host->mem_res = res;
-       host->irq = irq;
-
-       if (cpu_is_omap24xx()) {
-               host->iclk = clk_get(&pdev->dev, "mmc_ick");
-               if (IS_ERR(host->iclk))
-                       goto err_free_mmc_host;
-               clk_enable(host->iclk);
-       }
-
-       if (!cpu_is_omap24xx())
-               host->fclk = clk_get(&pdev->dev, "mmc_ck");
-       else
-               host->fclk = clk_get(&pdev->dev, "mmc_fck");
-
-       if (IS_ERR(host->fclk)) {
-               ret = PTR_ERR(host->fclk);
-               goto err_free_iclk;
-       }
-
-       /* REVISIT:
-        * Also, use minfo->cover to decide how to manage
-        * the card detect sensing.
-        */
-       host->power_pin = minfo->power_pin;
-       host->switch_pin = minfo->switch_pin;
-       host->wp_pin = minfo->wp_pin;
-       host->use_dma = 1;
-       host->dma_ch = -1;
-
-       host->irq = irq;
-       host->phys_base = host->mem_res->start;
-       host->virt_base = (void __iomem *) IO_ADDRESS(host->phys_base);
-
-       mmc->ops = &mmc_omap_ops;
-       mmc->f_min = 400000;
-       mmc->f_max = 24000000;
-       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->caps = MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
-
-       if (minfo->wire4)
-                mmc->caps |= MMC_CAP_4_BIT_DATA;
-
-       /* Use scatterlist DMA to reduce per-transfer costs.
-        * NOTE max_seg_size assumption that small blocks aren't
-        * normally used (except e.g. for reading SD registers).
-        */
-       mmc->max_phys_segs = 32;
-       mmc->max_hw_segs = 32;
-       mmc->max_blk_size = 2048;       /* BLEN is 11 bits (+1) */
-       mmc->max_blk_count = 2048;      /* NBLK is 11 bits (+1) */
-       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
-       mmc->max_seg_size = mmc->max_req_size;
-
-       if (host->power_pin >= 0) {
-               if ((ret = omap_request_gpio(host->power_pin)) != 0) {
-                       dev_err(mmc_dev(host->mmc),
-                               "Unable to get GPIO pin for MMC power\n");
-                       goto err_free_fclk;
-               }
-               omap_set_gpio_direction(host->power_pin, 0);
-       }
-
-       ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
-       if (ret)
-               goto err_free_power_gpio;
-
-       host->dev = &pdev->dev;
-       platform_set_drvdata(pdev, host);
-
-       if (host->switch_pin >= 0) {
-               INIT_WORK(&host->switch_work, mmc_omap_switch_handler);
-               init_timer(&host->switch_timer);
-               host->switch_timer.function = mmc_omap_switch_timer;
-               host->switch_timer.data = (unsigned long) host;
-               if (omap_request_gpio(host->switch_pin) != 0) {
-                       dev_warn(mmc_dev(host->mmc), "Unable to get GPIO pin for MMC cover switch\n");
-                       host->switch_pin = -1;
-                       goto no_switch;
-               }
-
-               omap_set_gpio_direction(host->switch_pin, 1);
-               ret = request_irq(OMAP_GPIO_IRQ(host->switch_pin),
-                                 mmc_omap_switch_irq, IRQF_TRIGGER_RISING, DRIVER_NAME, host);
-               if (ret) {
-                       dev_warn(mmc_dev(host->mmc), "Unable to get IRQ for MMC cover switch\n");
-                       omap_free_gpio(host->switch_pin);
-                       host->switch_pin = -1;
-                       goto no_switch;
-               }
-               ret = device_create_file(&pdev->dev, &dev_attr_cover_switch);
-               if (ret == 0) {
-                       ret = device_create_file(&pdev->dev, &dev_attr_enable_poll);
-                       if (ret != 0)
-                               device_remove_file(&pdev->dev, &dev_attr_cover_switch);
-               }
-               if (ret) {
-                       dev_warn(mmc_dev(host->mmc), "Unable to create sysfs attributes\n");
-                       free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
-                       omap_free_gpio(host->switch_pin);
-                       host->switch_pin = -1;
-                       goto no_switch;
-               }
-               if (mmc_omap_enable_poll && mmc_omap_cover_is_open(host))
-                       schedule_work(&host->switch_work);
-       }
-
-       mmc_add_host(mmc);
-
-       return 0;
-
-no_switch:
-       /* FIXME: Free other resources too. */
-       if (host) {
-               if (host->iclk && !IS_ERR(host->iclk))
-                       clk_put(host->iclk);
-               if (host->fclk && !IS_ERR(host->fclk))
-                       clk_put(host->fclk);
-               mmc_free_host(host->mmc);
-       }
-err_free_power_gpio:
-       if (host->power_pin >= 0)
-               omap_free_gpio(host->power_pin);
-err_free_fclk:
-       clk_put(host->fclk);
-err_free_iclk:
-       if (host->iclk != NULL) {
-               clk_disable(host->iclk);
-               clk_put(host->iclk);
-       }
-err_free_mmc_host:
-       mmc_free_host(host->mmc);
-err_free_mem_region:
-       release_mem_region(res->start, res->end - res->start + 1);
-       return ret;
-}
-
-static int mmc_omap_remove(struct platform_device *pdev)
-{
-       struct mmc_omap_host *host = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-
-       BUG_ON(host == NULL);
-
-       mmc_remove_host(host->mmc);
-       free_irq(host->irq, host);
-
-       if (host->power_pin >= 0)
-               omap_free_gpio(host->power_pin);
-       if (host->switch_pin >= 0) {
-               device_remove_file(&pdev->dev, &dev_attr_enable_poll);
-               device_remove_file(&pdev->dev, &dev_attr_cover_switch);
-               free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
-               omap_free_gpio(host->switch_pin);
-               host->switch_pin = -1;
-               del_timer_sync(&host->switch_timer);
-               flush_scheduled_work();
-       }
-       if (host->iclk && !IS_ERR(host->iclk))
-               clk_put(host->iclk);
-       if (host->fclk && !IS_ERR(host->fclk))
-               clk_put(host->fclk);
-
-       release_mem_region(pdev->resource[0].start,
-                          pdev->resource[0].end - pdev->resource[0].start + 1);
-
-       mmc_free_host(host->mmc);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg)
-{
-       int ret = 0;
-       struct mmc_omap_host *host = platform_get_drvdata(pdev);
-
-       if (host && host->suspended)
-               return 0;
-
-       if (host) {
-               ret = mmc_suspend_host(host->mmc, mesg);
-               if (ret == 0)
-                       host->suspended = 1;
-       }
-       return ret;
-}
-
-static int mmc_omap_resume(struct platform_device *pdev)
-{
-       int ret = 0;
-       struct mmc_omap_host *host = platform_get_drvdata(pdev);
-
-       if (host && !host->suspended)
-               return 0;
-
-       if (host) {
-               ret = mmc_resume_host(host->mmc);
-               if (ret == 0)
-                       host->suspended = 0;
-       }
-
-       return ret;
-}
-#else
-#define mmc_omap_suspend       NULL
-#define mmc_omap_resume                NULL
-#endif
-
-static struct platform_driver mmc_omap_driver = {
-       .probe          = mmc_omap_probe,
-       .remove         = mmc_omap_remove,
-       .suspend        = mmc_omap_suspend,
-       .resume         = mmc_omap_resume,
-       .driver         = {
-               .name   = DRIVER_NAME,
-       },
-};
-
-static int __init mmc_omap_init(void)
-{
-       return platform_driver_register(&mmc_omap_driver);
-}
-
-static void __exit mmc_omap_exit(void)
-{
-       platform_driver_unregister(&mmc_omap_driver);
-}
-
-module_init(mmc_omap_init);
-module_exit(mmc_omap_exit);
-
-MODULE_DESCRIPTION("OMAP Multimedia Card driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS(DRIVER_NAME);
-MODULE_AUTHOR("Juha Yrjölä");
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
deleted file mode 100644 (file)
index a98ff98..0000000
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- *  linux/drivers/mmc/pxa.c - PXA MMCI driver
- *
- *  Copyright (C) 2003 Russell King, 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.
- *
- *  This hardware is really sick:
- *   - No way to clear interrupts.
- *   - Have to turn off the clock whenever we touch the device.
- *   - Doesn't tell you how many data blocks were transferred.
- *  Yuck!
- *
- *     1 and 3 byte data transfers not supported
- *     max block length up to 1023
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/mmc/host.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/scatterlist.h>
-#include <asm/sizes.h>
-
-#include <asm/arch/pxa-regs.h>
-#include <asm/arch/mmc.h>
-
-#include "pxamci.h"
-
-#define DRIVER_NAME    "pxa2xx-mci"
-
-#define NR_SG  1
-
-struct pxamci_host {
-       struct mmc_host         *mmc;
-       spinlock_t              lock;
-       struct resource         *res;
-       void __iomem            *base;
-       int                     irq;
-       int                     dma;
-       unsigned int            clkrt;
-       unsigned int            cmdat;
-       unsigned int            imask;
-       unsigned int            power_mode;
-       struct pxamci_platform_data *pdata;
-
-       struct mmc_request      *mrq;
-       struct mmc_command      *cmd;
-       struct mmc_data         *data;
-
-       dma_addr_t              sg_dma;
-       struct pxa_dma_desc     *sg_cpu;
-       unsigned int            dma_len;
-
-       unsigned int            dma_dir;
-};
-
-static void pxamci_stop_clock(struct pxamci_host *host)
-{
-       if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
-               unsigned long timeout = 10000;
-               unsigned int v;
-
-               writel(STOP_CLOCK, host->base + MMC_STRPCL);
-
-               do {
-                       v = readl(host->base + MMC_STAT);
-                       if (!(v & STAT_CLK_EN))
-                               break;
-                       udelay(1);
-               } while (timeout--);
-
-               if (v & STAT_CLK_EN)
-                       dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
-       }
-}
-
-static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&host->lock, flags);
-       host->imask &= ~mask;
-       writel(host->imask, host->base + MMC_I_MASK);
-       spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&host->lock, flags);
-       host->imask |= mask;
-       writel(host->imask, host->base + MMC_I_MASK);
-       spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
-{
-       unsigned int nob = data->blocks;
-       unsigned long long clks;
-       unsigned int timeout;
-       u32 dcmd;
-       int i;
-
-       host->data = data;
-
-       if (data->flags & MMC_DATA_STREAM)
-               nob = 0xffff;
-
-       writel(nob, host->base + MMC_NOB);
-       writel(data->blksz, host->base + MMC_BLKLEN);
-
-       clks = (unsigned long long)data->timeout_ns * CLOCKRATE;
-       do_div(clks, 1000000000UL);
-       timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
-       writel((timeout + 255) / 256, host->base + MMC_RDTO);
-
-       if (data->flags & MMC_DATA_READ) {
-               host->dma_dir = DMA_FROM_DEVICE;
-               dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
-               DRCMRTXMMC = 0;
-               DRCMRRXMMC = host->dma | DRCMR_MAPVLD;
-       } else {
-               host->dma_dir = DMA_TO_DEVICE;
-               dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
-               DRCMRRXMMC = 0;
-               DRCMRTXMMC = host->dma | DRCMR_MAPVLD;
-       }
-
-       dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
-
-       host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
-                                  host->dma_dir);
-
-       for (i = 0; i < host->dma_len; i++) {
-               if (data->flags & MMC_DATA_READ) {
-                       host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
-                       host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
-               } else {
-                       host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
-                       host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
-               }
-               host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);
-               host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
-                                       sizeof(struct pxa_dma_desc);
-       }
-       host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
-       wmb();
-
-       DDADR(host->dma) = host->sg_dma;
-       DCSR(host->dma) = DCSR_RUN;
-}
-
-static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
-{
-       WARN_ON(host->cmd != NULL);
-       host->cmd = cmd;
-
-       if (cmd->flags & MMC_RSP_BUSY)
-               cmdat |= CMDAT_BUSY;
-
-#define RSP_TYPE(x)    ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
-       switch (RSP_TYPE(mmc_resp_type(cmd))) {
-       case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
-               cmdat |= CMDAT_RESP_SHORT;
-               break;
-       case RSP_TYPE(MMC_RSP_R3):
-               cmdat |= CMDAT_RESP_R3;
-               break;
-       case RSP_TYPE(MMC_RSP_R2):
-               cmdat |= CMDAT_RESP_R2;
-               break;
-       default:
-               break;
-       }
-
-       writel(cmd->opcode, host->base + MMC_CMD);
-       writel(cmd->arg >> 16, host->base + MMC_ARGH);
-       writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
-       writel(cmdat, host->base + MMC_CMDAT);
-       writel(host->clkrt, host->base + MMC_CLKRT);
-
-       writel(START_CLOCK, host->base + MMC_STRPCL);
-
-       pxamci_enable_irq(host, END_CMD_RES);
-}
-
-static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
-{
-       host->mrq = NULL;
-       host->cmd = NULL;
-       host->data = NULL;
-       mmc_request_done(host->mmc, mrq);
-}
-
-static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
-{
-       struct mmc_command *cmd = host->cmd;
-       int i;
-       u32 v;
-
-       if (!cmd)
-               return 0;
-
-       host->cmd = NULL;
-
-       /*
-        * Did I mention this is Sick.  We always need to
-        * discard the upper 8 bits of the first 16-bit word.
-        */
-       v = readl(host->base + MMC_RES) & 0xffff;
-       for (i = 0; i < 4; i++) {
-               u32 w1 = readl(host->base + MMC_RES) & 0xffff;
-               u32 w2 = readl(host->base + MMC_RES) & 0xffff;
-               cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
-               v = w2;
-       }
-
-       if (stat & STAT_TIME_OUT_RESPONSE) {
-               cmd->error = MMC_ERR_TIMEOUT;
-       } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
-#ifdef CONFIG_PXA27x
-               /*
-                * workaround for erratum #42:
-                * Intel PXA27x Family Processor Specification Update Rev 001
-                */
-               if (cmd->opcode == MMC_ALL_SEND_CID ||
-                   cmd->opcode == MMC_SEND_CSD ||
-                   cmd->opcode == MMC_SEND_CID) {
-                       /* a bogus CRC error can appear if the msb of
-                          the 15 byte response is a one */
-                       if ((cmd->resp[0] & 0x80000000) == 0)
-                               cmd->error = MMC_ERR_BADCRC;
-               } else {
-                       pr_debug("ignoring CRC from command %d - *risky*\n",cmd->opcode);
-               }
-#else
-               cmd->error = MMC_ERR_BADCRC;
-#endif
-       }
-
-       pxamci_disable_irq(host, END_CMD_RES);
-       if (host->data && cmd->error == MMC_ERR_NONE) {
-               pxamci_enable_irq(host, DATA_TRAN_DONE);
-       } else {
-               pxamci_finish_request(host, host->mrq);
-       }
-
-       return 1;
-}
-
-static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
-{
-       struct mmc_data *data = host->data;
-
-       if (!data)
-               return 0;
-
-       DCSR(host->dma) = 0;
-       dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
-                    host->dma_dir);
-
-       if (stat & STAT_READ_TIME_OUT)
-               data->error = MMC_ERR_TIMEOUT;
-       else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
-               data->error = MMC_ERR_BADCRC;
-
-       /*
-        * There appears to be a hardware design bug here.  There seems to
-        * be no way to find out how much data was transferred to the card.
-        * This means that if there was an error on any block, we mark all
-        * data blocks as being in error.
-        */
-       if (data->error == MMC_ERR_NONE)
-               data->bytes_xfered = data->blocks * data->blksz;
-       else
-               data->bytes_xfered = 0;
-
-       pxamci_disable_irq(host, DATA_TRAN_DONE);
-
-       host->data = NULL;
-       if (host->mrq->stop) {
-               pxamci_stop_clock(host);
-               pxamci_start_cmd(host, host->mrq->stop, 0);
-       } else {
-               pxamci_finish_request(host, host->mrq);
-       }
-
-       return 1;
-}
-
-static irqreturn_t pxamci_irq(int irq, void *devid)
-{
-       struct pxamci_host *host = devid;
-       unsigned int ireg;
-       int handled = 0;
-
-       ireg = readl(host->base + MMC_I_REG);
-
-       if (ireg) {
-               unsigned stat = readl(host->base + MMC_STAT);
-
-               pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
-
-               if (ireg & END_CMD_RES)
-                       handled |= pxamci_cmd_done(host, stat);
-               if (ireg & DATA_TRAN_DONE)
-                       handled |= pxamci_data_done(host, stat);
-       }
-
-       return IRQ_RETVAL(handled);
-}
-
-static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-       struct pxamci_host *host = mmc_priv(mmc);
-       unsigned int cmdat;
-
-       WARN_ON(host->mrq != NULL);
-
-       host->mrq = mrq;
-
-       pxamci_stop_clock(host);
-
-       cmdat = host->cmdat;
-       host->cmdat &= ~CMDAT_INIT;
-
-       if (mrq->data) {
-               pxamci_setup_data(host, mrq->data);
-
-               cmdat &= ~CMDAT_BUSY;
-               cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
-               if (mrq->data->flags & MMC_DATA_WRITE)
-                       cmdat |= CMDAT_WRITE;
-
-               if (mrq->data->flags & MMC_DATA_STREAM)
-                       cmdat |= CMDAT_STREAM;
-       }
-
-       pxamci_start_cmd(host, mrq->cmd, cmdat);
-}
-
-static int pxamci_get_ro(struct mmc_host *mmc)
-{
-       struct pxamci_host *host = mmc_priv(mmc);
-
-       if (host->pdata && host->pdata->get_ro)
-               return host->pdata->get_ro(mmc_dev(mmc));
-       /* Host doesn't support read only detection so assume writeable */
-       return 0;
-}
-
-static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-       struct pxamci_host *host = mmc_priv(mmc);
-
-       if (ios->clock) {
-               unsigned int clk = CLOCKRATE / ios->clock;
-               if (CLOCKRATE / clk > ios->clock)
-                       clk <<= 1;
-               host->clkrt = fls(clk) - 1;
-               pxa_set_cken(CKEN12_MMC, 1);
-
-               /*
-                * we write clkrt on the next command
-                */
-       } else {
-               pxamci_stop_clock(host);
-               pxa_set_cken(CKEN12_MMC, 0);
-       }
-
-       if (host->power_mode != ios->power_mode) {
-               host->power_mode = ios->power_mode;
-
-               if (host->pdata && host->pdata->setpower)
-                       host->pdata->setpower(mmc_dev(mmc), ios->vdd);
-
-               if (ios->power_mode == MMC_POWER_ON)
-                       host->cmdat |= CMDAT_INIT;
-       }
-
-       pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
-                host->clkrt, host->cmdat);
-}
-
-static const struct mmc_host_ops pxamci_ops = {
-       .request        = pxamci_request,
-       .get_ro         = pxamci_get_ro,
-       .set_ios        = pxamci_set_ios,
-};
-
-static void pxamci_dma_irq(int dma, void *devid)
-{
-       printk(KERN_ERR "DMA%d: IRQ???\n", dma);
-       DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
-}
-
-static irqreturn_t pxamci_detect_irq(int irq, void *devid)
-{
-       struct pxamci_host *host = mmc_priv(devid);
-
-       mmc_detect_change(devid, host->pdata->detect_delay);
-       return IRQ_HANDLED;
-}
-
-static int pxamci_probe(struct platform_device *pdev)
-{
-       struct mmc_host *mmc;
-       struct pxamci_host *host = NULL;
-       struct resource *r;
-       int ret, 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, SZ_4K, DRIVER_NAME);
-       if (!r)
-               return -EBUSY;
-
-       mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
-       if (!mmc) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       mmc->ops = &pxamci_ops;
-       mmc->f_min = CLOCKRATE_MIN;
-       mmc->f_max = CLOCKRATE_MAX;
-
-       /*
-        * We can do SG-DMA, but we don't because we never know how much
-        * data we successfully wrote to the card.
-        */
-       mmc->max_phys_segs = NR_SG;
-
-       /*
-        * Our hardware DMA can handle a maximum of one page per SG entry.
-        */
-       mmc->max_seg_size = PAGE_SIZE;
-
-       /*
-        * Block length register is 10 bits.
-        */
-       mmc->max_blk_size = 1023;
-
-       /*
-        * Block count register is 16 bits.
-        */
-       mmc->max_blk_count = 65535;
-
-       host = mmc_priv(mmc);
-       host->mmc = mmc;
-       host->dma = -1;
-       host->pdata = pdev->dev.platform_data;
-       mmc->ocr_avail = host->pdata ?
-                        host->pdata->ocr_mask :
-                        MMC_VDD_32_33|MMC_VDD_33_34;
-
-       host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
-       if (!host->sg_cpu) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       spin_lock_init(&host->lock);
-       host->res = r;
-       host->irq = irq;
-       host->imask = MMC_I_MASK_ALL;
-
-       host->base = ioremap(r->start, SZ_4K);
-       if (!host->base) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       /*
-        * Ensure that the host controller is shut down, and setup
-        * with our defaults.
-        */
-       pxamci_stop_clock(host);
-       writel(0, host->base + MMC_SPI);
-       writel(64, host->base + MMC_RESTO);
-       writel(host->imask, host->base + MMC_I_MASK);
-
-       host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
-                                   pxamci_dma_irq, host);
-       if (host->dma < 0) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
-       if (ret)
-               goto out;
-
-       platform_set_drvdata(pdev, mmc);
-
-       if (host->pdata && host->pdata->init)
-               host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
-
-       mmc_add_host(mmc);
-
-       return 0;
-
- out:
-       if (host) {
-               if (host->dma >= 0)
-                       pxa_free_dma(host->dma);
-               if (host->base)
-                       iounmap(host->base);
-               if (host->sg_cpu)
-                       dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
-       }
-       if (mmc)
-               mmc_free_host(mmc);
-       release_resource(r);
-       return ret;
-}
-
-static int pxamci_remove(struct platform_device *pdev)
-{
-       struct mmc_host *mmc = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (mmc) {
-               struct pxamci_host *host = mmc_priv(mmc);
-
-               if (host->pdata && host->pdata->exit)
-                       host->pdata->exit(&pdev->dev, mmc);
-
-               mmc_remove_host(mmc);
-
-               pxamci_stop_clock(host);
-               writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
-                      END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
-                      host->base + MMC_I_MASK);
-
-               DRCMRRXMMC = 0;
-               DRCMRTXMMC = 0;
-
-               free_irq(host->irq, host);
-               pxa_free_dma(host->dma);
-               iounmap(host->base);
-               dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
-
-               release_resource(host->res);
-
-               mmc_free_host(mmc);
-       }
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int pxamci_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct mmc_host *mmc = platform_get_drvdata(dev);
-       int ret = 0;
-
-       if (mmc)
-               ret = mmc_suspend_host(mmc, state);
-
-       return ret;
-}
-
-static int pxamci_resume(struct platform_device *dev)
-{
-       struct mmc_host *mmc = platform_get_drvdata(dev);
-       int ret = 0;
-
-       if (mmc)
-               ret = mmc_resume_host(mmc);
-
-       return ret;
-}
-#else
-#define pxamci_suspend NULL
-#define pxamci_resume  NULL
-#endif
-
-static struct platform_driver pxamci_driver = {
-       .probe          = pxamci_probe,
-       .remove         = pxamci_remove,
-       .suspend        = pxamci_suspend,
-       .resume         = pxamci_resume,
-       .driver         = {
-               .name   = DRIVER_NAME,
-       },
-};
-
-static int __init pxamci_init(void)
-{
-       return platform_driver_register(&pxamci_driver);
-}
-
-static void __exit pxamci_exit(void)
-{
-       platform_driver_unregister(&pxamci_driver);
-}
-
-module_init(pxamci_init);
-module_exit(pxamci_exit);
-
-MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/pxamci.h b/drivers/mmc/pxamci.h
deleted file mode 100644 (file)
index 1b16322..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-#undef MMC_STRPCL
-#undef MMC_STAT
-#undef MMC_CLKRT
-#undef MMC_SPI
-#undef MMC_CMDAT
-#undef MMC_RESTO
-#undef MMC_RDTO
-#undef MMC_BLKLEN
-#undef MMC_NOB
-#undef MMC_PRTBUF
-#undef MMC_I_MASK
-#undef END_CMD_RES
-#undef PRG_DONE
-#undef DATA_TRAN_DONE
-#undef MMC_I_REG
-#undef MMC_CMD
-#undef MMC_ARGH
-#undef MMC_ARGL
-#undef MMC_RES
-#undef MMC_RXFIFO
-#undef MMC_TXFIFO
-
-#define MMC_STRPCL     0x0000
-#define STOP_CLOCK             (1 << 0)
-#define START_CLOCK            (2 << 0)
-
-#define MMC_STAT       0x0004
-#define STAT_END_CMD_RES               (1 << 13)
-#define STAT_PRG_DONE                  (1 << 12)
-#define STAT_DATA_TRAN_DONE            (1 << 11)
-#define STAT_CLK_EN                    (1 << 8)
-#define STAT_RECV_FIFO_FULL            (1 << 7)
-#define STAT_XMIT_FIFO_EMPTY           (1 << 6)
-#define STAT_RES_CRC_ERR               (1 << 5)
-#define STAT_SPI_READ_ERROR_TOKEN      (1 << 4)
-#define STAT_CRC_READ_ERROR            (1 << 3)
-#define STAT_CRC_WRITE_ERROR           (1 << 2)
-#define STAT_TIME_OUT_RESPONSE         (1 << 1)
-#define STAT_READ_TIME_OUT             (1 << 0)
-
-#define MMC_CLKRT      0x0008          /* 3 bit */
-
-#define MMC_SPI                0x000c
-#define SPI_CS_ADDRESS         (1 << 3)
-#define SPI_CS_EN              (1 << 2)
-#define CRC_ON                 (1 << 1)
-#define SPI_EN                 (1 << 0)
-
-#define MMC_CMDAT      0x0010
-#define CMDAT_DMAEN            (1 << 7)
-#define CMDAT_INIT             (1 << 6)
-#define CMDAT_BUSY             (1 << 5)
-#define CMDAT_STREAM           (1 << 4)        /* 1 = stream */
-#define CMDAT_WRITE            (1 << 3)        /* 1 = write */
-#define CMDAT_DATAEN           (1 << 2)
-#define CMDAT_RESP_NONE                (0 << 0)
-#define CMDAT_RESP_SHORT       (1 << 0)
-#define CMDAT_RESP_R2          (2 << 0)
-#define CMDAT_RESP_R3          (3 << 0)
-
-#define MMC_RESTO      0x0014  /* 7 bit */
-
-#define MMC_RDTO       0x0018  /* 16 bit */
-
-#define MMC_BLKLEN     0x001c  /* 10 bit */
-
-#define MMC_NOB                0x0020  /* 16 bit */
-
-#define MMC_PRTBUF     0x0024
-#define BUF_PART_FULL          (1 << 0)
-
-#define MMC_I_MASK     0x0028
-
-/*PXA27x MMC interrupts*/
-#define SDIO_SUSPEND_ACK       (1 << 12)
-#define SDIO_INT               (1 << 11)
-#define RD_STALLED             (1 << 10)
-#define RES_ERR                (1 << 9)
-#define DAT_ERR                (1 << 8)
-#define TINT                   (1 << 7)
-
-/*PXA2xx MMC interrupts*/
-#define TXFIFO_WR_REQ          (1 << 6)
-#define RXFIFO_RD_REQ          (1 << 5)
-#define CLK_IS_OFF             (1 << 4)
-#define STOP_CMD               (1 << 3)
-#define END_CMD_RES            (1 << 2)
-#define PRG_DONE               (1 << 1)
-#define DATA_TRAN_DONE         (1 << 0)
-
-#ifdef CONFIG_PXA27x
-#define MMC_I_MASK_ALL          0x00001fff
-#else
-#define MMC_I_MASK_ALL          0x0000007f
-#endif
-
-#define MMC_I_REG      0x002c
-/* same as MMC_I_MASK */
-
-#define MMC_CMD                0x0030
-
-#define MMC_ARGH       0x0034  /* 16 bit */
-
-#define MMC_ARGL       0x0038  /* 16 bit */
-
-#define MMC_RES                0x003c  /* 16 bit */
-
-#define MMC_RXFIFO     0x0040  /* 8 bit */
-
-#define MMC_TXFIFO     0x0044  /* 8 bit */
-
-/*
- * The base MMC clock rate
- */
-#ifdef CONFIG_PXA27x
-#define CLOCKRATE_MIN  304688
-#define CLOCKRATE_MAX  19500000
-#else
-#define CLOCKRATE_MIN  312500
-#define CLOCKRATE_MAX  20000000
-#endif
-
-#define CLOCKRATE      CLOCKRATE_MAX
-
diff --git a/drivers/mmc/queue.c b/drivers/mmc/queue.c
deleted file mode 100644 (file)
index aa75ac1..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- *  linux/drivers/mmc/queue.c
- *
- *  Copyright (C) 2003 Russell King, All Rights Reserved.
- *  Copyright 2006-2007 Pierre Ossman
- *
- * 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/module.h>
-#include <linux/blkdev.h>
-#include <linux/kthread.h>
-
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include "queue.h"
-
-#define MMC_QUEUE_SUSPENDED    (1 << 0)
-
-/*
- * Prepare a MMC request.  Essentially, this means passing the
- * preparation off to the media driver.  The media driver will
- * create a mmc_io_request in req->special.
- */
-static int mmc_prep_request(struct request_queue *q, struct request *req)
-{
-       struct mmc_queue *mq = q->queuedata;
-       int ret = BLKPREP_KILL;
-
-       if (blk_special_request(req)) {
-               /*
-                * Special commands already have the command
-                * blocks already setup in req->special.
-                */
-               BUG_ON(!req->special);
-
-               ret = BLKPREP_OK;
-       } else if (blk_fs_request(req) || blk_pc_request(req)) {
-               /*
-                * Block I/O requests need translating according
-                * to the protocol.
-                */
-               ret = mq->prep_fn(mq, req);
-       } else {
-               /*
-                * Everything else is invalid.
-                */
-               blk_dump_rq_flags(req, "MMC bad request");
-       }
-
-       if (ret == BLKPREP_OK)
-               req->cmd_flags |= REQ_DONTPREP;
-
-       return ret;
-}
-
-static int mmc_queue_thread(void *d)
-{
-       struct mmc_queue *mq = d;
-       struct request_queue *q = mq->queue;
-
-       /*
-        * Set iothread to ensure that we aren't put to sleep by
-        * the process freezing.  We handle suspension ourselves.
-        */
-       current->flags |= PF_MEMALLOC|PF_NOFREEZE;
-
-       down(&mq->thread_sem);
-       do {
-               struct request *req = NULL;
-
-               spin_lock_irq(q->queue_lock);
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (!blk_queue_plugged(q))
-                       req = elv_next_request(q);
-               mq->req = req;
-               spin_unlock_irq(q->queue_lock);
-
-               if (!req) {
-                       if (kthread_should_stop()) {
-                               set_current_state(TASK_RUNNING);
-                               break;
-                       }
-                       up(&mq->thread_sem);
-                       schedule();
-                       down(&mq->thread_sem);
-                       continue;
-               }
-               set_current_state(TASK_RUNNING);
-
-               mq->issue_fn(mq, req);
-       } while (1);
-       up(&mq->thread_sem);
-
-       return 0;
-}
-
-/*
- * Generic MMC request handler.  This is called for any queue on a
- * particular host.  When the host is not busy, we look for a request
- * on any queue on this host, and attempt to issue it.  This may
- * not be the queue we were asked to process.
- */
-static void mmc_request(request_queue_t *q)
-{
-       struct mmc_queue *mq = q->queuedata;
-       struct request *req;
-       int ret;
-
-       if (!mq) {
-               printk(KERN_ERR "MMC: killing requests for dead queue\n");
-               while ((req = elv_next_request(q)) != NULL) {
-                       do {
-                               ret = end_that_request_chunk(req, 0,
-                                       req->current_nr_sectors << 9);
-                       } while (ret);
-               }
-               return;
-       }
-
-       if (!mq->req)
-               wake_up_process(mq->thread);
-}
-
-/**
- * mmc_init_queue - initialise a queue structure.
- * @mq: mmc queue
- * @card: mmc card to attach this queue
- * @lock: queue lock
- *
- * Initialise a MMC card request queue.
- */
-int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)
-{
-       struct mmc_host *host = card->host;
-       u64 limit = BLK_BOUNCE_HIGH;
-       int ret;
-
-       if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
-               limit = *mmc_dev(host)->dma_mask;
-
-       mq->card = card;
-       mq->queue = blk_init_queue(mmc_request, lock);
-       if (!mq->queue)
-               return -ENOMEM;
-
-       blk_queue_prep_rq(mq->queue, mmc_prep_request);
-       blk_queue_bounce_limit(mq->queue, limit);
-       blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
-       blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
-       blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
-       blk_queue_max_segment_size(mq->queue, host->max_seg_size);
-
-       mq->queue->queuedata = mq;
-       mq->req = NULL;
-
-       mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs,
-                        GFP_KERNEL);
-       if (!mq->sg) {
-               ret = -ENOMEM;
-               goto cleanup_queue;
-       }
-
-       init_MUTEX(&mq->thread_sem);
-
-       mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");
-       if (IS_ERR(mq->thread)) {
-               ret = PTR_ERR(mq->thread);
-               goto free_sg;
-       }
-
-       return 0;
-
- free_sg:
-       kfree(mq->sg);
-       mq->sg = NULL;
- cleanup_queue:
-       blk_cleanup_queue(mq->queue);
-       return ret;
-}
-
-void mmc_cleanup_queue(struct mmc_queue *mq)
-{
-       request_queue_t *q = mq->queue;
-       unsigned long flags;
-
-       /* Mark that we should start throwing out stragglers */
-       spin_lock_irqsave(q->queue_lock, flags);
-       q->queuedata = NULL;
-       spin_unlock_irqrestore(q->queue_lock, flags);
-
-       /* Then terminate our worker thread */
-       kthread_stop(mq->thread);
-
-       kfree(mq->sg);
-       mq->sg = NULL;
-
-       blk_cleanup_queue(mq->queue);
-
-       mq->card = NULL;
-}
-EXPORT_SYMBOL(mmc_cleanup_queue);
-
-/**
- * mmc_queue_suspend - suspend a MMC request queue
- * @mq: MMC queue to suspend
- *
- * Stop the block request queue, and wait for our thread to
- * complete any outstanding requests.  This ensures that we
- * won't suspend while a request is being processed.
- */
-void mmc_queue_suspend(struct mmc_queue *mq)
-{
-       request_queue_t *q = mq->queue;
-       unsigned long flags;
-
-       if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
-               mq->flags |= MMC_QUEUE_SUSPENDED;
-
-               spin_lock_irqsave(q->queue_lock, flags);
-               blk_stop_queue(q);
-               spin_unlock_irqrestore(q->queue_lock, flags);
-
-               down(&mq->thread_sem);
-       }
-}
-
-/**
- * mmc_queue_resume - resume a previously suspended MMC request queue
- * @mq: MMC queue to resume
- */
-void mmc_queue_resume(struct mmc_queue *mq)
-{
-       request_queue_t *q = mq->queue;
-       unsigned long flags;
-
-       if (mq->flags & MMC_QUEUE_SUSPENDED) {
-               mq->flags &= ~MMC_QUEUE_SUSPENDED;
-
-               up(&mq->thread_sem);
-
-               spin_lock_irqsave(q->queue_lock, flags);
-               blk_start_queue(q);
-               spin_unlock_irqrestore(q->queue_lock, flags);
-       }
-}
-
diff --git a/drivers/mmc/queue.h b/drivers/mmc/queue.h
deleted file mode 100644 (file)
index c9f139e..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef MMC_QUEUE_H
-#define MMC_QUEUE_H
-
-struct request;
-struct task_struct;
-
-struct mmc_queue {
-       struct mmc_card         *card;
-       struct task_struct      *thread;
-       struct semaphore        thread_sem;
-       unsigned int            flags;
-       struct request          *req;
-       int                     (*prep_fn)(struct mmc_queue *, struct request *);
-       int                     (*issue_fn)(struct mmc_queue *, struct request *);
-       void                    *data;
-       struct request_queue    *queue;
-       struct scatterlist      *sg;
-};
-
-struct mmc_io_request {
-       struct request          *rq;
-       int                     num;
-       struct mmc_command      selcmd;         /* mmc_queue private */
-       struct mmc_command      cmd[4];         /* max 4 commands */
-};
-
-extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
-extern void mmc_cleanup_queue(struct mmc_queue *);
-extern void mmc_queue_suspend(struct mmc_queue *);
-extern void mmc_queue_resume(struct mmc_queue *);
-
-#endif
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
deleted file mode 100644 (file)
index 579142a..0000000
+++ /dev/null
@@ -1,1539 +0,0 @@
-/*
- *  linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver
- *
- *  Copyright (C) 2005-2007 Pierre Ossman, 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 as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/delay.h>
-#include <linux/highmem.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-
-#include <linux/mmc/host.h>
-
-#include <asm/scatterlist.h>
-
-#include "sdhci.h"
-
-#define DRIVER_NAME "sdhci"
-
-#define DBG(f, x...) \
-       pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
-
-static unsigned int debug_nodma = 0;
-static unsigned int debug_forcedma = 0;
-static unsigned int debug_quirks = 0;
-
-#define SDHCI_QUIRK_CLOCK_BEFORE_RESET                 (1<<0)
-#define SDHCI_QUIRK_FORCE_DMA                          (1<<1)
-/* Controller doesn't like some resets when there is no card inserted. */
-#define SDHCI_QUIRK_NO_CARD_NO_RESET                   (1<<2)
-#define SDHCI_QUIRK_SINGLE_POWER_WRITE                 (1<<3)
-
-static const struct pci_device_id pci_ids[] __devinitdata = {
-       {
-               .vendor         = PCI_VENDOR_ID_RICOH,
-               .device         = PCI_DEVICE_ID_RICOH_R5C822,
-               .subvendor      = PCI_VENDOR_ID_IBM,
-               .subdevice      = PCI_ANY_ID,
-               .driver_data    = SDHCI_QUIRK_CLOCK_BEFORE_RESET |
-                                 SDHCI_QUIRK_FORCE_DMA,
-       },
-
-       {
-               .vendor         = PCI_VENDOR_ID_RICOH,
-               .device         = PCI_DEVICE_ID_RICOH_R5C822,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .driver_data    = SDHCI_QUIRK_FORCE_DMA |
-                                 SDHCI_QUIRK_NO_CARD_NO_RESET,
-       },
-
-       {
-               .vendor         = PCI_VENDOR_ID_TI,
-               .device         = PCI_DEVICE_ID_TI_XX21_XX11_SD,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .driver_data    = SDHCI_QUIRK_FORCE_DMA,
-       },
-
-       {
-               .vendor         = PCI_VENDOR_ID_ENE,
-               .device         = PCI_DEVICE_ID_ENE_CB712_SD,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE,
-       },
-
-       {       /* Generic SD host controller */
-               PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
-       },
-
-       { /* end: all zeroes */ },
-};
-
-MODULE_DEVICE_TABLE(pci, pci_ids);
-
-static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
-static void sdhci_finish_data(struct sdhci_host *);
-
-static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
-static void sdhci_finish_command(struct sdhci_host *);
-
-static void sdhci_dumpregs(struct sdhci_host *host)
-{
-       printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
-
-       printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
-               readl(host->ioaddr + SDHCI_DMA_ADDRESS),
-               readw(host->ioaddr + SDHCI_HOST_VERSION));
-       printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
-               readw(host->ioaddr + SDHCI_BLOCK_SIZE),
-               readw(host->ioaddr + SDHCI_BLOCK_COUNT));
-       printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
-               readl(host->ioaddr + SDHCI_ARGUMENT),
-               readw(host->ioaddr + SDHCI_TRANSFER_MODE));
-       printk(KERN_DEBUG DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
-               readl(host->ioaddr + SDHCI_PRESENT_STATE),
-               readb(host->ioaddr + SDHCI_HOST_CONTROL));
-       printk(KERN_DEBUG DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
-               readb(host->ioaddr + SDHCI_POWER_CONTROL),
-               readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL));
-       printk(KERN_DEBUG DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
-               readb(host->ioaddr + SDHCI_WALK_UP_CONTROL),
-               readw(host->ioaddr + SDHCI_CLOCK_CONTROL));
-       printk(KERN_DEBUG DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
-               readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL),
-               readl(host->ioaddr + SDHCI_INT_STATUS));
-       printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
-               readl(host->ioaddr + SDHCI_INT_ENABLE),
-               readl(host->ioaddr + SDHCI_SIGNAL_ENABLE));
-       printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
-               readw(host->ioaddr + SDHCI_ACMD12_ERR),
-               readw(host->ioaddr + SDHCI_SLOT_INT_STATUS));
-       printk(KERN_DEBUG DRIVER_NAME ": Caps:     0x%08x | Max curr: 0x%08x\n",
-               readl(host->ioaddr + SDHCI_CAPABILITIES),
-               readl(host->ioaddr + SDHCI_MAX_CURRENT));
-
-       printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n");
-}
-
-/*****************************************************************************\
- *                                                                           *
- * Low level functions                                                       *
- *                                                                           *
-\*****************************************************************************/
-
-static void sdhci_reset(struct sdhci_host *host, u8 mask)
-{
-       unsigned long timeout;
-
-       if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
-               if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
-                       SDHCI_CARD_PRESENT))
-                       return;
-       }
-
-       writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
-
-       if (mask & SDHCI_RESET_ALL)
-               host->clock = 0;
-
-       /* Wait max 100 ms */
-       timeout = 100;
-
-       /* hw clears the bit when it's done */
-       while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) {
-               if (timeout == 0) {
-                       printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
-                               mmc_hostname(host->mmc), (int)mask);
-                       sdhci_dumpregs(host);
-                       return;
-               }
-               timeout--;
-               mdelay(1);
-       }
-}
-
-static void sdhci_init(struct sdhci_host *host)
-{
-       u32 intmask;
-
-       sdhci_reset(host, SDHCI_RESET_ALL);
-
-       intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
-               SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
-               SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
-               SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
-               SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
-               SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
-
-       writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
-       writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
-}
-
-static void sdhci_activate_led(struct sdhci_host *host)
-{
-       u8 ctrl;
-
-       ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
-       ctrl |= SDHCI_CTRL_LED;
-       writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
-}
-
-static void sdhci_deactivate_led(struct sdhci_host *host)
-{
-       u8 ctrl;
-
-       ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
-       ctrl &= ~SDHCI_CTRL_LED;
-       writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
-}
-
-/*****************************************************************************\
- *                                                                           *
- * Core functions                                                            *
- *                                                                           *
-\*****************************************************************************/
-
-static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
-{
-       return page_address(host->cur_sg->page) + host->cur_sg->offset;
-}
-
-static inline int sdhci_next_sg(struct sdhci_host* host)
-{
-       /*
-        * Skip to next SG entry.
-        */
-       host->cur_sg++;
-       host->num_sg--;
-
-       /*
-        * Any entries left?
-        */
-       if (host->num_sg > 0) {
-               host->offset = 0;
-               host->remain = host->cur_sg->length;
-       }
-
-       return host->num_sg;
-}
-
-static void sdhci_read_block_pio(struct sdhci_host *host)
-{
-       int blksize, chunk_remain;
-       u32 data;
-       char *buffer;
-       int size;
-
-       DBG("PIO reading\n");
-
-       blksize = host->data->blksz;
-       chunk_remain = 0;
-       data = 0;
-
-       buffer = sdhci_sg_to_buffer(host) + host->offset;
-
-       while (blksize) {
-               if (chunk_remain == 0) {
-                       data = readl(host->ioaddr + SDHCI_BUFFER);
-                       chunk_remain = min(blksize, 4);
-               }
-
-               size = min(host->remain, chunk_remain);
-
-               chunk_remain -= size;
-               blksize -= size;
-               host->offset += size;
-               host->remain -= size;
-
-               while (size) {
-                       *buffer = data & 0xFF;
-                       buffer++;
-                       data >>= 8;
-                       size--;
-               }
-
-               if (host->remain == 0) {
-                       if (sdhci_next_sg(host) == 0) {
-                               BUG_ON(blksize != 0);
-                               return;
-                       }
-                       buffer = sdhci_sg_to_buffer(host);
-               }
-       }
-}
-
-static void sdhci_write_block_pio(struct sdhci_host *host)
-{
-       int blksize, chunk_remain;
-       u32 data;
-       char *buffer;
-       int bytes, size;
-
-       DBG("PIO writing\n");
-
-       blksize = host->data->blksz;
-       chunk_remain = 4;
-       data = 0;
-
-       bytes = 0;
-       buffer = sdhci_sg_to_buffer(host) + host->offset;
-
-       while (blksize) {
-               size = min(host->remain, chunk_remain);
-
-               chunk_remain -= size;
-               blksize -= size;
-               host->offset += size;
-               host->remain -= size;
-
-               while (size) {
-                       data >>= 8;
-                       data |= (u32)*buffer << 24;
-                       buffer++;
-                       size--;
-               }
-
-               if (chunk_remain == 0) {
-                       writel(data, host->ioaddr + SDHCI_BUFFER);
-                       chunk_remain = min(blksize, 4);
-               }
-
-               if (host->remain == 0) {
-                       if (sdhci_next_sg(host) == 0) {
-                               BUG_ON(blksize != 0);
-                               return;
-                       }
-                       buffer = sdhci_sg_to_buffer(host);
-               }
-       }
-}
-
-static void sdhci_transfer_pio(struct sdhci_host *host)
-{
-       u32 mask;
-
-       BUG_ON(!host->data);
-
-       if (host->num_sg == 0)
-               return;
-
-       if (host->data->flags & MMC_DATA_READ)
-               mask = SDHCI_DATA_AVAILABLE;
-       else
-               mask = SDHCI_SPACE_AVAILABLE;
-
-       while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
-               if (host->data->flags & MMC_DATA_READ)
-                       sdhci_read_block_pio(host);
-               else
-                       sdhci_write_block_pio(host);
-
-               if (host->num_sg == 0)
-                       break;
-       }
-
-       DBG("PIO transfer complete.\n");
-}
-
-static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
-{
-       u8 count;
-       unsigned target_timeout, current_timeout;
-
-       WARN_ON(host->data);
-
-       if (data == NULL)
-               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 */
-       BUG_ON(data->blksz * data->blocks > 524288);
-       BUG_ON(data->blksz > host->mmc->max_blk_size);
-       BUG_ON(data->blocks > 65535);
-
-       /* timeout in us */
-       target_timeout = data->timeout_ns / 1000 +
-               data->timeout_clks / host->clock;
-
-       /*
-        * Figure out needed cycles.
-        * We do this in steps in order to fit inside a 32 bit int.
-        * The first step is the minimum timeout, which will have a
-        * minimum resolution of 6 bits:
-        * (1) 2^13*1000 > 2^22,
-        * (2) host->timeout_clk < 2^16
-        *     =>
-        *     (1) / (2) > 2^6
-        */
-       count = 0;
-       current_timeout = (1 << 13) * 1000 / host->timeout_clk;
-       while (current_timeout < target_timeout) {
-               count++;
-               current_timeout <<= 1;
-               if (count >= 0xF)
-                       break;
-       }
-
-       if (count >= 0xF) {
-               printk(KERN_WARNING "%s: Too large timeout requested!\n",
-                       mmc_hostname(host->mmc));
-               count = 0xE;
-       }
-
-       writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
-
-       if (host->flags & SDHCI_USE_DMA) {
-               int count;
-
-               count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len,
-                       (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
-               BUG_ON(count != 1);
-
-               writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
-       } else {
-               host->cur_sg = data->sg;
-               host->num_sg = data->sg_len;
-
-               host->offset = 0;
-               host->remain = host->cur_sg->length;
-       }
-
-       /* We do not handle DMA boundaries, so set it to max (512 KiB) */
-       writew(SDHCI_MAKE_BLKSZ(7, data->blksz),
-               host->ioaddr + SDHCI_BLOCK_SIZE);
-       writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
-}
-
-static void sdhci_set_transfer_mode(struct sdhci_host *host,
-       struct mmc_data *data)
-{
-       u16 mode;
-
-       WARN_ON(host->data);
-
-       if (data == NULL)
-               return;
-
-       mode = SDHCI_TRNS_BLK_CNT_EN;
-       if (data->blocks > 1)
-               mode |= SDHCI_TRNS_MULTI;
-       if (data->flags & MMC_DATA_READ)
-               mode |= SDHCI_TRNS_READ;
-       if (host->flags & SDHCI_USE_DMA)
-               mode |= SDHCI_TRNS_DMA;
-
-       writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
-}
-
-static void sdhci_finish_data(struct sdhci_host *host)
-{
-       struct mmc_data *data;
-       u16 blocks;
-
-       BUG_ON(!host->data);
-
-       data = host->data;
-       host->data = NULL;
-
-       if (host->flags & SDHCI_USE_DMA) {
-               pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len,
-                       (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
-       }
-
-       /*
-        * Controller doesn't count down when in single block mode.
-        */
-       if ((data->blocks == 1) && (data->error == MMC_ERR_NONE))
-               blocks = 0;
-       else
-               blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
-       data->bytes_xfered = data->blksz * (data->blocks - blocks);
-
-       if ((data->error == MMC_ERR_NONE) && blocks) {
-               printk(KERN_ERR "%s: Controller signalled completion even "
-                       "though there were blocks left.\n",
-                       mmc_hostname(host->mmc));
-               data->error = MMC_ERR_FAILED;
-       }
-
-       DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered);
-
-       if (data->stop) {
-               /*
-                * The controller needs a reset of internal state machines
-                * upon error conditions.
-                */
-               if (data->error != MMC_ERR_NONE) {
-                       sdhci_reset(host, SDHCI_RESET_CMD);
-                       sdhci_reset(host, SDHCI_RESET_DATA);
-               }
-
-               sdhci_send_command(host, data->stop);
-       } else
-               tasklet_schedule(&host->finish_tasklet);
-}
-
-static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
-{
-       int flags;
-       u32 mask;
-       unsigned long timeout;
-
-       WARN_ON(host->cmd);
-
-       DBG("Sending cmd (%x)\n", cmd->opcode);
-
-       /* Wait max 10 ms */
-       timeout = 10;
-
-       mask = SDHCI_CMD_INHIBIT;
-       if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
-               mask |= SDHCI_DATA_INHIBIT;
-
-       /* We shouldn't wait for data inihibit for stop commands, even
-          though they might use busy signaling */
-       if (host->mrq->data && (cmd == host->mrq->data->stop))
-               mask &= ~SDHCI_DATA_INHIBIT;
-
-       while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
-               if (timeout == 0) {
-                       printk(KERN_ERR "%s: Controller never released "
-                               "inhibit bit(s).\n", mmc_hostname(host->mmc));
-                       sdhci_dumpregs(host);
-                       cmd->error = MMC_ERR_FAILED;
-                       tasklet_schedule(&host->finish_tasklet);
-                       return;
-               }
-               timeout--;
-               mdelay(1);
-       }
-
-       mod_timer(&host->timer, jiffies + 10 * HZ);
-
-       host->cmd = cmd;
-
-       sdhci_prepare_data(host, cmd->data);
-
-       writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT);
-
-       sdhci_set_transfer_mode(host, cmd->data);
-
-       if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
-               printk(KERN_ERR "%s: Unsupported response type!\n",
-                       mmc_hostname(host->mmc));
-               cmd->error = MMC_ERR_INVALID;
-               tasklet_schedule(&host->finish_tasklet);
-               return;
-       }
-
-       if (!(cmd->flags & MMC_RSP_PRESENT))
-               flags = SDHCI_CMD_RESP_NONE;
-       else if (cmd->flags & MMC_RSP_136)
-               flags = SDHCI_CMD_RESP_LONG;
-       else if (cmd->flags & MMC_RSP_BUSY)
-               flags = SDHCI_CMD_RESP_SHORT_BUSY;
-       else
-               flags = SDHCI_CMD_RESP_SHORT;
-
-       if (cmd->flags & MMC_RSP_CRC)
-               flags |= SDHCI_CMD_CRC;
-       if (cmd->flags & MMC_RSP_OPCODE)
-               flags |= SDHCI_CMD_INDEX;
-       if (cmd->data)
-               flags |= SDHCI_CMD_DATA;
-
-       writew(SDHCI_MAKE_CMD(cmd->opcode, flags),
-               host->ioaddr + SDHCI_COMMAND);
-}
-
-static void sdhci_finish_command(struct sdhci_host *host)
-{
-       int i;
-
-       BUG_ON(host->cmd == NULL);
-
-       if (host->cmd->flags & MMC_RSP_PRESENT) {
-               if (host->cmd->flags & MMC_RSP_136) {
-                       /* CRC is stripped so we need to do some shifting. */
-                       for (i = 0;i < 4;i++) {
-                               host->cmd->resp[i] = readl(host->ioaddr +
-                                       SDHCI_RESPONSE + (3-i)*4) << 8;
-                               if (i != 3)
-                                       host->cmd->resp[i] |=
-                                               readb(host->ioaddr +
-                                               SDHCI_RESPONSE + (3-i)*4-1);
-                       }
-               } else {
-                       host->cmd->resp[0] = readl(host->ioaddr + SDHCI_RESPONSE);
-               }
-       }
-
-       host->cmd->error = MMC_ERR_NONE;
-
-       DBG("Ending cmd (%x)\n", host->cmd->opcode);
-
-       if (host->cmd->data)
-               host->data = host->cmd->data;
-       else
-               tasklet_schedule(&host->finish_tasklet);
-
-       host->cmd = NULL;
-}
-
-static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
-{
-       int div;
-       u16 clk;
-       unsigned long timeout;
-
-       if (clock == host->clock)
-               return;
-
-       writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
-
-       if (clock == 0)
-               goto out;
-
-       for (div = 1;div < 256;div *= 2) {
-               if ((host->max_clk / div) <= clock)
-                       break;
-       }
-       div >>= 1;
-
-       clk = div << SDHCI_DIVIDER_SHIFT;
-       clk |= SDHCI_CLOCK_INT_EN;
-       writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
-
-       /* Wait max 10 ms */
-       timeout = 10;
-       while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL))
-               & SDHCI_CLOCK_INT_STABLE)) {
-               if (timeout == 0) {
-                       printk(KERN_ERR "%s: Internal clock never "
-                               "stabilised.\n", mmc_hostname(host->mmc));
-                       sdhci_dumpregs(host);
-                       return;
-               }
-               timeout--;
-               mdelay(1);
-       }
-
-       clk |= SDHCI_CLOCK_CARD_EN;
-       writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
-
-out:
-       host->clock = clock;
-}
-
-static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
-{
-       u8 pwr;
-
-       if (host->power == power)
-               return;
-
-       if (power == (unsigned short)-1) {
-               writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
-               goto out;
-       }
-
-       /*
-        * Spec says that we should clear the power reg before setting
-        * a new value. Some controllers don't seem to like this though.
-        */
-       if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
-               writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
-
-       pwr = SDHCI_POWER_ON;
-
-       switch (power) {
-       case MMC_VDD_170:
-       case MMC_VDD_180:
-       case MMC_VDD_190:
-               pwr |= SDHCI_POWER_180;
-               break;
-       case MMC_VDD_290:
-       case MMC_VDD_300:
-       case MMC_VDD_310:
-               pwr |= SDHCI_POWER_300;
-               break;
-       case MMC_VDD_320:
-       case MMC_VDD_330:
-       case MMC_VDD_340:
-               pwr |= SDHCI_POWER_330;
-               break;
-       default:
-               BUG();
-       }
-
-       writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
-
-out:
-       host->power = power;
-}
-
-/*****************************************************************************\
- *                                                                           *
- * MMC callbacks                                                             *
- *                                                                           *
-\*****************************************************************************/
-
-static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-       struct sdhci_host *host;
-       unsigned long flags;
-
-       host = mmc_priv(mmc);
-
-       spin_lock_irqsave(&host->lock, flags);
-
-       WARN_ON(host->mrq != NULL);
-
-       sdhci_activate_led(host);
-
-       host->mrq = mrq;
-
-       if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
-               host->mrq->cmd->error = MMC_ERR_TIMEOUT;
-               tasklet_schedule(&host->finish_tasklet);
-       } else
-               sdhci_send_command(host, mrq->cmd);
-
-       mmiowb();
-       spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-       struct sdhci_host *host;
-       unsigned long flags;
-       u8 ctrl;
-
-       host = mmc_priv(mmc);
-
-       spin_lock_irqsave(&host->lock, flags);
-
-       /*
-        * Reset the chip on each power off.
-        * Should clear out any weird states.
-        */
-       if (ios->power_mode == MMC_POWER_OFF) {
-               writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE);
-               sdhci_init(host);
-       }
-
-       sdhci_set_clock(host, ios->clock);
-
-       if (ios->power_mode == MMC_POWER_OFF)
-               sdhci_set_power(host, -1);
-       else
-               sdhci_set_power(host, ios->vdd);
-
-       ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
-
-       if (ios->bus_width == MMC_BUS_WIDTH_4)
-               ctrl |= SDHCI_CTRL_4BITBUS;
-       else
-               ctrl &= ~SDHCI_CTRL_4BITBUS;
-
-       if (ios->timing == MMC_TIMING_SD_HS)
-               ctrl |= SDHCI_CTRL_HISPD;
-       else
-               ctrl &= ~SDHCI_CTRL_HISPD;
-
-       writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
-
-       mmiowb();
-       spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static int sdhci_get_ro(struct mmc_host *mmc)
-{
-       struct sdhci_host *host;
-       unsigned long flags;
-       int present;
-
-       host = mmc_priv(mmc);
-
-       spin_lock_irqsave(&host->lock, flags);
-
-       present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
-
-       spin_unlock_irqrestore(&host->lock, flags);
-
-       return !(present & SDHCI_WRITE_PROTECT);
-}
-
-static const struct mmc_host_ops sdhci_ops = {
-       .request        = sdhci_request,
-       .set_ios        = sdhci_set_ios,
-       .get_ro         = sdhci_get_ro,
-};
-
-/*****************************************************************************\
- *                                                                           *
- * Tasklets                                                                  *
- *                                                                           *
-\*****************************************************************************/
-
-static void sdhci_tasklet_card(unsigned long param)
-{
-       struct sdhci_host *host;
-       unsigned long flags;
-
-       host = (struct sdhci_host*)param;
-
-       spin_lock_irqsave(&host->lock, flags);
-
-       if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
-               if (host->mrq) {
-                       printk(KERN_ERR "%s: Card removed during transfer!\n",
-                               mmc_hostname(host->mmc));
-                       printk(KERN_ERR "%s: Resetting controller.\n",
-                               mmc_hostname(host->mmc));
-
-                       sdhci_reset(host, SDHCI_RESET_CMD);
-                       sdhci_reset(host, SDHCI_RESET_DATA);
-
-                       host->mrq->cmd->error = MMC_ERR_FAILED;
-                       tasklet_schedule(&host->finish_tasklet);
-               }
-       }
-
-       spin_unlock_irqrestore(&host->lock, flags);
-
-       mmc_detect_change(host->mmc, msecs_to_jiffies(500));
-}
-
-static void sdhci_tasklet_finish(unsigned long param)
-{
-       struct sdhci_host *host;
-       unsigned long flags;
-       struct mmc_request *mrq;
-
-       host = (struct sdhci_host*)param;
-
-       spin_lock_irqsave(&host->lock, flags);
-
-       del_timer(&host->timer);
-
-       mrq = host->mrq;
-
-       DBG("Ending request, cmd (%x)\n", mrq->cmd->opcode);
-
-       /*
-        * The controller needs a reset of internal state machines
-        * upon error conditions.
-        */
-       if ((mrq->cmd->error != MMC_ERR_NONE) ||
-               (mrq->data && ((mrq->data->error != MMC_ERR_NONE) ||
-               (mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) {
-
-               /* Some controllers need this kick or reset won't work here */
-               if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
-                       unsigned int clock;
-
-                       /* This is to force an update */
-                       clock = host->clock;
-                       host->clock = 0;
-                       sdhci_set_clock(host, clock);
-               }
-
-               /* Spec says we should do both at the same time, but Ricoh
-                  controllers do not like that. */
-               sdhci_reset(host, SDHCI_RESET_CMD);
-               sdhci_reset(host, SDHCI_RESET_DATA);
-       }
-
-       host->mrq = NULL;
-       host->cmd = NULL;
-       host->data = NULL;
-
-       sdhci_deactivate_led(host);
-
-       mmiowb();
-       spin_unlock_irqrestore(&host->lock, flags);
-
-       mmc_request_done(host->mmc, mrq);
-}
-
-static void sdhci_timeout_timer(unsigned long data)
-{
-       struct sdhci_host *host;
-       unsigned long flags;
-
-       host = (struct sdhci_host*)data;
-
-       spin_lock_irqsave(&host->lock, flags);
-
-       if (host->mrq) {
-               printk(KERN_ERR "%s: Timeout waiting for hardware "
-                       "interrupt.\n", mmc_hostname(host->mmc));
-               sdhci_dumpregs(host);
-
-               if (host->data) {
-                       host->data->error = MMC_ERR_TIMEOUT;
-                       sdhci_finish_data(host);
-               } else {
-                       if (host->cmd)
-                               host->cmd->error = MMC_ERR_TIMEOUT;
-                       else
-                               host->mrq->cmd->error = MMC_ERR_TIMEOUT;
-
-                       tasklet_schedule(&host->finish_tasklet);
-               }
-       }
-
-       mmiowb();
-       spin_unlock_irqrestore(&host->lock, flags);
-}
-
-/*****************************************************************************\
- *                                                                           *
- * Interrupt handling                                                        *
- *                                                                           *
-\*****************************************************************************/
-
-static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
-{
-       BUG_ON(intmask == 0);
-
-       if (!host->cmd) {
-               printk(KERN_ERR "%s: Got command interrupt even though no "
-                       "command operation was in progress.\n",
-                       mmc_hostname(host->mmc));
-               sdhci_dumpregs(host);
-               return;
-       }
-
-       if (intmask & SDHCI_INT_RESPONSE)
-               sdhci_finish_command(host);
-       else {
-               if (intmask & SDHCI_INT_TIMEOUT)
-                       host->cmd->error = MMC_ERR_TIMEOUT;
-               else if (intmask & SDHCI_INT_CRC)
-                       host->cmd->error = MMC_ERR_BADCRC;
-               else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
-                       host->cmd->error = MMC_ERR_FAILED;
-               else
-                       host->cmd->error = MMC_ERR_INVALID;
-
-               tasklet_schedule(&host->finish_tasklet);
-       }
-}
-
-static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
-{
-       BUG_ON(intmask == 0);
-
-       if (!host->data) {
-               /*
-                * A data end interrupt is sent together with the response
-                * for the stop command.
-                */
-               if (intmask & SDHCI_INT_DATA_END)
-                       return;
-
-               printk(KERN_ERR "%s: Got data interrupt even though no "
-                       "data operation was in progress.\n",
-                       mmc_hostname(host->mmc));
-               sdhci_dumpregs(host);
-
-               return;
-       }
-
-       if (intmask & SDHCI_INT_DATA_TIMEOUT)
-               host->data->error = MMC_ERR_TIMEOUT;
-       else if (intmask & SDHCI_INT_DATA_CRC)
-               host->data->error = MMC_ERR_BADCRC;
-       else if (intmask & SDHCI_INT_DATA_END_BIT)
-               host->data->error = MMC_ERR_FAILED;
-
-       if (host->data->error != MMC_ERR_NONE)
-               sdhci_finish_data(host);
-       else {
-               if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
-                       sdhci_transfer_pio(host);
-
-               if (intmask & SDHCI_INT_DATA_END)
-                       sdhci_finish_data(host);
-       }
-}
-
-static irqreturn_t sdhci_irq(int irq, void *dev_id)
-{
-       irqreturn_t result;
-       struct sdhci_host* host = dev_id;
-       u32 intmask;
-
-       spin_lock(&host->lock);
-
-       intmask = readl(host->ioaddr + SDHCI_INT_STATUS);
-
-       if (!intmask || intmask == 0xffffffff) {
-               result = IRQ_NONE;
-               goto out;
-       }
-
-       DBG("*** %s got interrupt: 0x%08x\n", host->slot_descr, intmask);
-
-       if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
-               writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE),
-                       host->ioaddr + SDHCI_INT_STATUS);
-               tasklet_schedule(&host->card_tasklet);
-       }
-
-       intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
-
-       if (intmask & SDHCI_INT_CMD_MASK) {
-               writel(intmask & SDHCI_INT_CMD_MASK,
-                       host->ioaddr + SDHCI_INT_STATUS);
-               sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
-       }
-
-       if (intmask & SDHCI_INT_DATA_MASK) {
-               writel(intmask & SDHCI_INT_DATA_MASK,
-                       host->ioaddr + SDHCI_INT_STATUS);
-               sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
-       }
-
-       intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
-
-       if (intmask & SDHCI_INT_BUS_POWER) {
-               printk(KERN_ERR "%s: Card is consuming too much power!\n",
-                       mmc_hostname(host->mmc));
-               writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS);
-       }
-
-       intmask &= SDHCI_INT_BUS_POWER;
-
-       if (intmask) {
-               printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
-                       mmc_hostname(host->mmc), intmask);
-               sdhci_dumpregs(host);
-
-               writel(intmask, host->ioaddr + SDHCI_INT_STATUS);
-       }
-
-       result = IRQ_HANDLED;
-
-       mmiowb();
-out:
-       spin_unlock(&host->lock);
-
-       return result;
-}
-
-/*****************************************************************************\
- *                                                                           *
- * Suspend/resume                                                            *
- *                                                                           *
-\*****************************************************************************/
-
-#ifdef CONFIG_PM
-
-static int sdhci_suspend (struct pci_dev *pdev, pm_message_t state)
-{
-       struct sdhci_chip *chip;
-       int i, ret;
-
-       chip = pci_get_drvdata(pdev);
-       if (!chip)
-               return 0;
-
-       DBG("Suspending...\n");
-
-       for (i = 0;i < chip->num_slots;i++) {
-               if (!chip->hosts[i])
-                       continue;
-               ret = mmc_suspend_host(chip->hosts[i]->mmc, state);
-               if (ret) {
-                       for (i--;i >= 0;i--)
-                               mmc_resume_host(chip->hosts[i]->mmc);
-                       return ret;
-               }
-       }
-
-       pci_save_state(pdev);
-       pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
-
-       for (i = 0;i < chip->num_slots;i++) {
-               if (!chip->hosts[i])
-                       continue;
-               free_irq(chip->hosts[i]->irq, chip->hosts[i]);
-       }
-
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
-
-       return 0;
-}
-
-static int sdhci_resume (struct pci_dev *pdev)
-{
-       struct sdhci_chip *chip;
-       int i, ret;
-
-       chip = pci_get_drvdata(pdev);
-       if (!chip)
-               return 0;
-
-       DBG("Resuming...\n");
-
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
-       ret = pci_enable_device(pdev);
-       if (ret)
-               return ret;
-
-       for (i = 0;i < chip->num_slots;i++) {
-               if (!chip->hosts[i])
-                       continue;
-               if (chip->hosts[i]->flags & SDHCI_USE_DMA)
-                       pci_set_master(pdev);
-               ret = request_irq(chip->hosts[i]->irq, sdhci_irq,
-                       IRQF_SHARED, chip->hosts[i]->slot_descr,
-                       chip->hosts[i]);
-               if (ret)
-                       return ret;
-               sdhci_init(chip->hosts[i]);
-               mmiowb();
-               ret = mmc_resume_host(chip->hosts[i]->mmc);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-#else /* CONFIG_PM */
-
-#define sdhci_suspend NULL
-#define sdhci_resume NULL
-
-#endif /* CONFIG_PM */
-
-/*****************************************************************************\
- *                                                                           *
- * Device probing/removal                                                    *
- *                                                                           *
-\*****************************************************************************/
-
-static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
-{
-       int ret;
-       unsigned int version;
-       struct sdhci_chip *chip;
-       struct mmc_host *mmc;
-       struct sdhci_host *host;
-
-       u8 first_bar;
-       unsigned int caps;
-
-       chip = pci_get_drvdata(pdev);
-       BUG_ON(!chip);
-
-       ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
-       if (ret)
-               return ret;
-
-       first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
-
-       if (first_bar > 5) {
-               printk(KERN_ERR DRIVER_NAME ": Invalid first BAR. Aborting.\n");
-               return -ENODEV;
-       }
-
-       if (!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)) {
-               printk(KERN_ERR DRIVER_NAME ": BAR is not iomem. Aborting.\n");
-               return -ENODEV;
-       }
-
-       if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
-               printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. "
-                       "You may experience problems.\n");
-       }
-
-       if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
-               printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n");
-               return -ENODEV;
-       }
-
-       if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
-               printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n");
-               return -ENODEV;
-       }
-
-       mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
-       if (!mmc)
-               return -ENOMEM;
-
-       host = mmc_priv(mmc);
-       host->mmc = mmc;
-
-       host->chip = chip;
-       chip->hosts[slot] = host;
-
-       host->bar = first_bar + slot;
-
-       host->addr = pci_resource_start(pdev, host->bar);
-       host->irq = pdev->irq;
-
-       DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq);
-
-       snprintf(host->slot_descr, 20, "sdhci:slot%d", slot);
-
-       ret = pci_request_region(pdev, host->bar, host->slot_descr);
-       if (ret)
-               goto free;
-
-       host->ioaddr = ioremap_nocache(host->addr,
-               pci_resource_len(pdev, host->bar));
-       if (!host->ioaddr) {
-               ret = -ENOMEM;
-               goto release;
-       }
-
-       sdhci_reset(host, SDHCI_RESET_ALL);
-
-       version = readw(host->ioaddr + SDHCI_HOST_VERSION);
-       version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
-       if (version != 0) {
-               printk(KERN_ERR "%s: Unknown controller version (%d). "
-                       "You may experience problems.\n", host->slot_descr,
-                       version);
-       }
-
-       caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
-
-       if (debug_nodma)
-               DBG("DMA forced off\n");
-       else if (debug_forcedma) {
-               DBG("DMA forced on\n");
-               host->flags |= SDHCI_USE_DMA;
-       } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
-               host->flags |= SDHCI_USE_DMA;
-       else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
-               DBG("Controller doesn't have DMA interface\n");
-       else if (!(caps & SDHCI_CAN_DO_DMA))
-               DBG("Controller doesn't have DMA capability\n");
-       else
-               host->flags |= SDHCI_USE_DMA;
-
-       if (host->flags & SDHCI_USE_DMA) {
-               if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
-                       printk(KERN_WARNING "%s: No suitable DMA available. "
-                               "Falling back to PIO.\n", host->slot_descr);
-                       host->flags &= ~SDHCI_USE_DMA;
-               }
-       }
-
-       if (host->flags & SDHCI_USE_DMA)
-               pci_set_master(pdev);
-       else /* XXX: Hack to get MMC layer to avoid highmem */
-               pdev->dma_mask = 0;
-
-       host->max_clk =
-               (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
-       if (host->max_clk == 0) {
-               printk(KERN_ERR "%s: Hardware doesn't specify base clock "
-                       "frequency.\n", host->slot_descr);
-               ret = -ENODEV;
-               goto unmap;
-       }
-       host->max_clk *= 1000000;
-
-       host->timeout_clk =
-               (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
-       if (host->timeout_clk == 0) {
-               printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
-                       "frequency.\n", host->slot_descr);
-               ret = -ENODEV;
-               goto unmap;
-       }
-       if (caps & SDHCI_TIMEOUT_CLK_UNIT)
-               host->timeout_clk *= 1000;
-
-       /*
-        * Set host parameters.
-        */
-       mmc->ops = &sdhci_ops;
-       mmc->f_min = host->max_clk / 256;
-       mmc->f_max = host->max_clk;
-       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
-
-       if (caps & SDHCI_CAN_DO_HISPD)
-               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
-
-       mmc->ocr_avail = 0;
-       if (caps & SDHCI_CAN_VDD_330)
-               mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
-       if (caps & SDHCI_CAN_VDD_300)
-               mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
-       if (caps & SDHCI_CAN_VDD_180)
-               mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
-
-       if (mmc->ocr_avail == 0) {
-               printk(KERN_ERR "%s: Hardware doesn't report any "
-                       "support voltages.\n", host->slot_descr);
-               ret = -ENODEV;
-               goto unmap;
-       }
-
-       spin_lock_init(&host->lock);
-
-       /*
-        * Maximum number of segments. Hardware cannot do scatter lists.
-        */
-       if (host->flags & SDHCI_USE_DMA)
-               mmc->max_hw_segs = 1;
-       else
-               mmc->max_hw_segs = 16;
-       mmc->max_phys_segs = 16;
-
-       /*
-        * Maximum number of sectors in one transfer. Limited by DMA boundary
-        * size (512KiB).
-        */
-       mmc->max_req_size = 524288;
-
-       /*
-        * Maximum segment size. Could be one segment with the maximum number
-        * of bytes.
-        */
-       mmc->max_seg_size = mmc->max_req_size;
-
-       /*
-        * Maximum block size. This varies from controller to controller and
-        * is specified in the capabilities register.
-        */
-       mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
-       if (mmc->max_blk_size >= 3) {
-               printk(KERN_ERR "%s: Invalid maximum block size.\n",
-                       host->slot_descr);
-               ret = -ENODEV;
-               goto unmap;
-       }
-       mmc->max_blk_size = 512 << mmc->max_blk_size;
-
-       /*
-        * Maximum block count.
-        */
-       mmc->max_blk_count = 65535;
-
-       /*
-        * Init tasklets.
-        */
-       tasklet_init(&host->card_tasklet,
-               sdhci_tasklet_card, (unsigned long)host);
-       tasklet_init(&host->finish_tasklet,
-               sdhci_tasklet_finish, (unsigned long)host);
-
-       setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
-
-       ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-               host->slot_descr, host);
-       if (ret)
-               goto untasklet;
-
-       sdhci_init(host);
-
-#ifdef CONFIG_MMC_DEBUG
-       sdhci_dumpregs(host);
-#endif
-
-       mmiowb();
-
-       mmc_add_host(mmc);
-
-       printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", mmc_hostname(mmc),
-               host->addr, host->irq,
-               (host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
-
-       return 0;
-
-untasklet:
-       tasklet_kill(&host->card_tasklet);
-       tasklet_kill(&host->finish_tasklet);
-unmap:
-       iounmap(host->ioaddr);
-release:
-       pci_release_region(pdev, host->bar);
-free:
-       mmc_free_host(mmc);
-
-       return ret;
-}
-
-static void sdhci_remove_slot(struct pci_dev *pdev, int slot)
-{
-       struct sdhci_chip *chip;
-       struct mmc_host *mmc;
-       struct sdhci_host *host;
-
-       chip = pci_get_drvdata(pdev);
-       host = chip->hosts[slot];
-       mmc = host->mmc;
-
-       chip->hosts[slot] = NULL;
-
-       mmc_remove_host(mmc);
-
-       sdhci_reset(host, SDHCI_RESET_ALL);
-
-       free_irq(host->irq, host);
-
-       del_timer_sync(&host->timer);
-
-       tasklet_kill(&host->card_tasklet);
-       tasklet_kill(&host->finish_tasklet);
-
-       iounmap(host->ioaddr);
-
-       pci_release_region(pdev, host->bar);
-
-       mmc_free_host(mmc);
-}
-
-static int __devinit sdhci_probe(struct pci_dev *pdev,
-       const struct pci_device_id *ent)
-{
-       int ret, i;
-       u8 slots, rev;
-       struct sdhci_chip *chip;
-
-       BUG_ON(pdev == NULL);
-       BUG_ON(ent == NULL);
-
-       pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
-
-       printk(KERN_INFO DRIVER_NAME
-               ": SDHCI controller found at %s [%04x:%04x] (rev %x)\n",
-               pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
-               (int)rev);
-
-       ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
-       if (ret)
-               return ret;
-
-       slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
-       DBG("found %d slot(s)\n", slots);
-       if (slots == 0)
-               return -ENODEV;
-
-       ret = pci_enable_device(pdev);
-       if (ret)
-               return ret;
-
-       chip = kzalloc(sizeof(struct sdhci_chip) +
-               sizeof(struct sdhci_host*) * slots, GFP_KERNEL);
-       if (!chip) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       chip->pdev = pdev;
-       chip->quirks = ent->driver_data;
-
-       if (debug_quirks)
-               chip->quirks = debug_quirks;
-
-       chip->num_slots = slots;
-       pci_set_drvdata(pdev, chip);
-
-       for (i = 0;i < slots;i++) {
-               ret = sdhci_probe_slot(pdev, i);
-               if (ret) {
-                       for (i--;i >= 0;i--)
-                               sdhci_remove_slot(pdev, i);
-                       goto free;
-               }
-       }
-
-       return 0;
-
-free:
-       pci_set_drvdata(pdev, NULL);
-       kfree(chip);
-
-err:
-       pci_disable_device(pdev);
-       return ret;
-}
-
-static void __devexit sdhci_remove(struct pci_dev *pdev)
-{
-       int i;
-       struct sdhci_chip *chip;
-
-       chip = pci_get_drvdata(pdev);
-
-       if (chip) {
-               for (i = 0;i < chip->num_slots;i++)
-                       sdhci_remove_slot(pdev, i);
-
-               pci_set_drvdata(pdev, NULL);
-
-               kfree(chip);
-       }
-
-       pci_disable_device(pdev);
-}
-
-static struct pci_driver sdhci_driver = {
-       .name =         DRIVER_NAME,
-       .id_table =     pci_ids,
-       .probe =        sdhci_probe,
-       .remove =       __devexit_p(sdhci_remove),
-       .suspend =      sdhci_suspend,
-       .resume =       sdhci_resume,
-};
-
-/*****************************************************************************\
- *                                                                           *
- * Driver init/exit                                                          *
- *                                                                           *
-\*****************************************************************************/
-
-static int __init sdhci_drv_init(void)
-{
-       printk(KERN_INFO DRIVER_NAME
-               ": Secure Digital Host Controller Interface driver\n");
-       printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
-
-       return pci_register_driver(&sdhci_driver);
-}
-
-static void __exit sdhci_drv_exit(void)
-{
-       DBG("Exiting\n");
-
-       pci_unregister_driver(&sdhci_driver);
-}
-
-module_init(sdhci_drv_init);
-module_exit(sdhci_drv_exit);
-
-module_param(debug_nodma, uint, 0444);
-module_param(debug_forcedma, uint, 0444);
-module_param(debug_quirks, uint, 0444);
-
-MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
-MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
-MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)");
-MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h
deleted file mode 100644 (file)
index 7400f4b..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- *  linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver
- *
- *  Copyright (C) 2005-2007 Pierre Ossman, 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 as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-/*
- * PCI registers
- */
-
-#define PCI_SDHCI_IFPIO                        0x00
-#define PCI_SDHCI_IFDMA                        0x01
-#define PCI_SDHCI_IFVENDOR             0x02
-
-#define PCI_SLOT_INFO                  0x40    /* 8 bits */
-#define  PCI_SLOT_INFO_SLOTS(x)                ((x >> 4) & 7)
-#define  PCI_SLOT_INFO_FIRST_BAR_MASK  0x07
-
-/*
- * Controller registers
- */
-
-#define SDHCI_DMA_ADDRESS      0x00
-
-#define SDHCI_BLOCK_SIZE       0x04
-#define  SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
-
-#define SDHCI_BLOCK_COUNT      0x06
-
-#define SDHCI_ARGUMENT         0x08
-
-#define SDHCI_TRANSFER_MODE    0x0C
-#define  SDHCI_TRNS_DMA                0x01
-#define  SDHCI_TRNS_BLK_CNT_EN 0x02
-#define  SDHCI_TRNS_ACMD12     0x04
-#define  SDHCI_TRNS_READ       0x10
-#define  SDHCI_TRNS_MULTI      0x20
-
-#define SDHCI_COMMAND          0x0E
-#define  SDHCI_CMD_RESP_MASK   0x03
-#define  SDHCI_CMD_CRC         0x08
-#define  SDHCI_CMD_INDEX       0x10
-#define  SDHCI_CMD_DATA                0x20
-
-#define  SDHCI_CMD_RESP_NONE   0x00
-#define  SDHCI_CMD_RESP_LONG   0x01
-#define  SDHCI_CMD_RESP_SHORT  0x02
-#define  SDHCI_CMD_RESP_SHORT_BUSY 0x03
-
-#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
-
-#define SDHCI_RESPONSE         0x10
-
-#define SDHCI_BUFFER           0x20
-
-#define SDHCI_PRESENT_STATE    0x24
-#define  SDHCI_CMD_INHIBIT     0x00000001
-#define  SDHCI_DATA_INHIBIT    0x00000002
-#define  SDHCI_DOING_WRITE     0x00000100
-#define  SDHCI_DOING_READ      0x00000200
-#define  SDHCI_SPACE_AVAILABLE 0x00000400
-#define  SDHCI_DATA_AVAILABLE  0x00000800
-#define  SDHCI_CARD_PRESENT    0x00010000
-#define  SDHCI_WRITE_PROTECT   0x00080000
-
-#define SDHCI_HOST_CONTROL     0x28
-#define  SDHCI_CTRL_LED                0x01
-#define  SDHCI_CTRL_4BITBUS    0x02
-#define  SDHCI_CTRL_HISPD      0x04
-
-#define SDHCI_POWER_CONTROL    0x29
-#define  SDHCI_POWER_ON                0x01
-#define  SDHCI_POWER_180       0x0A
-#define  SDHCI_POWER_300       0x0C
-#define  SDHCI_POWER_330       0x0E
-
-#define SDHCI_BLOCK_GAP_CONTROL        0x2A
-
-#define SDHCI_WALK_UP_CONTROL  0x2B
-
-#define SDHCI_CLOCK_CONTROL    0x2C
-#define  SDHCI_DIVIDER_SHIFT   8
-#define  SDHCI_CLOCK_CARD_EN   0x0004
-#define  SDHCI_CLOCK_INT_STABLE        0x0002
-#define  SDHCI_CLOCK_INT_EN    0x0001
-
-#define SDHCI_TIMEOUT_CONTROL  0x2E
-
-#define SDHCI_SOFTWARE_RESET   0x2F
-#define  SDHCI_RESET_ALL       0x01
-#define  SDHCI_RESET_CMD       0x02
-#define  SDHCI_RESET_DATA      0x04
-
-#define SDHCI_INT_STATUS       0x30
-#define SDHCI_INT_ENABLE       0x34
-#define SDHCI_SIGNAL_ENABLE    0x38
-#define  SDHCI_INT_RESPONSE    0x00000001
-#define  SDHCI_INT_DATA_END    0x00000002
-#define  SDHCI_INT_DMA_END     0x00000008
-#define  SDHCI_INT_SPACE_AVAIL 0x00000010
-#define  SDHCI_INT_DATA_AVAIL  0x00000020
-#define  SDHCI_INT_CARD_INSERT 0x00000040
-#define  SDHCI_INT_CARD_REMOVE 0x00000080
-#define  SDHCI_INT_CARD_INT    0x00000100
-#define  SDHCI_INT_TIMEOUT     0x00010000
-#define  SDHCI_INT_CRC         0x00020000
-#define  SDHCI_INT_END_BIT     0x00040000
-#define  SDHCI_INT_INDEX       0x00080000
-#define  SDHCI_INT_DATA_TIMEOUT        0x00100000
-#define  SDHCI_INT_DATA_CRC    0x00200000
-#define  SDHCI_INT_DATA_END_BIT        0x00400000
-#define  SDHCI_INT_BUS_POWER   0x00800000
-#define  SDHCI_INT_ACMD12ERR   0x01000000
-
-#define  SDHCI_INT_NORMAL_MASK 0x00007FFF
-#define  SDHCI_INT_ERROR_MASK  0xFFFF8000
-
-#define  SDHCI_INT_CMD_MASK    (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
-               SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
-#define  SDHCI_INT_DATA_MASK   (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
-               SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
-               SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
-               SDHCI_INT_DATA_END_BIT)
-
-#define SDHCI_ACMD12_ERR       0x3C
-
-/* 3E-3F reserved */
-
-#define SDHCI_CAPABILITIES     0x40
-#define  SDHCI_TIMEOUT_CLK_MASK        0x0000003F
-#define  SDHCI_TIMEOUT_CLK_SHIFT 0
-#define  SDHCI_TIMEOUT_CLK_UNIT        0x00000080
-#define  SDHCI_CLOCK_BASE_MASK 0x00003F00
-#define  SDHCI_CLOCK_BASE_SHIFT        8
-#define  SDHCI_MAX_BLOCK_MASK  0x00030000
-#define  SDHCI_MAX_BLOCK_SHIFT  16
-#define  SDHCI_CAN_DO_HISPD    0x00200000
-#define  SDHCI_CAN_DO_DMA      0x00400000
-#define  SDHCI_CAN_VDD_330     0x01000000
-#define  SDHCI_CAN_VDD_300     0x02000000
-#define  SDHCI_CAN_VDD_180     0x04000000
-
-/* 44-47 reserved for more caps */
-
-#define SDHCI_MAX_CURRENT      0x48
-
-/* 4C-4F reserved for more max current */
-
-/* 50-FB reserved */
-
-#define SDHCI_SLOT_INT_STATUS  0xFC
-
-#define SDHCI_HOST_VERSION     0xFE
-#define  SDHCI_VENDOR_VER_MASK 0xFF00
-#define  SDHCI_VENDOR_VER_SHIFT        8
-#define  SDHCI_SPEC_VER_MASK   0x00FF
-#define  SDHCI_SPEC_VER_SHIFT  0
-
-struct sdhci_chip;
-
-struct sdhci_host {
-       struct sdhci_chip       *chip;
-       struct mmc_host         *mmc;           /* MMC structure */
-
-       spinlock_t              lock;           /* Mutex */
-
-       int                     flags;          /* Host attributes */
-#define SDHCI_USE_DMA          (1<<0)
-
-       unsigned int            max_clk;        /* Max possible freq (MHz) */
-       unsigned int            timeout_clk;    /* Timeout freq (KHz) */
-
-       unsigned int            clock;          /* Current clock (MHz) */
-       unsigned short          power;          /* Current voltage */
-
-       struct mmc_request      *mrq;           /* Current request */
-       struct mmc_command      *cmd;           /* Current command */
-       struct mmc_data         *data;          /* Current data request */
-
-       struct scatterlist      *cur_sg;        /* We're working on this */
-       int                     num_sg;         /* Entries left */
-       int                     offset;         /* Offset into current sg */
-       int                     remain;         /* Bytes left in current */
-
-       char                    slot_descr[20]; /* Name for reservations */
-
-       int                     irq;            /* Device IRQ */
-       int                     bar;            /* PCI BAR index */
-       unsigned long           addr;           /* Bus address */
-       void __iomem *          ioaddr;         /* Mapped address */
-
-       struct tasklet_struct   card_tasklet;   /* Tasklet structures */
-       struct tasklet_struct   finish_tasklet;
-
-       struct timer_list       timer;          /* Timer for timeouts */
-};
-
-struct sdhci_chip {
-       struct pci_dev          *pdev;
-
-       unsigned long           quirks;
-
-       int                     num_slots;      /* Slots on controller */
-       struct sdhci_host       *hosts[0];      /* Pointers to hosts */
-};
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
deleted file mode 100644 (file)
index b0d77d2..0000000
+++ /dev/null
@@ -1,1102 +0,0 @@
-/*
- *  tifm_sd.c - TI FlashMedia driver
- *
- *  Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
- *
- * 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.
- *
- * Special thanks to Brad Campbell for extensive testing of this driver.
- *
- */
-
-
-#include <linux/tifm.h>
-#include <linux/mmc/host.h>
-#include <linux/highmem.h>
-#include <linux/scatterlist.h>
-#include <asm/io.h>
-
-#define DRIVER_NAME "tifm_sd"
-#define DRIVER_VERSION "0.8"
-
-static int no_dma = 0;
-static int fixed_timeout = 0;
-module_param(no_dma, bool, 0644);
-module_param(fixed_timeout, bool, 0644);
-
-/* Constants here are mostly from OMAP5912 datasheet */
-#define TIFM_MMCSD_RESET      0x0002
-#define TIFM_MMCSD_CLKMASK    0x03ff
-#define TIFM_MMCSD_POWER      0x0800
-#define TIFM_MMCSD_4BBUS      0x8000
-#define TIFM_MMCSD_RXDE       0x8000   /* rx dma enable */
-#define TIFM_MMCSD_TXDE       0x0080   /* tx dma enable */
-#define TIFM_MMCSD_BUFINT     0x0c00   /* set bits: AE, AF */
-#define TIFM_MMCSD_DPE        0x0020   /* data timeout counted in kilocycles */
-#define TIFM_MMCSD_INAB       0x0080   /* abort / initialize command */
-#define TIFM_MMCSD_READ       0x8000
-
-#define TIFM_MMCSD_ERRMASK    0x01e0   /* set bits: CCRC, CTO, DCRC, DTO */
-#define TIFM_MMCSD_EOC        0x0001   /* end of command phase  */
-#define TIFM_MMCSD_CD         0x0002   /* card detect           */
-#define TIFM_MMCSD_CB         0x0004   /* card enter busy state */
-#define TIFM_MMCSD_BRS        0x0008   /* block received/sent   */
-#define TIFM_MMCSD_EOFB       0x0010   /* card exit busy state  */
-#define TIFM_MMCSD_DTO        0x0020   /* data time-out         */
-#define TIFM_MMCSD_DCRC       0x0040   /* data crc error        */
-#define TIFM_MMCSD_CTO        0x0080   /* command time-out      */
-#define TIFM_MMCSD_CCRC       0x0100   /* command crc error     */
-#define TIFM_MMCSD_AF         0x0400   /* fifo almost full      */
-#define TIFM_MMCSD_AE         0x0800   /* fifo almost empty     */
-#define TIFM_MMCSD_OCRB       0x1000   /* OCR busy              */
-#define TIFM_MMCSD_CIRQ       0x2000   /* card irq (cmd40/sdio) */
-#define TIFM_MMCSD_CERR       0x4000   /* card status error     */
-
-#define TIFM_MMCSD_ODTO       0x0040   /* open drain / extended timeout */
-#define TIFM_MMCSD_CARD_RO    0x0200   /* card is read-only     */
-
-#define TIFM_MMCSD_FIFO_SIZE  0x0020
-
-#define TIFM_MMCSD_RSP_R0     0x0000
-#define TIFM_MMCSD_RSP_R1     0x0100
-#define TIFM_MMCSD_RSP_R2     0x0200
-#define TIFM_MMCSD_RSP_R3     0x0300
-#define TIFM_MMCSD_RSP_R4     0x0400
-#define TIFM_MMCSD_RSP_R5     0x0500
-#define TIFM_MMCSD_RSP_R6     0x0600
-
-#define TIFM_MMCSD_RSP_BUSY   0x0800
-
-#define TIFM_MMCSD_CMD_BC     0x0000
-#define TIFM_MMCSD_CMD_BCR    0x1000
-#define TIFM_MMCSD_CMD_AC     0x2000
-#define TIFM_MMCSD_CMD_ADTC   0x3000
-
-#define TIFM_MMCSD_MAX_BLOCK_SIZE  0x0800UL
-
-enum {
-       CMD_READY    = 0x0001,
-       FIFO_READY   = 0x0002,
-       BRS_READY    = 0x0004,
-       SCMD_ACTIVE  = 0x0008,
-       SCMD_READY   = 0x0010,
-       CARD_BUSY    = 0x0020,
-       DATA_CARRY   = 0x0040
-};
-
-struct tifm_sd {
-       struct tifm_dev       *dev;
-
-       unsigned short        eject:1,
-                             open_drain:1,
-                             no_dma:1;
-       unsigned short        cmd_flags;
-
-       unsigned int          clk_freq;
-       unsigned int          clk_div;
-       unsigned long         timeout_jiffies;
-
-       struct tasklet_struct finish_tasklet;
-       struct timer_list     timer;
-       struct mmc_request    *req;
-
-       int                   sg_len;
-       int                   sg_pos;
-       unsigned int          block_pos;
-       struct scatterlist    bounce_buf;
-       unsigned char         bounce_buf_data[TIFM_MMCSD_MAX_BLOCK_SIZE];
-};
-
-/* for some reason, host won't respond correctly to readw/writew */
-static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
-                             unsigned int off, unsigned int cnt)
-{
-       struct tifm_dev *sock = host->dev;
-       unsigned char *buf;
-       unsigned int pos = 0, val;
-
-       buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + off;
-       if (host->cmd_flags & DATA_CARRY) {
-               buf[pos++] = host->bounce_buf_data[0];
-               host->cmd_flags &= ~DATA_CARRY;
-       }
-
-       while (pos < cnt) {
-               val = readl(sock->addr + SOCK_MMCSD_DATA);
-               buf[pos++] = val & 0xff;
-               if (pos == cnt) {
-                       host->bounce_buf_data[0] = (val >> 8) & 0xff;
-                       host->cmd_flags |= DATA_CARRY;
-                       break;
-               }
-               buf[pos++] = (val >> 8) & 0xff;
-       }
-       kunmap_atomic(buf - off, KM_BIO_DST_IRQ);
-}
-
-static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
-                              unsigned int off, unsigned int cnt)
-{
-       struct tifm_dev *sock = host->dev;
-       unsigned char *buf;
-       unsigned int pos = 0, val;
-
-       buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + off;
-       if (host->cmd_flags & DATA_CARRY) {
-               val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00);
-               writel(val, sock->addr + SOCK_MMCSD_DATA);
-               host->cmd_flags &= ~DATA_CARRY;
-       }
-
-       while (pos < cnt) {
-               val = buf[pos++];
-               if (pos == cnt) {
-                       host->bounce_buf_data[0] = val & 0xff;
-                       host->cmd_flags |= DATA_CARRY;
-                       break;
-               }
-               val |= (buf[pos++] << 8) & 0xff00;
-               writel(val, sock->addr + SOCK_MMCSD_DATA);
-       }
-       kunmap_atomic(buf - off, KM_BIO_SRC_IRQ);
-}
-
-static void tifm_sd_transfer_data(struct tifm_sd *host)
-{
-       struct mmc_data *r_data = host->req->cmd->data;
-       struct scatterlist *sg = r_data->sg;
-       unsigned int off, cnt, t_size = TIFM_MMCSD_FIFO_SIZE * 2;
-       unsigned int p_off, p_cnt;
-       struct page *pg;
-
-       if (host->sg_pos == host->sg_len)
-               return;
-       while (t_size) {
-               cnt = sg[host->sg_pos].length - host->block_pos;
-               if (!cnt) {
-                       host->block_pos = 0;
-                       host->sg_pos++;
-                       if (host->sg_pos == host->sg_len) {
-                               if ((r_data->flags & MMC_DATA_WRITE)
-                                   && DATA_CARRY)
-                                       writel(host->bounce_buf_data[0],
-                                              host->dev->addr
-                                              + SOCK_MMCSD_DATA);
-
-                               return;
-                       }
-                       cnt = sg[host->sg_pos].length;
-               }
-               off = sg[host->sg_pos].offset + host->block_pos;
-
-               pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
-               p_off = offset_in_page(off);
-               p_cnt = PAGE_SIZE - p_off;
-               p_cnt = min(p_cnt, cnt);
-               p_cnt = min(p_cnt, t_size);
-
-               if (r_data->flags & MMC_DATA_READ)
-                       tifm_sd_read_fifo(host, pg, p_off, p_cnt);
-               else if (r_data->flags & MMC_DATA_WRITE)
-                       tifm_sd_write_fifo(host, pg, p_off, p_cnt);
-
-               t_size -= p_cnt;
-               host->block_pos += p_cnt;
-       }
-}
-
-static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off,
-                             struct page *src, unsigned int src_off,
-                             unsigned int count)
-{
-       unsigned char *src_buf = kmap_atomic(src, KM_BIO_SRC_IRQ) + src_off;
-       unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off;
-
-       memcpy(dst_buf, src_buf, count);
-
-       kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ);
-       kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ);
-}
-
-static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data)
-{
-       struct scatterlist *sg = r_data->sg;
-       unsigned int t_size = r_data->blksz;
-       unsigned int off, cnt;
-       unsigned int p_off, p_cnt;
-       struct page *pg;
-
-       dev_dbg(&host->dev->dev, "bouncing block\n");
-       while (t_size) {
-               cnt = sg[host->sg_pos].length - host->block_pos;
-               if (!cnt) {
-                       host->block_pos = 0;
-                       host->sg_pos++;
-                       if (host->sg_pos == host->sg_len)
-                               return;
-                       cnt = sg[host->sg_pos].length;
-               }
-               off = sg[host->sg_pos].offset + host->block_pos;
-
-               pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
-               p_off = offset_in_page(off);
-               p_cnt = PAGE_SIZE - p_off;
-               p_cnt = min(p_cnt, cnt);
-               p_cnt = min(p_cnt, t_size);
-
-               if (r_data->flags & MMC_DATA_WRITE)
-                       tifm_sd_copy_page(host->bounce_buf.page,
-                                         r_data->blksz - t_size,
-                                         pg, p_off, p_cnt);
-               else if (r_data->flags & MMC_DATA_READ)
-                       tifm_sd_copy_page(pg, p_off, host->bounce_buf.page,
-                                         r_data->blksz - t_size, p_cnt);
-
-               t_size -= p_cnt;
-               host->block_pos += p_cnt;
-       }
-}
-
-int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data)
-{
-       struct tifm_dev *sock = host->dev;
-       unsigned int t_size = TIFM_DMA_TSIZE * r_data->blksz;
-       unsigned int dma_len, dma_blk_cnt, dma_off;
-       struct scatterlist *sg = NULL;
-       unsigned long flags;
-
-       if (host->sg_pos == host->sg_len)
-               return 1;
-
-       if (host->cmd_flags & DATA_CARRY) {
-               host->cmd_flags &= ~DATA_CARRY;
-               local_irq_save(flags);
-               tifm_sd_bounce_block(host, r_data);
-               local_irq_restore(flags);
-               if (host->sg_pos == host->sg_len)
-                       return 1;
-       }
-
-       dma_len = sg_dma_len(&r_data->sg[host->sg_pos]) - host->block_pos;
-       if (!dma_len) {
-               host->block_pos = 0;
-               host->sg_pos++;
-               if (host->sg_pos == host->sg_len)
-                       return 1;
-               dma_len = sg_dma_len(&r_data->sg[host->sg_pos]);
-       }
-
-       if (dma_len < t_size) {
-               dma_blk_cnt = dma_len / r_data->blksz;
-               dma_off = host->block_pos;
-               host->block_pos += dma_blk_cnt * r_data->blksz;
-       } else {
-               dma_blk_cnt = TIFM_DMA_TSIZE;
-               dma_off = host->block_pos;
-               host->block_pos += t_size;
-       }
-
-       if (dma_blk_cnt)
-               sg = &r_data->sg[host->sg_pos];
-       else if (dma_len) {
-               if (r_data->flags & MMC_DATA_WRITE) {
-                       local_irq_save(flags);
-                       tifm_sd_bounce_block(host, r_data);
-                       local_irq_restore(flags);
-               } else
-                       host->cmd_flags |= DATA_CARRY;
-
-               sg = &host->bounce_buf;
-               dma_off = 0;
-               dma_blk_cnt = 1;
-       } else
-               return 1;
-
-       dev_dbg(&sock->dev, "setting dma for %d blocks\n", dma_blk_cnt);
-       writel(sg_dma_address(sg) + dma_off, sock->addr + SOCK_DMA_ADDRESS);
-       if (r_data->flags & MMC_DATA_WRITE)
-               writel((dma_blk_cnt << 8) | TIFM_DMA_TX | TIFM_DMA_EN,
-                      sock->addr + SOCK_DMA_CONTROL);
-       else
-               writel((dma_blk_cnt << 8) | TIFM_DMA_EN,
-                      sock->addr + SOCK_DMA_CONTROL);
-
-       return 0;
-}
-
-static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
-{
-       unsigned int rc = 0;
-
-       switch (mmc_resp_type(cmd)) {
-       case MMC_RSP_NONE:
-               rc |= TIFM_MMCSD_RSP_R0;
-               break;
-       case MMC_RSP_R1B:
-               rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through
-       case MMC_RSP_R1:
-               rc |= TIFM_MMCSD_RSP_R1;
-               break;
-       case MMC_RSP_R2:
-               rc |= TIFM_MMCSD_RSP_R2;
-               break;
-       case MMC_RSP_R3:
-               rc |= TIFM_MMCSD_RSP_R3;
-               break;
-       default:
-               BUG();
-       }
-
-       switch (mmc_cmd_type(cmd)) {
-       case MMC_CMD_BC:
-               rc |= TIFM_MMCSD_CMD_BC;
-               break;
-       case MMC_CMD_BCR:
-               rc |= TIFM_MMCSD_CMD_BCR;
-               break;
-       case MMC_CMD_AC:
-               rc |= TIFM_MMCSD_CMD_AC;
-               break;
-       case MMC_CMD_ADTC:
-               rc |= TIFM_MMCSD_CMD_ADTC;
-               break;
-       default:
-               BUG();
-       }
-       return rc;
-}
-
-static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
-{
-       struct tifm_dev *sock = host->dev;
-       unsigned int cmd_mask = tifm_sd_op_flags(cmd);
-
-       if (host->open_drain)
-               cmd_mask |= TIFM_MMCSD_ODTO;
-
-       if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
-               cmd_mask |= TIFM_MMCSD_READ;
-
-       dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
-               cmd->opcode, cmd->arg, cmd_mask);
-
-       writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
-       writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
-       writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND);
-}
-
-static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock)
-{
-       cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16)
-                      | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18);
-       cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16)
-                      | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10);
-       cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16)
-                      | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08);
-       cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16)
-                      | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00);
-}
-
-static void tifm_sd_check_status(struct tifm_sd *host)
-{
-       struct tifm_dev *sock = host->dev;
-       struct mmc_command *cmd = host->req->cmd;
-
-       if (cmd->error != MMC_ERR_NONE)
-               goto finish_request;
-
-       if (!(host->cmd_flags & CMD_READY))
-               return;
-
-       if (cmd->data) {
-               if (cmd->data->error != MMC_ERR_NONE) {
-                       if ((host->cmd_flags & SCMD_ACTIVE)
-                           && !(host->cmd_flags & SCMD_READY))
-                               return;
-
-                       goto finish_request;
-               }
-
-               if (!(host->cmd_flags & BRS_READY))
-                       return;
-
-               if (!(host->no_dma || (host->cmd_flags & FIFO_READY)))
-                       return;
-
-               if (cmd->data->flags & MMC_DATA_WRITE) {
-                       if (host->req->stop) {
-                               if (!(host->cmd_flags & SCMD_ACTIVE)) {
-                                       host->cmd_flags |= SCMD_ACTIVE;
-                                       writel(TIFM_MMCSD_EOFB
-                                              | readl(sock->addr
-                                                      + SOCK_MMCSD_INT_ENABLE),
-                                              sock->addr
-                                              + SOCK_MMCSD_INT_ENABLE);
-                                       tifm_sd_exec(host, host->req->stop);
-                                       return;
-                               } else {
-                                       if (!(host->cmd_flags & SCMD_READY)
-                                           || (host->cmd_flags & CARD_BUSY))
-                                               return;
-                                       writel((~TIFM_MMCSD_EOFB)
-                                              & readl(sock->addr
-                                                      + SOCK_MMCSD_INT_ENABLE),
-                                              sock->addr
-                                              + SOCK_MMCSD_INT_ENABLE);
-                               }
-                       } else {
-                               if (host->cmd_flags & CARD_BUSY)
-                                       return;
-                               writel((~TIFM_MMCSD_EOFB)
-                                      & readl(sock->addr
-                                              + SOCK_MMCSD_INT_ENABLE),
-                                      sock->addr + SOCK_MMCSD_INT_ENABLE);
-                       }
-               } else {
-                       if (host->req->stop) {
-                               if (!(host->cmd_flags & SCMD_ACTIVE)) {
-                                       host->cmd_flags |= SCMD_ACTIVE;
-                                       tifm_sd_exec(host, host->req->stop);
-                                       return;
-                               } else {
-                                       if (!(host->cmd_flags & SCMD_READY))
-                                               return;
-                               }
-                       }
-               }
-       }
-finish_request:
-       tasklet_schedule(&host->finish_tasklet);
-}
-
-/* Called from interrupt handler */
-static void tifm_sd_data_event(struct tifm_dev *sock)
-{
-       struct tifm_sd *host;
-       unsigned int fifo_status = 0;
-       struct mmc_data *r_data = NULL;
-
-       spin_lock(&sock->lock);
-       host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
-       fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
-       dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n",
-               fifo_status, host->cmd_flags);
-
-       if (host->req) {
-               r_data = host->req->cmd->data;
-
-               if (r_data && (fifo_status & TIFM_FIFO_READY)) {
-                       if (tifm_sd_set_dma_data(host, r_data)) {
-                               host->cmd_flags |= FIFO_READY;
-                               tifm_sd_check_status(host);
-                       }
-               }
-       }
-
-       writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
-       spin_unlock(&sock->lock);
-}
-
-/* Called from interrupt handler */
-static void tifm_sd_card_event(struct tifm_dev *sock)
-{
-       struct tifm_sd *host;
-       unsigned int host_status = 0;
-       int cmd_error = MMC_ERR_NONE;
-       struct mmc_command *cmd = NULL;
-       unsigned long flags;
-
-       spin_lock(&sock->lock);
-       host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
-       host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
-       dev_dbg(&sock->dev, "host event: host_status %x, flags %x\n",
-               host_status, host->cmd_flags);
-
-       if (host->req) {
-               cmd = host->req->cmd;
-
-               if (host_status & TIFM_MMCSD_ERRMASK) {
-                       writel(host_status & TIFM_MMCSD_ERRMASK,
-                              sock->addr + SOCK_MMCSD_STATUS);
-                       if (host_status & TIFM_MMCSD_CTO)
-                               cmd_error = MMC_ERR_TIMEOUT;
-                       else if (host_status & TIFM_MMCSD_CCRC)
-                               cmd_error = MMC_ERR_BADCRC;
-
-                       if (cmd->data) {
-                               if (host_status & TIFM_MMCSD_DTO)
-                                       cmd->data->error = MMC_ERR_TIMEOUT;
-                               else if (host_status & TIFM_MMCSD_DCRC)
-                                       cmd->data->error = MMC_ERR_BADCRC;
-                       }
-
-                       writel(TIFM_FIFO_INT_SETALL,
-                              sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
-                       writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
-
-                       if (host->req->stop) {
-                               if (host->cmd_flags & SCMD_ACTIVE) {
-                                       host->req->stop->error = cmd_error;
-                                       host->cmd_flags |= SCMD_READY;
-                               } else {
-                                       cmd->error = cmd_error;
-                                       host->cmd_flags |= SCMD_ACTIVE;
-                                       tifm_sd_exec(host, host->req->stop);
-                                       goto done;
-                               }
-                       } else
-                               cmd->error = cmd_error;
-               } else {
-                       if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {
-                               if (!(host->cmd_flags & CMD_READY)) {
-                                       host->cmd_flags |= CMD_READY;
-                                       tifm_sd_fetch_resp(cmd, sock);
-                               } else if (host->cmd_flags & SCMD_ACTIVE) {
-                                       host->cmd_flags |= SCMD_READY;
-                                       tifm_sd_fetch_resp(host->req->stop,
-                                                          sock);
-                               }
-                       }
-                       if (host_status & TIFM_MMCSD_BRS)
-                               host->cmd_flags |= BRS_READY;
-               }
-
-               if (host->no_dma && cmd->data) {
-                       if (host_status & TIFM_MMCSD_AE)
-                               writel(host_status & TIFM_MMCSD_AE,
-                                      sock->addr + SOCK_MMCSD_STATUS);
-
-                       if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF
-                                          | TIFM_MMCSD_BRS)) {
-                               local_irq_save(flags);
-                               tifm_sd_transfer_data(host);
-                               local_irq_restore(flags);
-                               host_status &= ~TIFM_MMCSD_AE;
-                       }
-               }
-
-               if (host_status & TIFM_MMCSD_EOFB)
-                       host->cmd_flags &= ~CARD_BUSY;
-               else if (host_status & TIFM_MMCSD_CB)
-                       host->cmd_flags |= CARD_BUSY;
-
-               tifm_sd_check_status(host);
-       }
-done:
-       writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
-       spin_unlock(&sock->lock);
-}
-
-static void tifm_sd_set_data_timeout(struct tifm_sd *host,
-                                    struct mmc_data *data)
-{
-       struct tifm_dev *sock = host->dev;
-       unsigned int data_timeout = data->timeout_clks;
-
-       if (fixed_timeout)
-               return;
-
-       data_timeout += data->timeout_ns /
-                       ((1000000000UL / host->clk_freq) * host->clk_div);
-
-       if (data_timeout < 0xffff) {
-               writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
-               writel((~TIFM_MMCSD_DPE)
-                      & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
-                      sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
-       } else {
-               data_timeout = (data_timeout >> 10) + 1;
-               if (data_timeout > 0xffff)
-                       data_timeout = 0;       /* set to unlimited */
-               writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
-               writel(TIFM_MMCSD_DPE
-                      | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
-                      sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
-       }
-}
-
-static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-       struct tifm_sd *host = mmc_priv(mmc);
-       struct tifm_dev *sock = host->dev;
-       unsigned long flags;
-       struct mmc_data *r_data = mrq->cmd->data;
-
-       spin_lock_irqsave(&sock->lock, flags);
-       if (host->eject) {
-               spin_unlock_irqrestore(&sock->lock, flags);
-               goto err_out;
-       }
-
-       if (host->req) {
-               printk(KERN_ERR "%s : unfinished request detected\n",
-                      sock->dev.bus_id);
-               spin_unlock_irqrestore(&sock->lock, flags);
-               goto err_out;
-       }
-
-       host->cmd_flags = 0;
-       host->block_pos = 0;
-       host->sg_pos = 0;
-
-       if (r_data) {
-               tifm_sd_set_data_timeout(host, r_data);
-
-               if ((r_data->flags & MMC_DATA_WRITE) && !mrq->stop)
-                        writel(TIFM_MMCSD_EOFB
-                               | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
-                               sock->addr + SOCK_MMCSD_INT_ENABLE);
-
-               if (host->no_dma) {
-                       writel(TIFM_MMCSD_BUFINT
-                              | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
-                              sock->addr + SOCK_MMCSD_INT_ENABLE);
-                       writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
-                              | (TIFM_MMCSD_FIFO_SIZE - 1),
-                              sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-
-                       host->sg_len = r_data->sg_len;
-               } else {
-                       sg_init_one(&host->bounce_buf, host->bounce_buf_data,
-                                   r_data->blksz);
-
-                       if(1 != tifm_map_sg(sock, &host->bounce_buf, 1,
-                                           r_data->flags & MMC_DATA_WRITE
-                                           ? PCI_DMA_TODEVICE
-                                           : PCI_DMA_FROMDEVICE)) {
-                               printk(KERN_ERR "%s : scatterlist map failed\n",
-                                      sock->dev.bus_id);
-                               spin_unlock_irqrestore(&sock->lock, flags);
-                               goto err_out;
-                       }
-                       host->sg_len = tifm_map_sg(sock, r_data->sg,
-                                                  r_data->sg_len,
-                                                  r_data->flags
-                                                  & MMC_DATA_WRITE
-                                                  ? PCI_DMA_TODEVICE
-                                                  : PCI_DMA_FROMDEVICE);
-                       if (host->sg_len < 1) {
-                               printk(KERN_ERR "%s : scatterlist map failed\n",
-                                      sock->dev.bus_id);
-                               tifm_unmap_sg(sock, &host->bounce_buf, 1,
-                                             r_data->flags & MMC_DATA_WRITE
-                                             ? PCI_DMA_TODEVICE
-                                             : PCI_DMA_FROMDEVICE);
-                               spin_unlock_irqrestore(&sock->lock, flags);
-                               goto err_out;
-                       }
-
-                       writel(TIFM_FIFO_INT_SETALL,
-                              sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
-                       writel(ilog2(r_data->blksz) - 2,
-                              sock->addr + SOCK_FIFO_PAGE_SIZE);
-                       writel(TIFM_FIFO_ENABLE,
-                              sock->addr + SOCK_FIFO_CONTROL);
-                       writel(TIFM_FIFO_INTMASK,
-                              sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
-
-                       if (r_data->flags & MMC_DATA_WRITE)
-                               writel(TIFM_MMCSD_TXDE,
-                                      sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-                       else
-                               writel(TIFM_MMCSD_RXDE,
-                                      sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-
-                       tifm_sd_set_dma_data(host, r_data);
-               }
-
-               writel(r_data->blocks - 1,
-                      sock->addr + SOCK_MMCSD_NUM_BLOCKS);
-               writel(r_data->blksz - 1,
-                      sock->addr + SOCK_MMCSD_BLOCK_LEN);
-       }
-
-       host->req = mrq;
-       mod_timer(&host->timer, jiffies + host->timeout_jiffies);
-       writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
-              sock->addr + SOCK_CONTROL);
-       tifm_sd_exec(host, mrq->cmd);
-       spin_unlock_irqrestore(&sock->lock, flags);
-       return;
-
-err_out:
-       mrq->cmd->error = MMC_ERR_TIMEOUT;
-       mmc_request_done(mmc, mrq);
-}
-
-static void tifm_sd_end_cmd(unsigned long data)
-{
-       struct tifm_sd *host = (struct tifm_sd*)data;
-       struct tifm_dev *sock = host->dev;
-       struct mmc_host *mmc = tifm_get_drvdata(sock);
-       struct mmc_request *mrq;
-       struct mmc_data *r_data = NULL;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sock->lock, flags);
-
-       del_timer(&host->timer);
-       mrq = host->req;
-       host->req = NULL;
-
-       if (!mrq) {
-               printk(KERN_ERR " %s : no request to complete?\n",
-                      sock->dev.bus_id);
-               spin_unlock_irqrestore(&sock->lock, flags);
-               return;
-       }
-
-       r_data = mrq->cmd->data;
-       if (r_data) {
-               if (host->no_dma) {
-                       writel((~TIFM_MMCSD_BUFINT)
-                              & readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
-                              sock->addr + SOCK_MMCSD_INT_ENABLE);
-               } else {
-                       tifm_unmap_sg(sock, &host->bounce_buf, 1,
-                                     (r_data->flags & MMC_DATA_WRITE)
-                                     ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-                       tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
-                                     (r_data->flags & MMC_DATA_WRITE)
-                                     ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-               }
-
-               r_data->bytes_xfered = r_data->blocks
-                       - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
-               r_data->bytes_xfered *= r_data->blksz;
-               r_data->bytes_xfered += r_data->blksz
-                       - readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
-       }
-
-       writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
-              sock->addr + SOCK_CONTROL);
-
-       spin_unlock_irqrestore(&sock->lock, flags);
-       mmc_request_done(mmc, mrq);
-}
-
-static void tifm_sd_abort(unsigned long data)
-{
-       struct tifm_sd *host = (struct tifm_sd*)data;
-
-       printk(KERN_ERR
-              "%s : card failed to respond for a long period of time "
-              "(%x, %x)\n",
-              host->dev->dev.bus_id, host->req->cmd->opcode, host->cmd_flags);
-
-       tifm_eject(host->dev);
-}
-
-static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-       struct tifm_sd *host = mmc_priv(mmc);
-       struct tifm_dev *sock = host->dev;
-       unsigned int clk_div1, clk_div2;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sock->lock, flags);
-
-       dev_dbg(&sock->dev, "ios: clock = %u, vdd = %x, bus_mode = %x, "
-               "chip_select = %x, power_mode = %x, bus_width = %x\n",
-               ios->clock, ios->vdd, ios->bus_mode, ios->chip_select,
-               ios->power_mode, ios->bus_width);
-
-       if (ios->bus_width == MMC_BUS_WIDTH_4) {
-               writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
-                      sock->addr + SOCK_MMCSD_CONFIG);
-       } else {
-               writel((~TIFM_MMCSD_4BBUS)
-                      & readl(sock->addr + SOCK_MMCSD_CONFIG),
-                      sock->addr + SOCK_MMCSD_CONFIG);
-       }
-
-       if (ios->clock) {
-               clk_div1 = 20000000 / ios->clock;
-               if (!clk_div1)
-                       clk_div1 = 1;
-
-               clk_div2 = 24000000 / ios->clock;
-               if (!clk_div2)
-                       clk_div2 = 1;
-
-               if ((20000000 / clk_div1) > ios->clock)
-                       clk_div1++;
-               if ((24000000 / clk_div2) > ios->clock)
-                       clk_div2++;
-               if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
-                       host->clk_freq = 20000000;
-                       host->clk_div = clk_div1;
-                       writel((~TIFM_CTRL_FAST_CLK)
-                              & readl(sock->addr + SOCK_CONTROL),
-                              sock->addr + SOCK_CONTROL);
-               } else {
-                       host->clk_freq = 24000000;
-                       host->clk_div = clk_div2;
-                       writel(TIFM_CTRL_FAST_CLK
-                              | readl(sock->addr + SOCK_CONTROL),
-                              sock->addr + SOCK_CONTROL);
-               }
-       } else {
-               host->clk_div = 0;
-       }
-       host->clk_div &= TIFM_MMCSD_CLKMASK;
-       writel(host->clk_div
-              | ((~TIFM_MMCSD_CLKMASK)
-                 & readl(sock->addr + SOCK_MMCSD_CONFIG)),
-              sock->addr + SOCK_MMCSD_CONFIG);
-
-       host->open_drain = (ios->bus_mode == MMC_BUSMODE_OPENDRAIN);
-
-       /* chip_select : maybe later */
-       //vdd
-       //power is set before probe / after remove
-
-       spin_unlock_irqrestore(&sock->lock, flags);
-}
-
-static int tifm_sd_ro(struct mmc_host *mmc)
-{
-       int rc = 0;
-       struct tifm_sd *host = mmc_priv(mmc);
-       struct tifm_dev *sock = host->dev;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sock->lock, flags);
-       if (TIFM_MMCSD_CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE))
-               rc = 1;
-       spin_unlock_irqrestore(&sock->lock, flags);
-       return rc;
-}
-
-static const struct mmc_host_ops tifm_sd_ops = {
-       .request = tifm_sd_request,
-       .set_ios = tifm_sd_ios,
-       .get_ro  = tifm_sd_ro
-};
-
-static int tifm_sd_initialize_host(struct tifm_sd *host)
-{
-       int rc;
-       unsigned int host_status = 0;
-       struct tifm_dev *sock = host->dev;
-
-       writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
-       mmiowb();
-       host->clk_div = 61;
-       host->clk_freq = 20000000;
-       writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
-       writel(host->clk_div | TIFM_MMCSD_POWER,
-              sock->addr + SOCK_MMCSD_CONFIG);
-
-       /* wait up to 0.51 sec for reset */
-       for (rc = 32; rc <= 256; rc <<= 1) {
-               if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
-                       rc = 0;
-                       break;
-               }
-               msleep(rc);
-       }
-
-       if (rc) {
-               printk(KERN_ERR "%s : controller failed to reset\n",
-                      sock->dev.bus_id);
-               return -ENODEV;
-       }
-
-       writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
-       writel(host->clk_div | TIFM_MMCSD_POWER,
-              sock->addr + SOCK_MMCSD_CONFIG);
-       writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-
-       // command timeout fixed to 64 clocks for now
-       writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
-       writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
-
-       for (rc = 16; rc <= 64; rc <<= 1) {
-               host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
-               writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
-               if (!(host_status & TIFM_MMCSD_ERRMASK)
-                   && (host_status & TIFM_MMCSD_EOC)) {
-                       rc = 0;
-                       break;
-               }
-               msleep(rc);
-       }
-
-       if (rc) {
-               printk(KERN_ERR
-                      "%s : card not ready - probe failed on initialization\n",
-                      sock->dev.bus_id);
-               return -ENODEV;
-       }
-
-       writel(TIFM_MMCSD_CERR | TIFM_MMCSD_BRS | TIFM_MMCSD_EOC
-              | TIFM_MMCSD_ERRMASK,
-              sock->addr + SOCK_MMCSD_INT_ENABLE);
-       mmiowb();
-
-       return 0;
-}
-
-static int tifm_sd_probe(struct tifm_dev *sock)
-{
-       struct mmc_host *mmc;
-       struct tifm_sd *host;
-       int rc = -EIO;
-
-       if (!(TIFM_SOCK_STATE_OCCUPIED
-             & readl(sock->addr + SOCK_PRESENT_STATE))) {
-               printk(KERN_WARNING "%s : card gone, unexpectedly\n",
-                      sock->dev.bus_id);
-               return rc;
-       }
-
-       mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev);
-       if (!mmc)
-               return -ENOMEM;
-
-       host = mmc_priv(mmc);
-       host->no_dma = no_dma;
-       tifm_set_drvdata(sock, mmc);
-       host->dev = sock;
-       host->timeout_jiffies = msecs_to_jiffies(1000);
-
-       tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd,
-                    (unsigned long)host);
-       setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
-
-       mmc->ops = &tifm_sd_ops;
-       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
-       mmc->f_min = 20000000 / 60;
-       mmc->f_max = 24000000;
-
-       mmc->max_blk_count = 2048;
-       mmc->max_hw_segs = mmc->max_blk_count;
-       mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE);
-       mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;
-       mmc->max_req_size = mmc->max_seg_size;
-       mmc->max_phys_segs = mmc->max_hw_segs;
-
-       sock->card_event = tifm_sd_card_event;
-       sock->data_event = tifm_sd_data_event;
-       rc = tifm_sd_initialize_host(host);
-
-       if (!rc)
-               rc = mmc_add_host(mmc);
-       if (!rc)
-               return 0;
-
-       mmc_free_host(mmc);
-       return rc;
-}
-
-static void tifm_sd_remove(struct tifm_dev *sock)
-{
-       struct mmc_host *mmc = tifm_get_drvdata(sock);
-       struct tifm_sd *host = mmc_priv(mmc);
-       unsigned long flags;
-
-       spin_lock_irqsave(&sock->lock, flags);
-       host->eject = 1;
-       writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
-       mmiowb();
-       spin_unlock_irqrestore(&sock->lock, flags);
-
-       tasklet_kill(&host->finish_tasklet);
-
-       spin_lock_irqsave(&sock->lock, flags);
-       if (host->req) {
-               writel(TIFM_FIFO_INT_SETALL,
-                      sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
-               writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
-               host->req->cmd->error = MMC_ERR_TIMEOUT;
-               if (host->req->stop)
-                       host->req->stop->error = MMC_ERR_TIMEOUT;
-               tasklet_schedule(&host->finish_tasklet);
-       }
-       spin_unlock_irqrestore(&sock->lock, flags);
-       mmc_remove_host(mmc);
-       dev_dbg(&sock->dev, "after remove\n");
-
-       /* The meaning of the bit majority in this constant is unknown. */
-       writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
-              sock->addr + SOCK_CONTROL);
-
-       mmc_free_host(mmc);
-}
-
-#ifdef CONFIG_PM
-
-static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
-{
-       struct mmc_host *mmc = tifm_get_drvdata(sock);
-       int rc;
-
-       rc = mmc_suspend_host(mmc, state);
-       /* The meaning of the bit majority in this constant is unknown. */
-       writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
-              sock->addr + SOCK_CONTROL);
-       return rc;
-}
-
-static int tifm_sd_resume(struct tifm_dev *sock)
-{
-       struct mmc_host *mmc = tifm_get_drvdata(sock);
-       struct tifm_sd *host = mmc_priv(mmc);
-       int rc;
-
-       rc = tifm_sd_initialize_host(host);
-       dev_dbg(&sock->dev, "resume initialize %d\n", rc);
-
-       if (rc)
-               host->eject = 1;
-       else
-               rc = mmc_resume_host(mmc);
-
-       return rc;
-}
-
-#else
-
-#define tifm_sd_suspend NULL
-#define tifm_sd_resume NULL
-
-#endif /* CONFIG_PM */
-
-static struct tifm_device_id tifm_sd_id_tbl[] = {
-       { TIFM_TYPE_SD }, { }
-};
-
-static struct tifm_driver tifm_sd_driver = {
-       .driver = {
-               .name  = DRIVER_NAME,
-               .owner = THIS_MODULE
-       },
-       .id_table = tifm_sd_id_tbl,
-       .probe    = tifm_sd_probe,
-       .remove   = tifm_sd_remove,
-       .suspend  = tifm_sd_suspend,
-       .resume   = tifm_sd_resume
-};
-
-static int __init tifm_sd_init(void)
-{
-       return tifm_register_driver(&tifm_sd_driver);
-}
-
-static void __exit tifm_sd_exit(void)
-{
-       tifm_unregister_driver(&tifm_sd_driver);
-}
-
-MODULE_AUTHOR("Alex Dubov");
-MODULE_DESCRIPTION("TI FlashMedia SD driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl);
-MODULE_VERSION(DRIVER_VERSION);
-
-module_init(tifm_sd_init);
-module_exit(tifm_sd_exit);
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
deleted file mode 100644 (file)
index 9f7518b..0000000
+++ /dev/null
@@ -1,2062 +0,0 @@
-/*
- *  linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
- *
- *  Copyright (C) 2004-2007 Pierre Ossman, 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 as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- *
- * Warning!
- *
- * Changes to the FIFO system should be done with extreme care since
- * the hardware is full of bugs related to the FIFO. Known issues are:
- *
- * - FIFO size field in FSR is always zero.
- *
- * - FIFO interrupts tend not to work as they should. Interrupts are
- *   triggered only for full/empty events, not for threshold values.
- *
- * - On APIC systems the FIFO empty interrupt is sometimes lost.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/pnp.h>
-#include <linux/highmem.h>
-#include <linux/mmc/host.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/scatterlist.h>
-
-#include "wbsd.h"
-
-#define DRIVER_NAME "wbsd"
-
-#define DBG(x...) \
-       pr_debug(DRIVER_NAME ": " x)
-#define DBGF(f, x...) \
-       pr_debug(DRIVER_NAME " [%s()]: " f, __func__ , ##x)
-
-/*
- * Device resources
- */
-
-#ifdef CONFIG_PNP
-
-static const struct pnp_device_id pnp_dev_table[] = {
-       { "WEC0517", 0 },
-       { "WEC0518", 0 },
-       { "", 0 },
-};
-
-MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
-
-#endif /* CONFIG_PNP */
-
-static const int config_ports[] = { 0x2E, 0x4E };
-static const int unlock_codes[] = { 0x83, 0x87 };
-
-static const int valid_ids[] = {
-       0x7112,
-       };
-
-#ifdef CONFIG_PNP
-static unsigned int nopnp = 0;
-#else
-static const unsigned int nopnp = 1;
-#endif
-static unsigned int io = 0x248;
-static unsigned int irq = 6;
-static int dma = 2;
-
-/*
- * Basic functions
- */
-
-static inline void wbsd_unlock_config(struct wbsd_host *host)
-{
-       BUG_ON(host->config == 0);
-
-       outb(host->unlock_code, host->config);
-       outb(host->unlock_code, host->config);
-}
-
-static inline void wbsd_lock_config(struct wbsd_host *host)
-{
-       BUG_ON(host->config == 0);
-
-       outb(LOCK_CODE, host->config);
-}
-
-static inline void wbsd_write_config(struct wbsd_host *host, u8 reg, u8 value)
-{
-       BUG_ON(host->config == 0);
-
-       outb(reg, host->config);
-       outb(value, host->config + 1);
-}
-
-static inline u8 wbsd_read_config(struct wbsd_host *host, u8 reg)
-{
-       BUG_ON(host->config == 0);
-
-       outb(reg, host->config);
-       return inb(host->config + 1);
-}
-
-static inline void wbsd_write_index(struct wbsd_host *host, u8 index, u8 value)
-{
-       outb(index, host->base + WBSD_IDXR);
-       outb(value, host->base + WBSD_DATAR);
-}
-
-static inline u8 wbsd_read_index(struct wbsd_host *host, u8 index)
-{
-       outb(index, host->base + WBSD_IDXR);
-       return inb(host->base + WBSD_DATAR);
-}
-
-/*
- * Common routines
- */
-
-static void wbsd_init_device(struct wbsd_host *host)
-{
-       u8 setup, ier;
-
-       /*
-        * Reset chip (SD/MMC part) and fifo.
-        */
-       setup = wbsd_read_index(host, WBSD_IDX_SETUP);
-       setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET;
-       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-
-       /*
-        * Set DAT3 to input
-        */
-       setup &= ~WBSD_DAT3_H;
-       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-       host->flags &= ~WBSD_FIGNORE_DETECT;
-
-       /*
-        * Read back default clock.
-        */
-       host->clk = wbsd_read_index(host, WBSD_IDX_CLK);
-
-       /*
-        * Power down port.
-        */
-       outb(WBSD_POWER_N, host->base + WBSD_CSR);
-
-       /*
-        * Set maximum timeout.
-        */
-       wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F);
-
-       /*
-        * Test for card presence
-        */
-       if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)
-               host->flags |= WBSD_FCARD_PRESENT;
-       else
-               host->flags &= ~WBSD_FCARD_PRESENT;
-
-       /*
-        * Enable interesting interrupts.
-        */
-       ier = 0;
-       ier |= WBSD_EINT_CARD;
-       ier |= WBSD_EINT_FIFO_THRE;
-       ier |= WBSD_EINT_CRC;
-       ier |= WBSD_EINT_TIMEOUT;
-       ier |= WBSD_EINT_TC;
-
-       outb(ier, host->base + WBSD_EIR);
-
-       /*
-        * Clear interrupts.
-        */
-       inb(host->base + WBSD_ISR);
-}
-
-static void wbsd_reset(struct wbsd_host *host)
-{
-       u8 setup;
-
-       printk(KERN_ERR "%s: Resetting chip\n", mmc_hostname(host->mmc));
-
-       /*
-        * Soft reset of chip (SD/MMC part).
-        */
-       setup = wbsd_read_index(host, WBSD_IDX_SETUP);
-       setup |= WBSD_SOFT_RESET;
-       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-}
-
-static void wbsd_request_end(struct wbsd_host *host, struct mmc_request *mrq)
-{
-       unsigned long dmaflags;
-
-       DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode);
-
-       if (host->dma >= 0) {
-               /*
-                * Release ISA DMA controller.
-                */
-               dmaflags = claim_dma_lock();
-               disable_dma(host->dma);
-               clear_dma_ff(host->dma);
-               release_dma_lock(dmaflags);
-
-               /*
-                * Disable DMA on host.
-                */
-               wbsd_write_index(host, WBSD_IDX_DMA, 0);
-       }
-
-       host->mrq = NULL;
-
-       /*
-        * MMC layer might call back into the driver so first unlock.
-        */
-       spin_unlock(&host->lock);
-       mmc_request_done(host->mmc, mrq);
-       spin_lock(&host->lock);
-}
-
-/*
- * Scatter/gather functions
- */
-
-static inline void wbsd_init_sg(struct wbsd_host *host, struct mmc_data *data)
-{
-       /*
-        * Get info. about SG list from data structure.
-        */
-       host->cur_sg = data->sg;
-       host->num_sg = data->sg_len;
-
-       host->offset = 0;
-       host->remain = host->cur_sg->length;
-}
-
-static inline int wbsd_next_sg(struct wbsd_host *host)
-{
-       /*
-        * Skip to next SG entry.
-        */
-       host->cur_sg++;
-       host->num_sg--;
-
-       /*
-        * Any entries left?
-        */
-       if (host->num_sg > 0) {
-               host->offset = 0;
-               host->remain = host->cur_sg->length;
-       }
-
-       return host->num_sg;
-}
-
-static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
-{
-       return page_address(host->cur_sg->page) + host->cur_sg->offset;
-}
-
-static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
-{
-       unsigned int len, i;
-       struct scatterlist *sg;
-       char *dmabuf = host->dma_buffer;
-       char *sgbuf;
-
-       sg = data->sg;
-       len = data->sg_len;
-
-       for (i = 0; i < len; i++) {
-               sgbuf = page_address(sg[i].page) + sg[i].offset;
-               memcpy(dmabuf, sgbuf, sg[i].length);
-               dmabuf += sg[i].length;
-       }
-}
-
-static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
-{
-       unsigned int len, i;
-       struct scatterlist *sg;
-       char *dmabuf = host->dma_buffer;
-       char *sgbuf;
-
-       sg = data->sg;
-       len = data->sg_len;
-
-       for (i = 0; i < len; i++) {
-               sgbuf = page_address(sg[i].page) + sg[i].offset;
-               memcpy(sgbuf, dmabuf, sg[i].length);
-               dmabuf += sg[i].length;
-       }
-}
-
-/*
- * Command handling
- */
-
-static inline void wbsd_get_short_reply(struct wbsd_host *host,
-                                       struct mmc_command *cmd)
-{
-       /*
-        * Correct response type?
-        */
-       if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) {
-               cmd->error = MMC_ERR_INVALID;
-               return;
-       }
-
-       cmd->resp[0]  = wbsd_read_index(host, WBSD_IDX_RESP12) << 24;
-       cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP13) << 16;
-       cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP14) << 8;
-       cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP15) << 0;
-       cmd->resp[1]  = wbsd_read_index(host, WBSD_IDX_RESP16) << 24;
-}
-
-static inline void wbsd_get_long_reply(struct wbsd_host *host,
-       struct mmc_command *cmd)
-{
-       int i;
-
-       /*
-        * Correct response type?
-        */
-       if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) {
-               cmd->error = MMC_ERR_INVALID;
-               return;
-       }
-
-       for (i = 0; i < 4; i++) {
-               cmd->resp[i] =
-                       wbsd_read_index(host, WBSD_IDX_RESP1 + i * 4) << 24;
-               cmd->resp[i] |=
-                       wbsd_read_index(host, WBSD_IDX_RESP2 + i * 4) << 16;
-               cmd->resp[i] |=
-                       wbsd_read_index(host, WBSD_IDX_RESP3 + i * 4) << 8;
-               cmd->resp[i] |=
-                       wbsd_read_index(host, WBSD_IDX_RESP4 + i * 4) << 0;
-       }
-}
-
-static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
-{
-       int i;
-       u8 status, isr;
-
-       DBGF("Sending cmd (%x)\n", cmd->opcode);
-
-       /*
-        * Clear accumulated ISR. The interrupt routine
-        * will fill this one with events that occur during
-        * transfer.
-        */
-       host->isr = 0;
-
-       /*
-        * Send the command (CRC calculated by host).
-        */
-       outb(cmd->opcode, host->base + WBSD_CMDR);
-       for (i = 3; i >= 0; i--)
-               outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR);
-
-       cmd->error = MMC_ERR_NONE;
-
-       /*
-        * Wait for the request to complete.
-        */
-       do {
-               status = wbsd_read_index(host, WBSD_IDX_STATUS);
-       } while (status & WBSD_CARDTRAFFIC);
-
-       /*
-        * Do we expect a reply?
-        */
-       if (cmd->flags & MMC_RSP_PRESENT) {
-               /*
-                * Read back status.
-                */
-               isr = host->isr;
-
-               /* Card removed? */
-               if (isr & WBSD_INT_CARD)
-                       cmd->error = MMC_ERR_TIMEOUT;
-               /* Timeout? */
-               else if (isr & WBSD_INT_TIMEOUT)
-                       cmd->error = MMC_ERR_TIMEOUT;
-               /* CRC? */
-               else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC))
-                       cmd->error = MMC_ERR_BADCRC;
-               /* All ok */
-               else {
-                       if (cmd->flags & MMC_RSP_136)
-                               wbsd_get_long_reply(host, cmd);
-                       else
-                               wbsd_get_short_reply(host, cmd);
-               }
-       }
-
-       DBGF("Sent cmd (%x), res %d\n", cmd->opcode, cmd->error);
-}
-
-/*
- * Data functions
- */
-
-static void wbsd_empty_fifo(struct wbsd_host *host)
-{
-       struct mmc_data *data = host->mrq->cmd->data;
-       char *buffer;
-       int i, fsr, fifo;
-
-       /*
-        * Handle excessive data.
-        */
-       if (host->num_sg == 0)
-               return;
-
-       buffer = wbsd_sg_to_buffer(host) + host->offset;
-
-       /*
-        * Drain the fifo. This has a tendency to loop longer
-        * than the FIFO length (usually one block).
-        */
-       while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY)) {
-               /*
-                * The size field in the FSR is broken so we have to
-                * do some guessing.
-                */
-               if (fsr & WBSD_FIFO_FULL)
-                       fifo = 16;
-               else if (fsr & WBSD_FIFO_FUTHRE)
-                       fifo = 8;
-               else
-                       fifo = 1;
-
-               for (i = 0; i < fifo; i++) {
-                       *buffer = inb(host->base + WBSD_DFR);
-                       buffer++;
-                       host->offset++;
-                       host->remain--;
-
-                       data->bytes_xfered++;
-
-                       /*
-                        * End of scatter list entry?
-                        */
-                       if (host->remain == 0) {
-                               /*
-                                * Get next entry. Check if last.
-                                */
-                               if (!wbsd_next_sg(host))
-                                       return;
-
-                               buffer = wbsd_sg_to_buffer(host);
-                       }
-               }
-       }
-
-       /*
-        * This is a very dirty hack to solve a
-        * hardware problem. The chip doesn't trigger
-        * FIFO threshold interrupts properly.
-        */
-       if ((data->blocks * data->blksz - data->bytes_xfered) < 16)
-               tasklet_schedule(&host->fifo_tasklet);
-}
-
-static void wbsd_fill_fifo(struct wbsd_host *host)
-{
-       struct mmc_data *data = host->mrq->cmd->data;
-       char *buffer;
-       int i, fsr, fifo;
-
-       /*
-        * Check that we aren't being called after the
-        * entire buffer has been transfered.
-        */
-       if (host->num_sg == 0)
-               return;
-
-       buffer = wbsd_sg_to_buffer(host) + host->offset;
-
-       /*
-        * Fill the fifo. This has a tendency to loop longer
-        * than the FIFO length (usually one block).
-        */
-       while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL)) {
-               /*
-                * The size field in the FSR is broken so we have to
-                * do some guessing.
-                */
-               if (fsr & WBSD_FIFO_EMPTY)
-                       fifo = 0;
-               else if (fsr & WBSD_FIFO_EMTHRE)
-                       fifo = 8;
-               else
-                       fifo = 15;
-
-               for (i = 16; i > fifo; i--) {
-                       outb(*buffer, host->base + WBSD_DFR);
-                       buffer++;
-                       host->offset++;
-                       host->remain--;
-
-                       data->bytes_xfered++;
-
-                       /*
-                        * End of scatter list entry?
-                        */
-                       if (host->remain == 0) {
-                               /*
-                                * Get next entry. Check if last.
-                                */
-                               if (!wbsd_next_sg(host))
-                                       return;
-
-                               buffer = wbsd_sg_to_buffer(host);
-                       }
-               }
-       }
-
-       /*
-        * The controller stops sending interrupts for
-        * 'FIFO empty' under certain conditions. So we
-        * need to be a bit more pro-active.
-        */
-       tasklet_schedule(&host->fifo_tasklet);
-}
-
-static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
-{
-       u16 blksize;
-       u8 setup;
-       unsigned long dmaflags;
-       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.
-        */
-       size = data->blocks * data->blksz;
-
-       /*
-        * Check timeout values for overflow.
-        * (Yes, some cards cause this value to overflow).
-        */
-       if (data->timeout_ns > 127000000)
-               wbsd_write_index(host, WBSD_IDX_TAAC, 127);
-       else {
-               wbsd_write_index(host, WBSD_IDX_TAAC,
-                       data->timeout_ns / 1000000);
-       }
-
-       if (data->timeout_clks > 255)
-               wbsd_write_index(host, WBSD_IDX_NSAC, 255);
-       else
-               wbsd_write_index(host, WBSD_IDX_NSAC, data->timeout_clks);
-
-       /*
-        * Inform the chip of how large blocks will be
-        * sent. It needs this to determine when to
-        * calculate CRC.
-        *
-        * Space for CRC must be included in the size.
-        * Two bytes are needed for each data line.
-        */
-       if (host->bus_width == MMC_BUS_WIDTH_1) {
-               blksize = data->blksz + 2;
-
-               wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
-               wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
-       } else if (host->bus_width == MMC_BUS_WIDTH_4) {
-               blksize = data->blksz + 2 * 4;
-
-               wbsd_write_index(host, WBSD_IDX_PBSMSB,
-                       ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH);
-               wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
-       } else {
-               data->error = MMC_ERR_INVALID;
-               return;
-       }
-
-       /*
-        * Clear the FIFO. This is needed even for DMA
-        * transfers since the chip still uses the FIFO
-        * internally.
-        */
-       setup = wbsd_read_index(host, WBSD_IDX_SETUP);
-       setup |= WBSD_FIFO_RESET;
-       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-
-       /*
-        * DMA transfer?
-        */
-       if (host->dma >= 0) {
-               /*
-                * The buffer for DMA is only 64 kB.
-                */
-               BUG_ON(size > 0x10000);
-               if (size > 0x10000) {
-                       data->error = MMC_ERR_INVALID;
-                       return;
-               }
-
-               /*
-                * Transfer data from the SG list to
-                * the DMA buffer.
-                */
-               if (data->flags & MMC_DATA_WRITE)
-                       wbsd_sg_to_dma(host, data);
-
-               /*
-                * Initialise the ISA DMA controller.
-                */
-               dmaflags = claim_dma_lock();
-               disable_dma(host->dma);
-               clear_dma_ff(host->dma);
-               if (data->flags & MMC_DATA_READ)
-                       set_dma_mode(host->dma, DMA_MODE_READ & ~0x40);
-               else
-                       set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40);
-               set_dma_addr(host->dma, host->dma_addr);
-               set_dma_count(host->dma, size);
-
-               enable_dma(host->dma);
-               release_dma_lock(dmaflags);
-
-               /*
-                * Enable DMA on the host.
-                */
-               wbsd_write_index(host, WBSD_IDX_DMA, WBSD_DMA_ENABLE);
-       } else {
-               /*
-                * This flag is used to keep printk
-                * output to a minimum.
-                */
-               host->firsterr = 1;
-
-               /*
-                * Initialise the SG list.
-                */
-               wbsd_init_sg(host, data);
-
-               /*
-                * Turn off DMA.
-                */
-               wbsd_write_index(host, WBSD_IDX_DMA, 0);
-
-               /*
-                * Set up FIFO threshold levels (and fill
-                * buffer if doing a write).
-                */
-               if (data->flags & MMC_DATA_READ) {
-                       wbsd_write_index(host, WBSD_IDX_FIFOEN,
-                               WBSD_FIFOEN_FULL | 8);
-               } else {
-                       wbsd_write_index(host, WBSD_IDX_FIFOEN,
-                               WBSD_FIFOEN_EMPTY | 8);
-                       wbsd_fill_fifo(host);
-               }
-       }
-
-       data->error = MMC_ERR_NONE;
-}
-
-static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
-{
-       unsigned long dmaflags;
-       int count;
-       u8 status;
-
-       WARN_ON(host->mrq == NULL);
-
-       /*
-        * Send a stop command if needed.
-        */
-       if (data->stop)
-               wbsd_send_command(host, data->stop);
-
-       /*
-        * Wait for the controller to leave data
-        * transfer state.
-        */
-       do {
-               status = wbsd_read_index(host, WBSD_IDX_STATUS);
-       } while (status & (WBSD_BLOCK_READ | WBSD_BLOCK_WRITE));
-
-       /*
-        * DMA transfer?
-        */
-       if (host->dma >= 0) {
-               /*
-                * Disable DMA on the host.
-                */
-               wbsd_write_index(host, WBSD_IDX_DMA, 0);
-
-               /*
-                * Turn of ISA DMA controller.
-                */
-               dmaflags = claim_dma_lock();
-               disable_dma(host->dma);
-               clear_dma_ff(host->dma);
-               count = get_dma_residue(host->dma);
-               release_dma_lock(dmaflags);
-
-               data->bytes_xfered = host->mrq->data->blocks *
-                       host->mrq->data->blksz - count;
-               data->bytes_xfered -= data->bytes_xfered % data->blksz;
-
-               /*
-                * Any leftover data?
-                */
-               if (count) {
-                       printk(KERN_ERR "%s: Incomplete DMA transfer. "
-                               "%d bytes left.\n",
-                               mmc_hostname(host->mmc), count);
-
-                       if (data->error == MMC_ERR_NONE)
-                               data->error = MMC_ERR_FAILED;
-               } else {
-                       /*
-                        * Transfer data from DMA buffer to
-                        * SG list.
-                        */
-                       if (data->flags & MMC_DATA_READ)
-                               wbsd_dma_to_sg(host, data);
-               }
-
-               if (data->error != MMC_ERR_NONE) {
-                       if (data->bytes_xfered)
-                               data->bytes_xfered -= data->blksz;
-               }
-       }
-
-       DBGF("Ending data transfer (%d bytes)\n", data->bytes_xfered);
-
-       wbsd_request_end(host, host->mrq);
-}
-
-/*****************************************************************************\
- *                                                                           *
- * MMC layer callbacks                                                       *
- *                                                                           *
-\*****************************************************************************/
-
-static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-       struct wbsd_host *host = mmc_priv(mmc);
-       struct mmc_command *cmd;
-
-       /*
-        * Disable tasklets to avoid a deadlock.
-        */
-       spin_lock_bh(&host->lock);
-
-       BUG_ON(host->mrq != NULL);
-
-       cmd = mrq->cmd;
-
-       host->mrq = mrq;
-
-       /*
-        * If there is no card in the slot then
-        * timeout immediatly.
-        */
-       if (!(host->flags & WBSD_FCARD_PRESENT)) {
-               cmd->error = MMC_ERR_TIMEOUT;
-               goto done;
-       }
-
-       /*
-        * Does the request include data?
-        */
-       if (cmd->data) {
-               wbsd_prepare_data(host, cmd->data);
-
-               if (cmd->data->error != MMC_ERR_NONE)
-                       goto done;
-       }
-
-       wbsd_send_command(host, cmd);
-
-       /*
-        * If this is a data transfer the request
-        * will be finished after the data has
-        * transfered.
-        */
-       if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
-               /*
-                * The hardware is so delightfully stupid that it has a list
-                * of "data" commands. If a command isn't on this list, it'll
-                * just go back to the idle state and won't send any data
-                * interrupts.
-                */
-               switch (cmd->opcode) {
-               case 11:
-               case 17:
-               case 18:
-               case 20:
-               case 24:
-               case 25:
-               case 26:
-               case 27:
-               case 30:
-               case 42:
-               case 56:
-                       break;
-
-               /* ACMDs. We don't keep track of state, so we just treat them
-                * like any other command. */
-               case 51:
-                       break;
-
-               default:
-#ifdef CONFIG_MMC_DEBUG
-                       printk(KERN_WARNING "%s: Data command %d is not "
-                               "supported by this controller.\n",
-                               mmc_hostname(host->mmc), cmd->opcode);
-#endif
-                       cmd->data->error = MMC_ERR_INVALID;
-
-                       if (cmd->data->stop)
-                               wbsd_send_command(host, cmd->data->stop);
-
-                       goto done;
-               };
-
-               /*
-                * Dirty fix for hardware bug.
-                */
-               if (host->dma == -1)
-                       tasklet_schedule(&host->fifo_tasklet);
-
-               spin_unlock_bh(&host->lock);
-
-               return;
-       }
-
-done:
-       wbsd_request_end(host, mrq);
-
-       spin_unlock_bh(&host->lock);
-}
-
-static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-       struct wbsd_host *host = mmc_priv(mmc);
-       u8 clk, setup, pwr;
-
-       spin_lock_bh(&host->lock);
-
-       /*
-        * Reset the chip on each power off.
-        * Should clear out any weird states.
-        */
-       if (ios->power_mode == MMC_POWER_OFF)
-               wbsd_init_device(host);
-
-       if (ios->clock >= 24000000)
-               clk = WBSD_CLK_24M;
-       else if (ios->clock >= 16000000)
-               clk = WBSD_CLK_16M;
-       else if (ios->clock >= 12000000)
-               clk = WBSD_CLK_12M;
-       else
-               clk = WBSD_CLK_375K;
-
-       /*
-        * Only write to the clock register when
-        * there is an actual change.
-        */
-       if (clk != host->clk) {
-               wbsd_write_index(host, WBSD_IDX_CLK, clk);
-               host->clk = clk;
-       }
-
-       /*
-        * Power up card.
-        */
-       if (ios->power_mode != MMC_POWER_OFF) {
-               pwr = inb(host->base + WBSD_CSR);
-               pwr &= ~WBSD_POWER_N;
-               outb(pwr, host->base + WBSD_CSR);
-       }
-
-       /*
-        * MMC cards need to have pin 1 high during init.
-        * It wreaks havoc with the card detection though so
-        * that needs to be disabled.
-        */
-       setup = wbsd_read_index(host, WBSD_IDX_SETUP);
-       if (ios->chip_select == MMC_CS_HIGH) {
-               BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1);
-               setup |= WBSD_DAT3_H;
-               host->flags |= WBSD_FIGNORE_DETECT;
-       } else {
-               if (setup & WBSD_DAT3_H) {
-                       setup &= ~WBSD_DAT3_H;
-
-                       /*
-                        * We cannot resume card detection immediatly
-                        * because of capacitance and delays in the chip.
-                        */
-                       mod_timer(&host->ignore_timer, jiffies + HZ / 100);
-               }
-       }
-       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-
-       /*
-        * Store bus width for later. Will be used when
-        * setting up the data transfer.
-        */
-       host->bus_width = ios->bus_width;
-
-       spin_unlock_bh(&host->lock);
-}
-
-static int wbsd_get_ro(struct mmc_host *mmc)
-{
-       struct wbsd_host *host = mmc_priv(mmc);
-       u8 csr;
-
-       spin_lock_bh(&host->lock);
-
-       csr = inb(host->base + WBSD_CSR);
-       csr |= WBSD_MSLED;
-       outb(csr, host->base + WBSD_CSR);
-
-       mdelay(1);
-
-       csr = inb(host->base + WBSD_CSR);
-       csr &= ~WBSD_MSLED;
-       outb(csr, host->base + WBSD_CSR);
-
-       spin_unlock_bh(&host->lock);
-
-       return csr & WBSD_WRPT;
-}
-
-static const struct mmc_host_ops wbsd_ops = {
-       .request        = wbsd_request,
-       .set_ios        = wbsd_set_ios,
-       .get_ro         = wbsd_get_ro,
-};
-
-/*****************************************************************************\
- *                                                                           *
- * Interrupt handling                                                        *
- *                                                                           *
-\*****************************************************************************/
-
-/*
- * Helper function to reset detection ignore
- */
-
-static void wbsd_reset_ignore(unsigned long data)
-{
-       struct wbsd_host *host = (struct wbsd_host *)data;
-
-       BUG_ON(host == NULL);
-
-       DBG("Resetting card detection ignore\n");
-
-       spin_lock_bh(&host->lock);
-
-       host->flags &= ~WBSD_FIGNORE_DETECT;
-
-       /*
-        * Card status might have changed during the
-        * blackout.
-        */
-       tasklet_schedule(&host->card_tasklet);
-
-       spin_unlock_bh(&host->lock);
-}
-
-/*
- * Tasklets
- */
-
-static inline struct mmc_data *wbsd_get_data(struct wbsd_host *host)
-{
-       WARN_ON(!host->mrq);
-       if (!host->mrq)
-               return NULL;
-
-       WARN_ON(!host->mrq->cmd);
-       if (!host->mrq->cmd)
-               return NULL;
-
-       WARN_ON(!host->mrq->cmd->data);
-       if (!host->mrq->cmd->data)
-               return NULL;
-
-       return host->mrq->cmd->data;
-}
-
-static void wbsd_tasklet_card(unsigned long param)
-{
-       struct wbsd_host *host = (struct wbsd_host *)param;
-       u8 csr;
-       int delay = -1;
-
-       spin_lock(&host->lock);
-
-       if (host->flags & WBSD_FIGNORE_DETECT) {
-               spin_unlock(&host->lock);
-               return;
-       }
-
-       csr = inb(host->base + WBSD_CSR);
-       WARN_ON(csr == 0xff);
-
-       if (csr & WBSD_CARDPRESENT) {
-               if (!(host->flags & WBSD_FCARD_PRESENT)) {
-                       DBG("Card inserted\n");
-                       host->flags |= WBSD_FCARD_PRESENT;
-
-                       delay = 500;
-               }
-       } else if (host->flags & WBSD_FCARD_PRESENT) {
-               DBG("Card removed\n");
-               host->flags &= ~WBSD_FCARD_PRESENT;
-
-               if (host->mrq) {
-                       printk(KERN_ERR "%s: Card removed during transfer!\n",
-                               mmc_hostname(host->mmc));
-                       wbsd_reset(host);
-
-                       host->mrq->cmd->error = MMC_ERR_FAILED;
-                       tasklet_schedule(&host->finish_tasklet);
-               }
-
-               delay = 0;
-       }
-
-       /*
-        * Unlock first since we might get a call back.
-        */
-
-       spin_unlock(&host->lock);
-
-       if (delay != -1)
-               mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
-}
-
-static void wbsd_tasklet_fifo(unsigned long param)
-{
-       struct wbsd_host *host = (struct wbsd_host *)param;
-       struct mmc_data *data;
-
-       spin_lock(&host->lock);
-
-       if (!host->mrq)
-               goto end;
-
-       data = wbsd_get_data(host);
-       if (!data)
-               goto end;
-
-       if (data->flags & MMC_DATA_WRITE)
-               wbsd_fill_fifo(host);
-       else
-               wbsd_empty_fifo(host);
-
-       /*
-        * Done?
-        */
-       if (host->num_sg == 0) {
-               wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
-               tasklet_schedule(&host->finish_tasklet);
-       }
-
-end:
-       spin_unlock(&host->lock);
-}
-
-static void wbsd_tasklet_crc(unsigned long param)
-{
-       struct wbsd_host *host = (struct wbsd_host *)param;
-       struct mmc_data *data;
-
-       spin_lock(&host->lock);
-
-       if (!host->mrq)
-               goto end;
-
-       data = wbsd_get_data(host);
-       if (!data)
-               goto end;
-
-       DBGF("CRC error\n");
-
-       data->error = MMC_ERR_BADCRC;
-
-       tasklet_schedule(&host->finish_tasklet);
-
-end:
-       spin_unlock(&host->lock);
-}
-
-static void wbsd_tasklet_timeout(unsigned long param)
-{
-       struct wbsd_host *host = (struct wbsd_host *)param;
-       struct mmc_data *data;
-
-       spin_lock(&host->lock);
-
-       if (!host->mrq)
-               goto end;
-
-       data = wbsd_get_data(host);
-       if (!data)
-               goto end;
-
-       DBGF("Timeout\n");
-
-       data->error = MMC_ERR_TIMEOUT;
-
-       tasklet_schedule(&host->finish_tasklet);
-
-end:
-       spin_unlock(&host->lock);
-}
-
-static void wbsd_tasklet_finish(unsigned long param)
-{
-       struct wbsd_host *host = (struct wbsd_host *)param;
-       struct mmc_data *data;
-
-       spin_lock(&host->lock);
-
-       WARN_ON(!host->mrq);
-       if (!host->mrq)
-               goto end;
-
-       data = wbsd_get_data(host);
-       if (!data)
-               goto end;
-
-       wbsd_finish_data(host, data);
-
-end:
-       spin_unlock(&host->lock);
-}
-
-/*
- * Interrupt handling
- */
-
-static irqreturn_t wbsd_irq(int irq, void *dev_id)
-{
-       struct wbsd_host *host = dev_id;
-       int isr;
-
-       isr = inb(host->base + WBSD_ISR);
-
-       /*
-        * Was it actually our hardware that caused the interrupt?
-        */
-       if (isr == 0xff || isr == 0x00)
-               return IRQ_NONE;
-
-       host->isr |= isr;
-
-       /*
-        * Schedule tasklets as needed.
-        */
-       if (isr & WBSD_INT_CARD)
-               tasklet_schedule(&host->card_tasklet);
-       if (isr & WBSD_INT_FIFO_THRE)
-               tasklet_schedule(&host->fifo_tasklet);
-       if (isr & WBSD_INT_CRC)
-               tasklet_hi_schedule(&host->crc_tasklet);
-       if (isr & WBSD_INT_TIMEOUT)
-               tasklet_hi_schedule(&host->timeout_tasklet);
-       if (isr & WBSD_INT_TC)
-               tasklet_schedule(&host->finish_tasklet);
-
-       return IRQ_HANDLED;
-}
-
-/*****************************************************************************\
- *                                                                           *
- * Device initialisation and shutdown                                        *
- *                                                                           *
-\*****************************************************************************/
-
-/*
- * Allocate/free MMC structure.
- */
-
-static int __devinit wbsd_alloc_mmc(struct device *dev)
-{
-       struct mmc_host *mmc;
-       struct wbsd_host *host;
-
-       /*
-        * Allocate MMC structure.
-        */
-       mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
-       if (!mmc)
-               return -ENOMEM;
-
-       host = mmc_priv(mmc);
-       host->mmc = mmc;
-
-       host->dma = -1;
-
-       /*
-        * Set host parameters.
-        */
-       mmc->ops = &wbsd_ops;
-       mmc->f_min = 375000;
-       mmc->f_max = 24000000;
-       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
-
-       spin_lock_init(&host->lock);
-
-       /*
-        * Set up timers
-        */
-       init_timer(&host->ignore_timer);
-       host->ignore_timer.data = (unsigned long)host;
-       host->ignore_timer.function = wbsd_reset_ignore;
-
-       /*
-        * Maximum number of segments. Worst case is one sector per segment
-        * so this will be 64kB/512.
-        */
-       mmc->max_hw_segs = 128;
-       mmc->max_phys_segs = 128;
-
-       /*
-        * Maximum request size. Also limited by 64KiB buffer.
-        */
-       mmc->max_req_size = 65536;
-
-       /*
-        * Maximum segment size. Could be one segment with the maximum number
-        * of bytes.
-        */
-       mmc->max_seg_size = mmc->max_req_size;
-
-       /*
-        * Maximum block size. We have 12 bits (= 4095) but have to subtract
-        * space for CRC. So the maximum is 4095 - 4*2 = 4087.
-        */
-       mmc->max_blk_size = 4087;
-
-       /*
-        * Maximum block count. There is no real limit so the maximum
-        * request size will be the only restriction.
-        */
-       mmc->max_blk_count = mmc->max_req_size;
-
-       dev_set_drvdata(dev, mmc);
-
-       return 0;
-}
-
-static void __devexit wbsd_free_mmc(struct device *dev)
-{
-       struct mmc_host *mmc;
-       struct wbsd_host *host;
-
-       mmc = dev_get_drvdata(dev);
-       if (!mmc)
-               return;
-
-       host = mmc_priv(mmc);
-       BUG_ON(host == NULL);
-
-       del_timer_sync(&host->ignore_timer);
-
-       mmc_free_host(mmc);
-
-       dev_set_drvdata(dev, NULL);
-}
-
-/*
- * Scan for known chip id:s
- */
-
-static int __devinit wbsd_scan(struct wbsd_host *host)
-{
-       int i, j, k;
-       int id;
-
-       /*
-        * Iterate through all ports, all codes to
-        * find hardware that is in our known list.
-        */
-       for (i = 0; i < ARRAY_SIZE(config_ports); i++) {
-               if (!request_region(config_ports[i], 2, DRIVER_NAME))
-                       continue;
-
-               for (j = 0; j < ARRAY_SIZE(unlock_codes); j++) {
-                       id = 0xFFFF;
-
-                       host->config = config_ports[i];
-                       host->unlock_code = unlock_codes[j];
-
-                       wbsd_unlock_config(host);
-
-                       outb(WBSD_CONF_ID_HI, config_ports[i]);
-                       id = inb(config_ports[i] + 1) << 8;
-
-                       outb(WBSD_CONF_ID_LO, config_ports[i]);
-                       id |= inb(config_ports[i] + 1);
-
-                       wbsd_lock_config(host);
-
-                       for (k = 0; k < ARRAY_SIZE(valid_ids); k++) {
-                               if (id == valid_ids[k]) {
-                                       host->chip_id = id;
-
-                                       return 0;
-                               }
-                       }
-
-                       if (id != 0xFFFF) {
-                               DBG("Unknown hardware (id %x) found at %x\n",
-                                       id, config_ports[i]);
-                       }
-               }
-
-               release_region(config_ports[i], 2);
-       }
-
-       host->config = 0;
-       host->unlock_code = 0;
-
-       return -ENODEV;
-}
-
-/*
- * Allocate/free io port ranges
- */
-
-static int __devinit wbsd_request_region(struct wbsd_host *host, int base)
-{
-       if (base & 0x7)
-               return -EINVAL;
-
-       if (!request_region(base, 8, DRIVER_NAME))
-               return -EIO;
-
-       host->base = base;
-
-       return 0;
-}
-
-static void __devexit wbsd_release_regions(struct wbsd_host *host)
-{
-       if (host->base)
-               release_region(host->base, 8);
-
-       host->base = 0;
-
-       if (host->config)
-               release_region(host->config, 2);
-
-       host->config = 0;
-}
-
-/*
- * Allocate/free DMA port and buffer
- */
-
-static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma)
-{
-       if (dma < 0)
-               return;
-
-       if (request_dma(dma, DRIVER_NAME))
-               goto err;
-
-       /*
-        * We need to allocate a special buffer in
-        * order for ISA to be able to DMA to it.
-        */
-       host->dma_buffer = kmalloc(WBSD_DMA_SIZE,
-               GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN);
-       if (!host->dma_buffer)
-               goto free;
-
-       /*
-        * Translate the address to a physical address.
-        */
-       host->dma_addr = dma_map_single(mmc_dev(host->mmc), host->dma_buffer,
-               WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
-
-       /*
-        * ISA DMA must be aligned on a 64k basis.
-        */
-       if ((host->dma_addr & 0xffff) != 0)
-               goto kfree;
-       /*
-        * ISA cannot access memory above 16 MB.
-        */
-       else if (host->dma_addr >= 0x1000000)
-               goto kfree;
-
-       host->dma = dma;
-
-       return;
-
-kfree:
-       /*
-        * If we've gotten here then there is some kind of alignment bug
-        */
-       BUG_ON(1);
-
-       dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
-               WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
-       host->dma_addr = (dma_addr_t)NULL;
-
-       kfree(host->dma_buffer);
-       host->dma_buffer = NULL;
-
-free:
-       free_dma(dma);
-
-err:
-       printk(KERN_WARNING DRIVER_NAME ": Unable to allocate DMA %d. "
-               "Falling back on FIFO.\n", dma);
-}
-
-static void __devexit wbsd_release_dma(struct wbsd_host *host)
-{
-       if (host->dma_addr) {
-               dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
-                       WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
-       }
-       kfree(host->dma_buffer);
-       if (host->dma >= 0)
-               free_dma(host->dma);
-
-       host->dma = -1;
-       host->dma_buffer = NULL;
-       host->dma_addr = (dma_addr_t)NULL;
-}
-
-/*
- * Allocate/free IRQ.
- */
-
-static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
-{
-       int ret;
-
-       /*
-        * Allocate interrupt.
-        */
-
-       ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
-       if (ret)
-               return ret;
-
-       host->irq = irq;
-
-       /*
-        * Set up tasklets.
-        */
-       tasklet_init(&host->card_tasklet, wbsd_tasklet_card,
-                       (unsigned long)host);
-       tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo,
-                       (unsigned long)host);
-       tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc,
-                       (unsigned long)host);
-       tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout,
-                       (unsigned long)host);
-       tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,
-                       (unsigned long)host);
-
-       return 0;
-}
-
-static void __devexit wbsd_release_irq(struct wbsd_host *host)
-{
-       if (!host->irq)
-               return;
-
-       free_irq(host->irq, host);
-
-       host->irq = 0;
-
-       tasklet_kill(&host->card_tasklet);
-       tasklet_kill(&host->fifo_tasklet);
-       tasklet_kill(&host->crc_tasklet);
-       tasklet_kill(&host->timeout_tasklet);
-       tasklet_kill(&host->finish_tasklet);
-}
-
-/*
- * Allocate all resources for the host.
- */
-
-static int __devinit wbsd_request_resources(struct wbsd_host *host,
-       int base, int irq, int dma)
-{
-       int ret;
-
-       /*
-        * Allocate I/O ports.
-        */
-       ret = wbsd_request_region(host, base);
-       if (ret)
-               return ret;
-
-       /*
-        * Allocate interrupt.
-        */
-       ret = wbsd_request_irq(host, irq);
-       if (ret)
-               return ret;
-
-       /*
-        * Allocate DMA.
-        */
-       wbsd_request_dma(host, dma);
-
-       return 0;
-}
-
-/*
- * Release all resources for the host.
- */
-
-static void __devexit wbsd_release_resources(struct wbsd_host *host)
-{
-       wbsd_release_dma(host);
-       wbsd_release_irq(host);
-       wbsd_release_regions(host);
-}
-
-/*
- * Configure the resources the chip should use.
- */
-
-static void wbsd_chip_config(struct wbsd_host *host)
-{
-       wbsd_unlock_config(host);
-
-       /*
-        * Reset the chip.
-        */
-       wbsd_write_config(host, WBSD_CONF_SWRST, 1);
-       wbsd_write_config(host, WBSD_CONF_SWRST, 0);
-
-       /*
-        * Select SD/MMC function.
-        */
-       wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
-
-       /*
-        * Set up card detection.
-        */
-       wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11);
-
-       /*
-        * Configure chip
-        */
-       wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8);
-       wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff);
-
-       wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
-
-       if (host->dma >= 0)
-               wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
-
-       /*
-        * Enable and power up chip.
-        */
-       wbsd_write_config(host, WBSD_CONF_ENABLE, 1);
-       wbsd_write_config(host, WBSD_CONF_POWER, 0x20);
-
-       wbsd_lock_config(host);
-}
-
-/*
- * Check that configured resources are correct.
- */
-
-static int wbsd_chip_validate(struct wbsd_host *host)
-{
-       int base, irq, dma;
-
-       wbsd_unlock_config(host);
-
-       /*
-        * Select SD/MMC function.
-        */
-       wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
-
-       /*
-        * Read configuration.
-        */
-       base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8;
-       base |= wbsd_read_config(host, WBSD_CONF_PORT_LO);
-
-       irq = wbsd_read_config(host, WBSD_CONF_IRQ);
-
-       dma = wbsd_read_config(host, WBSD_CONF_DRQ);
-
-       wbsd_lock_config(host);
-
-       /*
-        * Validate against given configuration.
-        */
-       if (base != host->base)
-               return 0;
-       if (irq != host->irq)
-               return 0;
-       if ((dma != host->dma) && (host->dma != -1))
-               return 0;
-
-       return 1;
-}
-
-/*
- * Powers down the SD function
- */
-
-static void wbsd_chip_poweroff(struct wbsd_host *host)
-{
-       wbsd_unlock_config(host);
-
-       wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
-       wbsd_write_config(host, WBSD_CONF_ENABLE, 0);
-
-       wbsd_lock_config(host);
-}
-
-/*****************************************************************************\
- *                                                                           *
- * Devices setup and shutdown                                                *
- *                                                                           *
-\*****************************************************************************/
-
-static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma,
-       int pnp)
-{
-       struct wbsd_host *host = NULL;
-       struct mmc_host *mmc = NULL;
-       int ret;
-
-       ret = wbsd_alloc_mmc(dev);
-       if (ret)
-               return ret;
-
-       mmc = dev_get_drvdata(dev);
-       host = mmc_priv(mmc);
-
-       /*
-        * Scan for hardware.
-        */
-       ret = wbsd_scan(host);
-       if (ret) {
-               if (pnp && (ret == -ENODEV)) {
-                       printk(KERN_WARNING DRIVER_NAME
-                               ": Unable to confirm device presence. You may "
-                               "experience lock-ups.\n");
-               } else {
-                       wbsd_free_mmc(dev);
-                       return ret;
-               }
-       }
-
-       /*
-        * Request resources.
-        */
-       ret = wbsd_request_resources(host, base, irq, dma);
-       if (ret) {
-               wbsd_release_resources(host);
-               wbsd_free_mmc(dev);
-               return ret;
-       }
-
-       /*
-        * See if chip needs to be configured.
-        */
-       if (pnp) {
-               if ((host->config != 0) && !wbsd_chip_validate(host)) {
-                       printk(KERN_WARNING DRIVER_NAME
-                               ": PnP active but chip not configured! "
-                               "You probably have a buggy BIOS. "
-                               "Configuring chip manually.\n");
-                       wbsd_chip_config(host);
-               }
-       } else
-               wbsd_chip_config(host);
-
-       /*
-        * Power Management stuff. No idea how this works.
-        * Not tested.
-        */
-#ifdef CONFIG_PM
-       if (host->config) {
-               wbsd_unlock_config(host);
-               wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
-               wbsd_lock_config(host);
-       }
-#endif
-       /*
-        * Allow device to initialise itself properly.
-        */
-       mdelay(5);
-
-       /*
-        * Reset the chip into a known state.
-        */
-       wbsd_init_device(host);
-
-       mmc_add_host(mmc);
-
-       printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc));
-       if (host->chip_id != 0)
-               printk(" id %x", (int)host->chip_id);
-       printk(" at 0x%x irq %d", (int)host->base, (int)host->irq);
-       if (host->dma >= 0)
-               printk(" dma %d", (int)host->dma);
-       else
-               printk(" FIFO");
-       if (pnp)
-               printk(" PnP");
-       printk("\n");
-
-       return 0;
-}
-
-static void __devexit wbsd_shutdown(struct device *dev, int pnp)
-{
-       struct mmc_host *mmc = dev_get_drvdata(dev);
-       struct wbsd_host *host;
-
-       if (!mmc)
-               return;
-
-       host = mmc_priv(mmc);
-
-       mmc_remove_host(mmc);
-
-       /*
-        * Power down the SD/MMC function.
-        */
-       if (!pnp)
-               wbsd_chip_poweroff(host);
-
-       wbsd_release_resources(host);
-
-       wbsd_free_mmc(dev);
-}
-
-/*
- * Non-PnP
- */
-
-static int __devinit wbsd_probe(struct platform_device *dev)
-{
-       /* Use the module parameters for resources */
-       return wbsd_init(&dev->dev, io, irq, dma, 0);
-}
-
-static int __devexit wbsd_remove(struct platform_device *dev)
-{
-       wbsd_shutdown(&dev->dev, 0);
-
-       return 0;
-}
-
-/*
- * PnP
- */
-
-#ifdef CONFIG_PNP
-
-static int __devinit
-wbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id)
-{
-       int io, irq, dma;
-
-       /*
-        * Get resources from PnP layer.
-        */
-       io = pnp_port_start(pnpdev, 0);
-       irq = pnp_irq(pnpdev, 0);
-       if (pnp_dma_valid(pnpdev, 0))
-               dma = pnp_dma(pnpdev, 0);
-       else
-               dma = -1;
-
-       DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma);
-
-       return wbsd_init(&pnpdev->dev, io, irq, dma, 1);
-}
-
-static void __devexit wbsd_pnp_remove(struct pnp_dev *dev)
-{
-       wbsd_shutdown(&dev->dev, 1);
-}
-
-#endif /* CONFIG_PNP */
-
-/*
- * Power management
- */
-
-#ifdef CONFIG_PM
-
-static int wbsd_suspend(struct wbsd_host *host, pm_message_t state)
-{
-       BUG_ON(host == NULL);
-
-       return mmc_suspend_host(host->mmc, state);
-}
-
-static int wbsd_resume(struct wbsd_host *host)
-{
-       BUG_ON(host == NULL);
-
-       wbsd_init_device(host);
-
-       return mmc_resume_host(host->mmc);
-}
-
-static int wbsd_platform_suspend(struct platform_device *dev,
-                                pm_message_t state)
-{
-       struct mmc_host *mmc = platform_get_drvdata(dev);
-       struct wbsd_host *host;
-       int ret;
-
-       if (mmc == NULL)
-               return 0;
-
-       DBGF("Suspending...\n");
-
-       host = mmc_priv(mmc);
-
-       ret = wbsd_suspend(host, state);
-       if (ret)
-               return ret;
-
-       wbsd_chip_poweroff(host);
-
-       return 0;
-}
-
-static int wbsd_platform_resume(struct platform_device *dev)
-{
-       struct mmc_host *mmc = platform_get_drvdata(dev);
-       struct wbsd_host *host;
-
-       if (mmc == NULL)
-               return 0;
-
-       DBGF("Resuming...\n");
-
-       host = mmc_priv(mmc);
-
-       wbsd_chip_config(host);
-
-       /*
-        * Allow device to initialise itself properly.
-        */
-       mdelay(5);
-
-       return wbsd_resume(host);
-}
-
-#ifdef CONFIG_PNP
-
-static int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
-{
-       struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
-       struct wbsd_host *host;
-
-       if (mmc == NULL)
-               return 0;
-
-       DBGF("Suspending...\n");
-
-       host = mmc_priv(mmc);
-
-       return wbsd_suspend(host, state);
-}
-
-static int wbsd_pnp_resume(struct pnp_dev *pnp_dev)
-{
-       struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
-       struct wbsd_host *host;
-
-       if (mmc == NULL)
-               return 0;
-
-       DBGF("Resuming...\n");
-
-       host = mmc_priv(mmc);
-
-       /*
-        * See if chip needs to be configured.
-        */
-       if (host->config != 0) {
-               if (!wbsd_chip_validate(host)) {
-                       printk(KERN_WARNING DRIVER_NAME
-                               ": PnP active but chip not configured! "
-                               "You probably have a buggy BIOS. "
-                               "Configuring chip manually.\n");
-                       wbsd_chip_config(host);
-               }
-       }
-
-       /*
-        * Allow device to initialise itself properly.
-        */
-       mdelay(5);
-
-       return wbsd_resume(host);
-}
-
-#endif /* CONFIG_PNP */
-
-#else /* CONFIG_PM */
-
-#define wbsd_platform_suspend NULL
-#define wbsd_platform_resume NULL
-
-#define wbsd_pnp_suspend NULL
-#define wbsd_pnp_resume NULL
-
-#endif /* CONFIG_PM */
-
-static struct platform_device *wbsd_device;
-
-static struct platform_driver wbsd_driver = {
-       .probe          = wbsd_probe,
-       .remove         = __devexit_p(wbsd_remove),
-
-       .suspend        = wbsd_platform_suspend,
-       .resume         = wbsd_platform_resume,
-       .driver         = {
-               .name   = DRIVER_NAME,
-       },
-};
-
-#ifdef CONFIG_PNP
-
-static struct pnp_driver wbsd_pnp_driver = {
-       .name           = DRIVER_NAME,
-       .id_table       = pnp_dev_table,
-       .probe          = wbsd_pnp_probe,
-       .remove         = __devexit_p(wbsd_pnp_remove),
-
-       .suspend        = wbsd_pnp_suspend,
-       .resume         = wbsd_pnp_resume,
-};
-
-#endif /* CONFIG_PNP */
-
-/*
- * Module loading/unloading
- */
-
-static int __init wbsd_drv_init(void)
-{
-       int result;
-
-       printk(KERN_INFO DRIVER_NAME
-               ": Winbond W83L51xD SD/MMC card interface driver\n");
-       printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
-
-#ifdef CONFIG_PNP
-
-       if (!nopnp) {
-               result = pnp_register_driver(&wbsd_pnp_driver);
-               if (result < 0)
-                       return result;
-       }
-#endif /* CONFIG_PNP */
-
-       if (nopnp) {
-               result = platform_driver_register(&wbsd_driver);
-               if (result < 0)
-                       return result;
-
-               wbsd_device = platform_device_alloc(DRIVER_NAME, -1);
-               if (!wbsd_device) {
-                       platform_driver_unregister(&wbsd_driver);
-                       return -ENOMEM;
-               }
-
-               result = platform_device_add(wbsd_device);
-               if (result) {
-                       platform_device_put(wbsd_device);
-                       platform_driver_unregister(&wbsd_driver);
-                       return result;
-               }
-       }
-
-       return 0;
-}
-
-static void __exit wbsd_drv_exit(void)
-{
-#ifdef CONFIG_PNP
-
-       if (!nopnp)
-               pnp_unregister_driver(&wbsd_pnp_driver);
-
-#endif /* CONFIG_PNP */
-
-       if (nopnp) {
-               platform_device_unregister(wbsd_device);
-
-               platform_driver_unregister(&wbsd_driver);
-       }
-
-       DBG("unloaded\n");
-}
-
-module_init(wbsd_drv_init);
-module_exit(wbsd_drv_exit);
-#ifdef CONFIG_PNP
-module_param(nopnp, uint, 0444);
-#endif
-module_param(io, uint, 0444);
-module_param(irq, uint, 0444);
-module_param(dma, int, 0444);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
-MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
-
-#ifdef CONFIG_PNP
-MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)");
-#endif
-MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)");
-MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)");
-MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)");
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
deleted file mode 100644 (file)
index 873bda1..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- *  linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver
- *
- *  Copyright (C) 2004-2007 Pierre Ossman, 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 as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#define LOCK_CODE              0xAA
-
-#define WBSD_CONF_SWRST                0x02
-#define WBSD_CONF_DEVICE       0x07
-#define WBSD_CONF_ID_HI                0x20
-#define WBSD_CONF_ID_LO                0x21
-#define WBSD_CONF_POWER                0x22
-#define WBSD_CONF_PME          0x23
-#define WBSD_CONF_PMES         0x24
-
-#define WBSD_CONF_ENABLE       0x30
-#define WBSD_CONF_PORT_HI      0x60
-#define WBSD_CONF_PORT_LO      0x61
-#define WBSD_CONF_IRQ          0x70
-#define WBSD_CONF_DRQ          0x74
-
-#define WBSD_CONF_PINS         0xF0
-
-#define DEVICE_SD              0x03
-
-#define WBSD_PINS_DAT3_HI      0x20
-#define WBSD_PINS_DAT3_OUT     0x10
-#define WBSD_PINS_GP11_HI      0x04
-#define WBSD_PINS_DETECT_GP11  0x02
-#define WBSD_PINS_DETECT_DAT3  0x01
-
-#define WBSD_CMDR              0x00
-#define WBSD_DFR               0x01
-#define WBSD_EIR               0x02
-#define WBSD_ISR               0x03
-#define WBSD_FSR               0x04
-#define WBSD_IDXR              0x05
-#define WBSD_DATAR             0x06
-#define WBSD_CSR               0x07
-
-#define WBSD_EINT_CARD         0x40
-#define WBSD_EINT_FIFO_THRE    0x20
-#define WBSD_EINT_CRC          0x10
-#define WBSD_EINT_TIMEOUT      0x08
-#define WBSD_EINT_PROGEND      0x04
-#define WBSD_EINT_BUSYEND      0x02
-#define WBSD_EINT_TC           0x01
-
-#define WBSD_INT_PENDING       0x80
-#define WBSD_INT_CARD          0x40
-#define WBSD_INT_FIFO_THRE     0x20
-#define WBSD_INT_CRC           0x10
-#define WBSD_INT_TIMEOUT       0x08
-#define WBSD_INT_PROGEND       0x04
-#define WBSD_INT_BUSYEND       0x02
-#define WBSD_INT_TC            0x01
-
-#define WBSD_FIFO_EMPTY                0x80
-#define WBSD_FIFO_FULL         0x40
-#define WBSD_FIFO_EMTHRE       0x20
-#define WBSD_FIFO_FUTHRE       0x10
-#define WBSD_FIFO_SZMASK       0x0F
-
-#define WBSD_MSLED             0x20
-#define WBSD_POWER_N           0x10
-#define WBSD_WRPT              0x04
-#define WBSD_CARDPRESENT       0x01
-
-#define WBSD_IDX_CLK           0x01
-#define WBSD_IDX_PBSMSB                0x02
-#define WBSD_IDX_TAAC          0x03
-#define WBSD_IDX_NSAC          0x04
-#define WBSD_IDX_PBSLSB                0x05
-#define WBSD_IDX_SETUP         0x06
-#define WBSD_IDX_DMA           0x07
-#define WBSD_IDX_FIFOEN                0x08
-#define WBSD_IDX_STATUS                0x10
-#define WBSD_IDX_RSPLEN                0x1E
-#define WBSD_IDX_RESP0         0x1F
-#define WBSD_IDX_RESP1         0x20
-#define WBSD_IDX_RESP2         0x21
-#define WBSD_IDX_RESP3         0x22
-#define WBSD_IDX_RESP4         0x23
-#define WBSD_IDX_RESP5         0x24
-#define WBSD_IDX_RESP6         0x25
-#define WBSD_IDX_RESP7         0x26
-#define WBSD_IDX_RESP8         0x27
-#define WBSD_IDX_RESP9         0x28
-#define WBSD_IDX_RESP10                0x29
-#define WBSD_IDX_RESP11                0x2A
-#define WBSD_IDX_RESP12                0x2B
-#define WBSD_IDX_RESP13                0x2C
-#define WBSD_IDX_RESP14                0x2D
-#define WBSD_IDX_RESP15                0x2E
-#define WBSD_IDX_RESP16                0x2F
-#define WBSD_IDX_CRCSTATUS     0x30
-#define WBSD_IDX_ISR           0x3F
-
-#define WBSD_CLK_375K          0x00
-#define WBSD_CLK_12M           0x01
-#define WBSD_CLK_16M           0x02
-#define WBSD_CLK_24M           0x03
-
-#define WBSD_DATA_WIDTH                0x01
-
-#define WBSD_DAT3_H            0x08
-#define WBSD_FIFO_RESET                0x04
-#define WBSD_SOFT_RESET                0x02
-#define WBSD_INC_INDEX         0x01
-
-#define WBSD_DMA_SINGLE                0x02
-#define WBSD_DMA_ENABLE                0x01
-
-#define WBSD_FIFOEN_EMPTY      0x20
-#define WBSD_FIFOEN_FULL       0x10
-#define WBSD_FIFO_THREMASK     0x0F
-
-#define WBSD_BLOCK_READ                0x80
-#define WBSD_BLOCK_WRITE       0x40
-#define WBSD_BUSY              0x20
-#define WBSD_CARDTRAFFIC       0x04
-#define WBSD_SENDCMD           0x02
-#define WBSD_RECVRES           0x01
-
-#define WBSD_RSP_SHORT         0x00
-#define WBSD_RSP_LONG          0x01
-
-#define WBSD_CRC_MASK          0x1F
-#define WBSD_CRC_OK            0x05 /* S010E (00101) */
-#define WBSD_CRC_FAIL          0x0B /* S101E (01011) */
-
-#define WBSD_DMA_SIZE          65536
-
-struct wbsd_host
-{
-       struct mmc_host*        mmc;            /* MMC structure */
-
-       spinlock_t              lock;           /* Mutex */
-
-       int                     flags;          /* Driver states */
-
-#define WBSD_FCARD_PRESENT     (1<<0)          /* Card is present */
-#define WBSD_FIGNORE_DETECT    (1<<1)          /* Ignore card detection */
-
-       struct mmc_request*     mrq;            /* Current request */
-
-       u8                      isr;            /* Accumulated ISR */
-
-       struct scatterlist*     cur_sg;         /* Current SG entry */
-       unsigned int            num_sg;         /* Number of entries left */
-
-       unsigned int            offset;         /* Offset into current entry */
-       unsigned int            remain;         /* Data left in curren entry */
-
-       char*                   dma_buffer;     /* ISA DMA buffer */
-       dma_addr_t              dma_addr;       /* Physical address for same */
-
-       int                     firsterr;       /* See fifo functions */
-
-       u8                      clk;            /* Current clock speed */
-       unsigned char           bus_width;      /* Current bus width */
-
-       int                     config;         /* Config port */
-       u8                      unlock_code;    /* Code to unlock config */
-
-       int                     chip_id;        /* ID of controller */
-
-       int                     base;           /* I/O port base */
-       int                     irq;            /* Interrupt */
-       int                     dma;            /* DMA channel */
-
-       struct tasklet_struct   card_tasklet;   /* Tasklet structures */
-       struct tasklet_struct   fifo_tasklet;
-       struct tasklet_struct   crc_tasklet;
-       struct tasklet_struct   timeout_tasklet;
-       struct tasklet_struct   finish_tasklet;
-
-       struct timer_list       ignore_timer;   /* Ignore detection timer */
-};