This is actually a forward port of the SD/MMC driver from the latest
LSP, melded into linux-2.6.23-git. I've tried to keep the style
updates that were merged recently. I fixed the exit code (in
davinci_mmcsd_exit) to release clocks, and some failure paths in
davinci_mmcsd_init.

This is probably not quite what David and Dirk were wanting, as it's
probably further from being merged upstream than previously.
However, it works for me (have tried reading/writing an SD card
successfully, reading at about ~6MB/s and writing at ~1MB/s). It
hasn't been put under particularly strenuous testing either, so
beware.

YMMV.
Bernard.

 davinci_mmc.c |  748 ++++++++++++++++++++++++++++++++++++++--------------------
 davinci_mmc.h |   23 +
 2 files changed, 520 insertions(+), 251 deletions(-)

diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 5d8e79f..3a635d0 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -24,13 +24,17 @@
  Modifications:
  ver. 1.0: Oct 2005, Purushotam Kumar   Initial version
  ver 1.1:  Nov  2005, Purushotam Kumar  Solved bugs
- ver 1.2:  Jan  2066, Purushotam Kumar   Added card remove insert support
+ ver 1.2:  Jan  2006, Purushotam Kumar   Added card remove insert support
  -
  *
-
  */
 
 #include <linux/module.h>
+#include <linux/version.h>
+/* DEBUG check shall be made before kernel.h or device.h is included */
+#ifdef CONFIG_MMC_DEBUG
+#define DEBUG
+#endif
 #include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
@@ -41,35 +45,25 @@ #include <linux/clk.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/mmc.h>
-
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/hardware.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <asm/arch/irqs.h>
 #include <asm/arch/hardware.h>
 
 #include "davinci_mmc.h"
 #include <asm/arch/edma.h>
 
-/* FIXME: old defines  from old mmc.h */
-/* #define MMC_RSP_NONE        (0 << 0) */
-/* #define MMC_RSP_SHORT       (1 << 0) */
-/* #define MMC_RSP_LONG        (2 << 0) */
-/* #define MMC_RSP_MASK        (3 << 0) */
-/* #define MMC_RSP_CRC (1 << 3)                /\* expect valid crc *\/ */
-/* #define MMC_RSP_BUSY        (1 << 4)                /\* card may send busy 
*\/ */
-#define MMC_RSP_SHORT  MMC_RSP_PRESENT
-#define MMC_RSP_LONG    MMC_RSP_136
-#define MMC_RSP_MASK    (MMC_RSP_PRESENT | MMC_RSP_136)
-
 extern void davinci_clean_channel(int ch_no);
 
 /* MMCSD Init clock in Hz in opendain mode */
-#define MMCSD_INIT_CLOCK               200000
-#define DRIVER_NAME                    "mmc0"
-#define MMCINT_INTERRUPT               IRQ_MMCINT
-#define MMCSD_REGS_BASE_ADDR           DAVINCI_MMC_SD_BASE
-#define TCINTEN                                (0x1<<20)
+#define MMCSD_INIT_CLOCK               200000
+#define DRIVER_NAME                    "mmc0"
+#define MMCINT_INTERRUPT               IRQ_MMCINT
+#define MMCSD_REGS_BASE_ADDR           DAVINCI_MMC_SD_BASE
+#define TCINTEN                        (0x1<<20)
 
 /* This macro could not be defined to 0 (ZERO) or -ve value.
  * This value is multiplied to "HZ"
@@ -83,6 +77,8 @@ mmcsd_config_def mmcsd_cfg = {
 /* read write thresholds (in bytes) can be any power of 2 from 2 to 64 */
        32,
 /* To use the DMA or not-- 1- Use DMA, 0-Interrupt mode */
+       1,
+/* flag Indicates 1bit/4bit mode */
        1
 };
 
@@ -107,54 +103,71 @@ static struct mmc_request *que_mmc_reque
 /* tells whether card is initizlzed or not */
 static unsigned int is_card_initialized = 0;
 static unsigned int new_card_state = 0;        /* tells current state of card 
*/
+static unsigned int is_card_removed = 0;
 
 static DEFINE_SPINLOCK(mmc_lock);
 
+#define RSP_TYPE(x)    ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
+#define MMCST1_BUSY    (1 << 0)
+
+static inline void wait_on_data(void)
+{
+       int cnt = 900000;
+       while (((mmcsd_regs->mmc_st1) & MMCST1_BUSY) && cnt) {
+               cnt--;
+               udelay(1);
+       }
+       if (!cnt) {
+               dev_warn(&mmc_dev, "ERROR: TOUT waiting for BUSY\n");
+       }
+}
+
 static void mmc_davinci_start_command(struct mmc_davinci_host *host,
                struct mmc_command *cmd)
 {
        u32 cmd_reg = 0;
        u32 resp_type = 0;
        u32 cmd_type = 0;
-       int byte_cnt = 0, i = 0;
        unsigned long flags;
 
+#ifdef CONFIG_MMC_DEBUG
        dev_dbg(&mmc_dev, "\nMMCSD : CMD%d, argument 0x%08x",
                cmd->opcode, cmd->arg);
-       if (cmd->flags & MMC_RSP_SHORT)
-               dev_dbg(&mmc_dev, ", 32-bit response");
-       if (cmd->flags & MMC_RSP_LONG)
-               dev_dbg(&mmc_dev, ", 128-bit response");
-       if (cmd->flags & MMC_RSP_CRC)
-               dev_dbg(&mmc_dev, ", CRC");
-       if (cmd->flags & MMC_RSP_BUSY)
-               dev_dbg(&mmc_dev, ", busy notification");
-       else
-               dev_dbg(&mmc_dev, ", No busy notification");
+       switch (RSP_TYPE(mmc_resp_type(cmd))) {
+       case RSP_TYPE(MMC_RSP_R1):
+               dev_dbg(&mmc_dev, ", R1/R1b response");
+               break;
+       case RSP_TYPE(MMC_RSP_R2):
+               dev_dbg(&mmc_dev, ", R2 response");
+               break;
+       case RSP_TYPE(MMC_RSP_R3):
+               dev_dbg(&mmc_dev, ", R3 response");
+               break;
+       default:
+               break;
+       }
        dev_dbg(&mmc_dev, "\n");
+#endif
        host->cmd = cmd;
 
        /* Protocol layer does not provide response type,
         * but our hardware needs to know exact type, not just size!
         */
-       switch (cmd->flags & MMC_RSP_MASK) {
+       switch (RSP_TYPE(mmc_resp_type(cmd))) {
        case MMC_RSP_NONE:
                /* resp 0 */
                break;
-       case MMC_RSP_SHORT:
-               /* resp 1, resp 1b */
-               /* OR resp 3!! (assume this if bus is set opendrain) */
-               if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) {
-                       resp_type = 3;
-                       if (cmd->opcode == 3)
-                               resp_type = 1;
-               } else
-                       resp_type = 1;
+       case RSP_TYPE(MMC_RSP_R1):
+               resp_type = 1;
                break;
-       case MMC_RSP_LONG:
-               /* resp 2 */
+       case RSP_TYPE(MMC_RSP_R2):
                resp_type = 2;
                break;
+       case RSP_TYPE(MMC_RSP_R3):
+               resp_type = 3;
+               break;
+       default:
+               break;
        }
 
        /* Protocol layer does not provide command type, but our hardware
@@ -171,11 +184,11 @@ static void mmc_davinci_start_command(st
         * rest are ac, except if opendrain
         */
 
-       if (host->data_dir)
+       if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
                cmd_type = DAVINCI_MMC_CMDTYPE_ADTC;
-       else if (resp_type == 0 && cmd->opcode != 15)
+       else if (mmc_cmd_type(cmd) == MMC_CMD_BC)
                cmd_type = DAVINCI_MMC_CMDTYPE_BC;
-       else if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
+       else if (mmc_cmd_type(cmd) == MMC_CMD_BCR)
                cmd_type = DAVINCI_MMC_CMDTYPE_BCR;
        else
                cmd_type = DAVINCI_MMC_CMDTYPE_AC;
@@ -198,10 +211,9 @@ static void mmc_davinci_start_command(st
                cmd_reg = cmd_reg | (1 << 14);
 
        /* Set for generating DMA Xfer event */
-       if ((host->use_dma == 1) && (host->data != NULL)
-                       && ((cmd->opcode == 18) || (cmd->opcode == 25)
-                               || (cmd->opcode == 24)
-                               || (cmd->opcode == 17)))
+       if ((host->do_dma == 1) && (host->data != NULL)
+           && ((cmd->opcode == 18) || (cmd->opcode == 25)
+               || (cmd->opcode == 24) || (cmd->opcode == 17)))
                cmd_reg = cmd_reg | (1 << 16);
 
        /* Setting whether command involves data transfer or not */
@@ -227,7 +239,7 @@ static void mmc_davinci_start_command(st
 
        /* Enable interrupt */
        if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
-               if (host->use_dma != 1)
+               if (host->do_dma != 1)
                        mmcsd_regs->mmc_im = MMCSD_EVENT_EOFCMD
                                        | MMCSD_EVENT_WRITE
                                        | MMCSD_EVENT_ERROR_CMDCRC
@@ -243,7 +255,7 @@ static void mmc_davinci_start_command(st
                                        | MMCSD_EVENT_ERROR_DATATIMEOUT
                                        | MMCSD_EVENT_BLOCK_XFERRED;
        } else if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
-               if (host->use_dma != 1)
+               if (host->do_dma != 1)
                        mmcsd_regs->mmc_im = MMCSD_EVENT_EOFCMD
                                        | MMCSD_EVENT_READ
                                        | MMCSD_EVENT_ERROR_CMDCRC
@@ -271,25 +283,22 @@ static void mmc_davinci_start_command(st
         */
        if ((host->data_dir == DAVINCI_MMC_DATADIR_WRITE)
                        && (cmd_type == DAVINCI_MMC_CMDTYPE_ADTC)
-                       && (host->use_dma != 1)) {
-               byte_cnt = mmcsd_cfg.rw_threshold;
-               host->bytes_left -= mmcsd_cfg.rw_threshold;
-               for (i = 0; i < (byte_cnt / 4); i++) {
-                       mmcsd_regs->mmc_dxr = *host->buffer;
-                       host->buffer++;
-               }
-       }
+                       && (host->do_dma != 1))
+               /* Fill the FIFO for Tx */
+               davinci_fifo_data_trans(host);
 
        if (cmd->opcode == 7) {
                spin_lock_irqsave(&mmc_lock, flags);
+               is_card_removed = 0;
                new_card_state = 1;
                is_card_initialized = 1;
                host->old_card_state = new_card_state;
                is_init_progress = 0;
                spin_unlock_irqrestore(&mmc_lock, flags);
        }
-       if (cmd->opcode == 1) {
+       if (cmd->opcode == 1 || cmd->opcode == 41) {
                spin_lock_irqsave(&mmc_lock, flags);
+               is_card_initialized = 0;
                is_init_progress = 1;
                spin_unlock_irqrestore(&mmc_lock, flags);
        }
@@ -302,47 +311,178 @@ static void mmc_davinci_start_command(st
 
 static void mmc_davinci_dma_cb(int lch, u16 ch_status, void *data)
 {
-       int sync_dev = 0;
-       struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
+       if (DMA_COMPLETE != ch_status) {
+               struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
+               dev_warn(&mmc_dev, "[DMA FAILED]");
+               davinci_abort_dma(host);
+       }
+}
 
-       if (DMA_COMPLETE == ch_status) {
+static void davinci_fifo_data_trans(struct mmc_davinci_host *host)
+{
+       int n, i;
 
-               if (host->cmd == NULL && host->data == NULL) {
-                       if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
-                               sync_dev = DAVINCI_DMA_MMCTXEVT;
-                       } else {
-                               sync_dev = DAVINCI_DMA_MMCRXEVT;
-                       }
-                       dev_dbg(&mmc_dev,
-                               "Interrupt from DMA when no request has been 
made\n");
-                       davinci_stop_dma(sync_dev);
-                       return;
-               }
+       if (host->buffer_bytes_left == 0) {
+               host->sg_idx++;
+               BUG_ON(host->sg_idx == host->sg_len);
+               mmc_davinci_sg_to_buf(host);
+       }
 
-               if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
-                       sync_dev = DAVINCI_DMA_MMCTXEVT;        /* Write */
-               } else {
-                       sync_dev = DAVINCI_DMA_MMCRXEVT;        /* Read */
+       n = mmcsd_cfg.rw_threshold;
+       if (n > host->buffer_bytes_left)
+               n = host->buffer_bytes_left;
+       host->buffer_bytes_left -= n;
+       host->bytes_left -= n;
+
+       if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
+               for (i = 0; i < (n / 4); i++) {
+                       mmcsd_regs->mmc_dxr = *host->buffer;
+                       host->buffer++;
                }
-               davinci_stop_dma(sync_dev);
        } else {
-               /* Handing of Event missed interreupt from DMA */
-               dev_dbg(&mmc_dev,
-                       "Event miss interrupt has been generated by DMA\n");
-               if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
-                       sync_dev = DAVINCI_DMA_MMCTXEVT;        /* Write */
-               } else {
-                       sync_dev = DAVINCI_DMA_MMCRXEVT;        /* Read */
+               for (i = 0; i < (n / 4); i++) {
+                       *host->buffer = mmcsd_regs->mmc_drr;
+                       host->buffer++;
                }
-               davinci_clean_channel(sync_dev);
        }
 }
 
+static void davinci_reinit_chan(void)
+{
+       int sync_dev;
+
+       sync_dev = DAVINCI_DMA_MMCTXEVT;
+       davinci_stop_dma(sync_dev);
+       davinci_clean_channel(sync_dev);
+
+       sync_dev = DAVINCI_DMA_MMCRXEVT;
+       davinci_stop_dma(sync_dev);
+       davinci_clean_channel(sync_dev);
+}
+
+static void davinci_abort_dma(struct mmc_davinci_host *host)
+{
+       int sync_dev = 0;
+
+       if (host->data_dir == DAVINCI_MMC_DATADIR_READ)
+               sync_dev = DAVINCI_DMA_MMCTXEVT;
+       else
+               sync_dev = DAVINCI_DMA_MMCRXEVT;
+
+       davinci_stop_dma(sync_dev);
+       davinci_clean_channel(sync_dev);
+
+}
+
 static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host,
                struct mmc_request *req)
 {
-       const char *dev_name;
-       int sync_dev, r, edma_ch = 0, tcc = 0;
+       int use_dma = 1, i;
+       struct mmc_data *data = host->data;
+       int block_size = data->blksz;
+
+       host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
+                               ((data->flags & MMC_DATA_WRITE)
+                               ? DMA_TO_DEVICE
+                               : DMA_FROM_DEVICE));
+
+       /* Decide if we can use DMA */
+       for (i = 0; i < host->sg_len; i++) {
+               if ((data->sg[i].length % block_size) != 0) {
+                       use_dma = 0;
+                       break;
+               }
+       }
+
+       if (!use_dma) {
+               dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
+                                 (data->flags & MMC_DATA_WRITE)
+                               ? DMA_TO_DEVICE
+                               : DMA_FROM_DEVICE);
+               return -1;
+       }
+
+       host->do_dma = 1;
+
+       host->dma_state = 0;
+
+       mmc_davinci_send_dma_request(host, req);
+
+       return 0;
+
+}
+
+static int davinci_release_dma_channels(struct mmc_davinci_host *host)
+{
+       davinci_free_dma(DAVINCI_DMA_MMCTXEVT);
+       davinci_free_dma(DAVINCI_DMA_MMCRXEVT);
+
+       if (host->edma_ch_details.cnt_chanel) {
+               davinci_free_dma(host->edma_ch_details.chanel_num[0]);
+               host->edma_ch_details.cnt_chanel = 0;
+       }
+
+       return 0;
+}
+
+static int davinci_acquire_dma_channels(struct mmc_davinci_host *host)
+{
+       int edma_chan_num, tcc = 0, r, sync_dev;
+       enum dma_event_q queue_no = EVENTQ_0;
+
+       /* Acquire master DMA write channel */
+       if ((r = davinci_request_dma(DAVINCI_DMA_MMCTXEVT, "MMC_WRITE",
+                       mmc_davinci_dma_cb, host, &edma_chan_num, &tcc,
+                       queue_no)) != 0) {
+               dev_warn(&mmc_dev,
+                               "MMC: davinci_request_dma() failed with %d\n",
+                               r);
+               return r;
+       }
+
+       /* Acquire master DMA read channel */
+       if ((r = davinci_request_dma(DAVINCI_DMA_MMCRXEVT, "MMC_READ",
+                       mmc_davinci_dma_cb, host, &edma_chan_num, &tcc,
+                       queue_no)) != 0) {
+               dev_warn(&mmc_dev,
+                               "MMC: davinci_request_dma() failed with %d\n",
+                               r);
+               goto free_master_write;
+       }
+
+       host->edma_ch_details.cnt_chanel = 0;
+
+       /* currently data Writes are done using single block mode,
+        * so no DMA slave write channel is required for now */
+
+       /* Create a DMA slave read channel 
+        * (assuming max segments handled is 2) */
+       sync_dev = DAVINCI_DMA_MMCRXEVT;
+       if ((r = davinci_request_dma(DAVINCI_EDMA_PARAM_ANY, "LINK",
+                       NULL, NULL, &edma_chan_num, &sync_dev,
+                       queue_no)) != 0) {
+               dev_warn(&mmc_dev,
+                       "MMC: davinci_request_dma() failed with %d\n", r);
+               goto free_master_read;
+       }
+
+       host->edma_ch_details.cnt_chanel++;
+       host->edma_ch_details.chanel_num[0] = edma_chan_num;
+
+       return 0;
+
+free_master_read:
+       davinci_free_dma(DAVINCI_DMA_MMCRXEVT);
+free_master_write:
+       davinci_free_dma(DAVINCI_DMA_MMCTXEVT);
+
+       return r;
+}
+
+static int mmc_davinci_send_dma_request(struct mmc_davinci_host *host,
+                                       struct mmc_request *req)
+{
+       int sync_dev;
        unsigned char i, j;
        unsigned short acnt, bcnt, ccnt;
        unsigned int src_port, dst_port, temp_ccnt;
@@ -353,69 +493,50 @@ static int mmc_davinci_start_dma_transfe
        unsigned short bcntrld;
        enum sync_dimension sync_mode;
        edmacc_paramentry_regs temp;
-       enum dma_event_q queue_no = EVENTQ_0;
        int edma_chan_num;
-       unsigned int num_eight_words = (req->data->blocks * 512) / 32;
        static unsigned int option_read = 0;
        static unsigned int option_write = 0;
-       static unsigned char dma_read_req = 1;
-       static unsigned char dma_write_req = 1;
+       struct mmc_data *data = host->data;
+       struct scatterlist *sg = &data->sg[0];
+       unsigned int count;
+       int num_frames, frame;
 
 #define MAX_C_CNT              64000
 
-       if ((req->data->flags & MMC_DATA_WRITE)) {
-               sync_dev = DAVINCI_DMA_MMCTXEVT;        /* Write */
-               dev_name = "MMC_WRITE";
+       frame = data->blksz;
+       count = sg_dma_len(sg);
 
-               if (dma_write_req) {
-                       r = davinci_request_dma(sync_dev, dev_name,
-                                               mmc_davinci_dma_cb, host,
-                                               &edma_ch, &tcc, queue_no);
-                       if (r != 0) {
-                               dev_dbg(&mmc_dev,
-                                       "MMC: davinci_request_dma() failed with 
%d\n",
-r);
-                               return r;
-                       }
-                       dma_write_req = 0;
-               }
-       } else {
-               sync_dev = DAVINCI_DMA_MMCRXEVT;        /* Read */
-               dev_name = "MMC_READ";
-               if (dma_read_req) {
-                       r = davinci_request_dma(sync_dev, dev_name,
-                                               mmc_davinci_dma_cb, host,
-                                               &edma_ch, &tcc, queue_no);
-                       if (r != 0) {
-                               dev_dbg(&mmc_dev,
-                                       "MMC: davinci_request_dma() failed with 
%d\n",
-                                       r);
-                               return r;
-                       }
-                       dma_read_req = 0;
-               }
+       if ((data->blocks == 1) && (count > data->blksz)) {
+               count = frame;
        }
 
-       if ((req->data->flags & MMC_DATA_WRITE)) {
-               /* AB Sync Transfer */
-               /* Acnt =32, Bcnt= , Cnt=1 */
-
-               sync_dev = DAVINCI_DMA_MMCTXEVT;        /* Write */
+       if (count % 32 == 0) {
                acnt = 4;
                bcnt = 8;
-               if (num_eight_words > MAX_C_CNT) {
-                       temp_ccnt = MAX_C_CNT;
-                       ccnt = temp_ccnt;
-               } else {
-                       ccnt = num_eight_words;
-                       temp_ccnt = ccnt;
-               }
+               num_frames = count / 32;
+       } else {
+               acnt = count;
+               bcnt = 1;
+               num_frames = 1;
+       }
+
+       if (num_frames > MAX_C_CNT) {
+               temp_ccnt = MAX_C_CNT;
+               ccnt = temp_ccnt;
+       } else {
+               ccnt = num_frames;
+               temp_ccnt = ccnt;
+       }
+
+       if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
+               /*AB Sync Transfer */
+               sync_dev = DAVINCI_DMA_MMCTXEVT;
 
-               src_port = (unsigned int)virt_to_phys(req->data->mrq->buffer);
+               src_port = (unsigned int)sg_dma_address(sg);
                mode_src = INCR;
                fifo_width_src = W8BIT; /* It's not cared as modeDsr is INCR */
-               src_bidx = 4;
-               src_cidx = 32;
+               src_bidx = acnt;
+               src_cidx = acnt * bcnt;
                dst_port = MMCSD_REGS_BASE_ADDR + 0x2C;
                mode_dst = INCR;
                fifo_width_dst = W8BIT; /* It's not cared as modeDsr is INCR */
@@ -425,27 +546,18 @@ r);
                sync_mode = ABSYNC;
 
        } else {
-               sync_dev = DAVINCI_DMA_MMCRXEVT;        /* Read */
-               acnt = 4;
-               bcnt = 8;
-               if (num_eight_words > MAX_C_CNT) {
-                       temp_ccnt = MAX_C_CNT;
-                       ccnt = temp_ccnt;
-               } else {
-                       ccnt = num_eight_words;
-                       temp_ccnt = ccnt;
-               }
+               sync_dev = DAVINCI_DMA_MMCRXEVT;
 
                src_port = MMCSD_REGS_BASE_ADDR + 0x28;
                mode_src = INCR;
                fifo_width_src = W8BIT;
                src_bidx = 0;
                src_cidx = 0;
-               dst_port = (unsigned int)virt_to_phys(req->data->mrq->buffer);
+               dst_port = (unsigned int)sg_dma_address(sg);
                mode_dst = INCR;
                fifo_width_dst = W8BIT; /* It's not cared as modeDsr is INCR */
-               dst_bidx = 4;
-               dst_cidx = 32;
+               dst_bidx = acnt;
+               dst_cidx = acnt * bcnt;
                bcntrld = 8;
                sync_mode = ABSYNC;
        }
@@ -459,7 +571,6 @@ r);
        davinci_set_dma_transfer_params(sync_dev, acnt, bcnt, ccnt, bcntrld,
                                        sync_mode);
 
-       host->edma_ch_details.cnt_chanel = 0;
        davinci_get_dma_params(sync_dev, &temp);
        if (sync_dev == DAVINCI_DMA_MMCTXEVT) {
                if (option_write == 0) {
@@ -478,12 +589,15 @@ r);
                }
        }
 
-       if (num_eight_words > MAX_C_CNT) {      /* Linking will be performed */
+       if (host->sg_len > 1) {
                davinci_get_dma_params(sync_dev, &temp);
                temp.opt &= ~TCINTEN;
                davinci_set_dma_params(sync_dev, &temp);
 
-               for (i = 0; i < EDMA_MAX_LOGICAL_CHA_ALLOWED; i++) {
+               for (i = 0; i < host->sg_len - 1; i++) {
+
+                       sg = &data->sg[i + 1];
+
                        if (i != 0) {
                                j = i - 1;
                                davinci_get_dma_params(
@@ -495,30 +609,24 @@ r);
                                        &temp);
                        }
 
-                       host->edma_ch_details.cnt_chanel++;
-                       davinci_request_dma(DAVINCI_EDMA_PARAM_ANY, "LINK",
-                                       NULL, NULL, &edma_chan_num,
-                                       &sync_dev, queue_no);
-                       host->edma_ch_details.chanel_num[i] = edma_chan_num;
-                       ccnt = temp.ccnt & 0x0000FFFF;
-                       if (sync_dev == DAVINCI_DMA_MMCTXEVT) {
-                               temp.src = temp.src + (acnt * bcnt * ccnt);
-                       } else {
-                               temp.dst = temp.dst + (acnt * bcnt * ccnt);
-                       }
+                       edma_chan_num = host->edma_ch_details.chanel_num[0];
+
+                       frame = data->blksz;
+                       count = sg_dma_len(sg);
+
+                       if ((data->blocks == 1) && (count > data->blksz))
+                               count = frame;
+
+                       ccnt = count / 32;
+
+                       if (sync_dev == DAVINCI_DMA_MMCTXEVT)
+                               temp.src = (unsigned int)sg_dma_address(sg);
+                       else
+                               temp.dst = (unsigned int)sg_dma_address(sg);
                        temp.opt |= TCINTEN;
 
-                       if ((num_eight_words - temp_ccnt) > MAX_C_CNT) {
-                               temp.ccnt = (temp.ccnt & 0xFFFF0000)
-                                       | MAX_C_CNT;
-                               ccnt = temp.ccnt & 0x0000FFFF;
-                               temp_ccnt = temp_ccnt + ccnt;
-                       } else {
-                               temp.ccnt = (temp.ccnt & 0xFFFF0000)
-                                       | (num_eight_words -temp_ccnt);
-                               ccnt = temp.ccnt & 0x0000FFFF;
-                               temp_ccnt = temp_ccnt + ccnt;
-                       }
+                       temp.ccnt = (temp.ccnt & 0xFFFF0000) | (ccnt);
+
                        davinci_set_dma_params(edma_chan_num, &temp);
                        if (i != 0) {
                                j = i - 1;
@@ -526,8 +634,6 @@ r);
                                                chanel_num[j],
                                                edma_chan_num);
                        }
-                       if (temp_ccnt == num_eight_words)
-                               break;
                }
                davinci_dma_link_lch(sync_dev,
                                host->edma_ch_details.chanel_num[0]);
@@ -540,8 +646,7 @@ r);
 static void
 mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request 
*req)
 {
-       int timeout;
-
+       int timeout, sg_len;
        host->data = req->data;
        if (req->data == NULL) {
                host->data_dir = DAVINCI_MMC_DATADIR_NONE;
@@ -549,6 +654,9 @@ mmc_davinci_prepare_data(struct mmc_davi
                mmcsd_regs->mmc_nblk = 0;
                return;
        }
+       /* Init idx */
+       host->sg_idx = 0;
+
        dev_dbg(&mmc_dev,
                "MMCSD : Data xfer (%s %s), "
                "DTO %d cycles + %d ns, %d blocks of %d bytes\r\n",
@@ -589,15 +697,33 @@ mmc_davinci_prepare_data(struct mmc_davi
                break;
        }
 
-       if ((host->use_dma == 1)
-                       && (mmc_davinci_start_dma_transfer(host, req) == 0)) {
+       sg_len = (req->data->blocks == 1) ? 1 : req->data->sg_len;
+       host->sg_len = sg_len;
+
+       host->bytes_left = req->data->blocks * req->data->blksz;
+
+       if ((host->use_dma == 1) && (host->bytes_left % 32 == 0)
+           && (mmc_davinci_start_dma_transfer(host, req) == 0)) {
                host->buffer = NULL;
                host->bytes_left = 0;
        } else {
                /* Revert to CPU Copy */
-               host->buffer = (u32 *) (req->data->mrq->buffer);
-               host->bytes_left = req->data->blocks * req->data->blksz;
-               host->use_dma = 0;
+
+               host->do_dma = 0;
+               mmc_davinci_sg_to_buf(host);
+       }
+}
+
+/* PIO only */
+static void mmc_davinci_sg_to_buf(struct mmc_davinci_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->bytes_left) {
+               host->buffer_bytes_left = host->bytes_left;
        }
 }
 
@@ -606,14 +732,27 @@ static void mmc_davinci_request(struct m
        struct mmc_davinci_host *host = mmc_priv(mmc);
        unsigned long flags;
 
+       if (is_card_removed) {
+               if (req->cmd) {
+                       req->cmd->error |= MMC_ERR_TIMEOUT;
+                       mmc_request_done(mmc, req);
+               }
+               dev_dbg(&mmc_dev,
+                       "From code segment excuted when card removed\n");
+               return;
+       }
+
+       wait_on_data();
+
        if (!is_card_detect_progress) {
                spin_lock_irqsave(&mmc_lock, flags);
                is_card_busy = 1;
                spin_unlock_irqrestore(&mmc_lock, flags);
+               host->do_dma = 0;
                mmc_davinci_prepare_data(host, req);
                mmc_davinci_start_command(host, req->cmd);
        } else {
-               /* Queu up the request as card dectection is being excuted */
+               /* Queue up the request as card dectection is being excuted */
                que_mmc_host = mmc;
                que_mmc_request = req;
                spin_lock_irqsave(&mmc_lock, flags);
@@ -652,6 +791,13 @@ static void mmc_davinci_set_ios(struct m
        dev_dbg(&mmc_dev, "clock %dHz busmode %d powermode %d Vdd %d.%02d\r\n",
                ios->clock, ios->bus_mode, ios->power_mode,
                ios->vdd / 100, ios->vdd % 100);
+       if (ios->bus_width == MMC_BUS_WIDTH_4) {
+               dev_dbg(&mmc_dev, "\nEnabling 4 bit mode\n");
+               mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl | (1 << 2);
+       } else {
+               dev_dbg(&mmc_dev, "Disabling 4 bit mode\n");
+               mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl & ~(1 << 2);
+       }
 
        if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
                open_drain_freq = ((unsigned int)cpu_arm_clk
@@ -660,8 +806,12 @@ static void mmc_davinci_set_ios(struct m
                                | open_drain_freq;
        } else {
                mmc_push_pull_freq = calculate_freq_for_card(ios->clock);
+               mmcsd_regs->mmc_clk &= ~(0x100);
+               udelay(10);
                mmcsd_regs->mmc_clk = (mmcsd_regs->mmc_clk & ~(0xFF))
                                | mmc_push_pull_freq;
+               mmcsd_regs->mmc_clk |= 0x100;
+               udelay(10);
        }
        host->bus_mode = ios->bus_mode;
        if (ios->power_mode == MMC_POWER_UP) {
@@ -685,6 +835,15 @@ mmc_davinci_xfer_done(struct mmc_davinci
        if (data->error == MMC_ERR_NONE)
                data->bytes_xfered += data->blocks * data->blksz;
 
+       if (host->do_dma) {
+               davinci_abort_dma(host);
+
+               dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
+                            (data->
+                             flags & MMC_DATA_WRITE) ? DMA_TO_DEVICE :
+                            DMA_FROM_DEVICE);
+       }
+
        if (data->error == MMC_ERR_TIMEOUT) {
                spin_lock_irqsave(&mmc_lock, flags);
                is_card_busy = 0;
@@ -708,25 +867,24 @@ static void mmc_davinci_cmd_done(struct 
                                 struct mmc_command *cmd)
 {
        unsigned long flags;
-
        host->cmd = NULL;
-       switch (cmd->flags & MMC_RSP_MASK) {
-       case MMC_RSP_NONE:
-               /* resp 0 */
-               break;
 
-       case MMC_RSP_SHORT:
-               /* response types 1, 1b, 3, 4, 5, 6 */
-               cmd->resp[0] = mmcsd_regs->mmc_rsp67;
-               break;
+       if (!cmd) {
+               dev_warn(&mmc_dev, "%s(): No cmd ptr\n", __FUNCTION__);
+               return;
+       }
 
-       case MMC_RSP_LONG:
-               /* response type 2 */
-               cmd->resp[3] = mmcsd_regs->mmc_rsp01;
-               cmd->resp[2] = mmcsd_regs->mmc_rsp23;
-               cmd->resp[1] = mmcsd_regs->mmc_rsp45;
-               cmd->resp[0] = mmcsd_regs->mmc_rsp67;
-               break;
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               if (cmd->flags & MMC_RSP_136) {
+                       /* response type 2 */
+                       cmd->resp[3] = mmcsd_regs->mmc_rsp01;
+                       cmd->resp[2] = mmcsd_regs->mmc_rsp23;
+                       cmd->resp[1] = mmcsd_regs->mmc_rsp45;
+                       cmd->resp[0] = mmcsd_regs->mmc_rsp67;
+               } else {
+                       /* response types 1, 1b, 3, 4, 5, 6 */
+                       cmd->resp[0] = mmcsd_regs->mmc_rsp67;
+               }
        }
 
        if (host->data == NULL || cmd->error != MMC_ERR_NONE) {
@@ -746,7 +904,6 @@ static irqreturn_t mmc_davinci_irq(int i
        u16 status;
        int end_command;
        int end_transfer;
-       int byte_cnt = 0, i = 0;
        unsigned long flags;
 
        if (host->is_core_command) {
@@ -783,44 +940,36 @@ static irqreturn_t mmc_davinci_irq(int i
                        if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
                                if (status & MMCSD_EVENT_WRITE) {
                                        /* Buffer almost empty */
-                                       if (host->bytes_left > 0) {
-                                               byte_cnt =
-                                                       mmcsd_cfg.rw_threshold;
-                                               host->bytes_left -=
-                                                       mmcsd_cfg.rw_threshold;
-                                               for (i = 0; i < (byte_cnt / 4);
-                                                               i++) {
-                                                       mmcsd_regs->mmc_dxr =
-                                                               *host->buffer;
-                                                       host->buffer++;
-                                               }
-                                       }
+                                       if (host->bytes_left > 0)
+                                               davinci_fifo_data_trans(host);
                                }
                        }
 
                        if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
                                if (status & MMCSD_EVENT_READ) {
                                        /* Buffer almost empty */
-                                       if (host->bytes_left > 0) {
-                                               byte_cnt =
-                                                       mmcsd_cfg.rw_threshold;
-                                               host->bytes_left -=
-                                                       mmcsd_cfg.rw_threshold;
-                                               for (i = 0; i < (byte_cnt / 4);
-                                                               i++) {
-                                                       *host->buffer =
-                                                               mmcsd_regs->
-                                                                       mmc_drr;
-                                                       host->buffer++;
-                                               }
-                                       }
+                                       if (host->bytes_left > 0)
+                                               davinci_fifo_data_trans(host);
                                }
                        }
 
                        if (status & MMCSD_EVENT_BLOCK_XFERRED) {
                                /* Block sent/received */
                                if (host->data != NULL) {
-                                       end_transfer = 1;
+
+                                       if (host->do_dma == 1) {
+                                               end_transfer = 1;
+                                       } else {
+                                               /* if datasize<32 no RX ints 
are generated */
+                                               if (host->bytes_left > 0) {
+                                                       davinci_fifo_data_trans
+                                                           (host);
+                                               }
+                                               end_transfer = 1;
+                                       }
+                               } else {
+                                       dev_warn(&mmc_dev,
+                                                "TC:host->data is NULL\n");
                                }
                        }
 
@@ -829,6 +978,7 @@ static irqreturn_t mmc_davinci_irq(int i
                                if ((host->data) && (new_card_state != 0)) {
                                        host->data->error |= MMC_ERR_TIMEOUT;
                                        spin_lock_irqsave(&mmc_lock, flags);
+                                       is_card_removed = 1;
                                        new_card_state = 0;
                                        is_card_initialized = 0;
                                        spin_unlock_irqrestore(&mmc_lock,
@@ -836,15 +986,23 @@ static irqreturn_t mmc_davinci_irq(int i
                                        dev_dbg(&mmc_dev,
                                                "MMCSD: Data timeout, CMD%d and 
status is %x\r\n",
                                                host->cmd->opcode, status);
+
+                                       if (host->cmd) {
+                                               host->cmd->error |=
+                                                   MMC_ERR_TIMEOUT;
+                                       }
                                        end_transfer = 1;
-                                       host->cmd->error |= MMC_ERR_TIMEOUT;
                                }
-                               dev_dbg(&mmc_dev,
-                                       "MMCSD: Data timeout, CMD%d and status 
is %x\r\n",
-                                       host->cmd->opcode, status);
                        }
 
                        if (status & MMCSD_EVENT_ERROR_DATACRC) {
+                               /* DAT line portion is diabled and in reset 
state */
+                               mmcsd_regs->mmc_ctl =
+                                   mmcsd_regs->mmc_ctl | (1 << 1);
+                               udelay(10);
+                               mmcsd_regs->mmc_ctl =
+                                   mmcsd_regs->mmc_ctl & ~(1 << 1);
+
                                /* Data CRC error */
                                if (host->data) {
                                        host->data->error |= MMC_ERR_BADCRC;
@@ -859,6 +1017,10 @@ static irqreturn_t mmc_davinci_irq(int i
                        }
 
                        if (status & MMCSD_EVENT_ERROR_CMDTIMEOUT) {
+                               if (host->do_dma)
+                                       /* abort DMA transfer */
+                                       davinci_abort_dma(host);
+
                                /* Command timeout */
                                if (host->cmd) {
                                        /* Timeouts are normal in case of
@@ -888,7 +1050,11 @@ static irqreturn_t mmc_davinci_irq(int i
                                /* Command CRC error */
                                dev_dbg(&mmc_dev, "Command CRC error\r\n");
                                if (host->cmd) {
-                                       host->cmd->error |= MMC_ERR_BADCRC;
+                                       /* Ignore CMD CRC errors during high 
speed operation */
+                                       if (host->mmc->ios.clock <= 25000000) {
+                                               host->cmd->error |=
+                                                   MMC_ERR_BADCRC;
+                                       }
                                        end_command = 1;
                                }
                        }
@@ -926,6 +1092,7 @@ static irqreturn_t mmc_davinci_irq(int i
 
                        } else {
                                spin_lock_irqsave(&mmc_lock, flags);
+                               is_card_removed = 1;
                                new_card_state = 0;
                                is_card_initialized = 0;
                                spin_unlock_irqrestore(&mmc_lock, flags);
@@ -945,15 +1112,17 @@ static irqreturn_t mmc_davinci_irq(int i
 
                }
 
-               if (host->cmd_code == 1) {
+               if (host->cmd_code == 1 || host->cmd_code == 55) {
                        if (status & MMCSD_EVENT_EOFCMD) {
                                spin_lock_irqsave(&mmc_lock, flags);
+                               is_card_removed = 0;
                                new_card_state = 1;
                                is_card_initialized = 0;
                                spin_unlock_irqrestore(&mmc_lock, flags);
                        } else {
 
                                spin_lock_irqsave(&mmc_lock, flags);
+                               is_card_removed = 1;
                                new_card_state = 0;
                                is_card_initialized = 0;
                                spin_unlock_irqrestore(&mmc_lock, flags);
@@ -970,19 +1139,31 @@ static irqreturn_t mmc_davinci_irq(int i
                                is_req_queued_up = 0;
                                spin_unlock_irqrestore(&mmc_lock, flags);
                        }
-
                }
 
                if (host->cmd_code == 0) {
                        if (status & MMCSD_EVENT_EOFCMD) {
+                               static int flag_sd_mmc;
                                host->is_core_command = 0;
-                               host->cmd_code = 1;
-                               dev_dbg(&mmc_dev,
-                                       "MMC-Probing mmc with cmd1\n");
-                               /* Issue cmd1 */
-                               mmcsd_regs->mmc_arghl = 0x80300000;
-                               mmcsd_regs->mmc_cmd = 0x00000601;
 
+                               if (flag_sd_mmc) {
+                                       flag_sd_mmc = 0;
+                                       host->cmd_code = 1;
+                                       /* Issue cmd1 */
+                                       mmcsd_regs->mmc_arghl = 0x80300000;
+                                       mmcsd_regs->mmc_cmd = 0x00000601;
+                               } else {
+                                       flag_sd_mmc = 1;
+                                       host->cmd_code = 55;
+                                       /* Issue cmd55 */
+                                       mmcsd_regs->mmc_arghl = 0x0;
+                                       mmcsd_regs->mmc_cmd =
+                                           ((0x0 | (1 << 9) | 55));
+                               }
+
+                               dev_dbg(&mmc_dev,
+                                       "MMC-Probing mmc with cmd%d\n",
+                                       host->cmd_code);
                        } else {
                                spin_lock_irqsave(&mmc_lock, flags);
                                new_card_state = 0;
@@ -999,12 +1180,22 @@ static irqreturn_t mmc_davinci_irq(int i
 static struct mmc_host_ops mmc_davinci_ops = {
        .request = mmc_davinci_request,
        .set_ios = mmc_davinci_set_ios,
+       .get_ro = mmc_davinci_get_ro
 };
 
+static int mmc_davinci_get_ro(struct mmc_host *mmc)
+{
+       return 0;
+}
+
 void mmc_check_card(unsigned long data)
 {
        struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
        unsigned long flags;
+       struct mmc_card *card = NULL;
+
+       if (host->mmc && host->mmc->card)
+               card = host->mmc->card;
 
        if ((!is_card_detect_progress) || (!is_init_progress)) {
                if (is_card_initialized) {
@@ -1014,7 +1205,9 @@ void mmc_check_card(unsigned long data)
                        is_card_detect_progress = 1;
                        spin_unlock_irqrestore(&mmc_lock, flags);
                        /* Issue cmd13 */
-                       mmcsd_regs->mmc_arghl = 0x10000;
+                       mmcsd_regs->mmc_arghl = (card
+                                                && mmc_card_sd(card))
+                           ? (card->rca << 16) : 0x10000;
                        mmcsd_regs->mmc_cmd = 0x0000028D;
                } else {
                        host->is_core_command = 0;
@@ -1041,6 +1234,8 @@ static void davinci_mmc_check_status(uns
 
        if (!is_card_busy) {
                if (host->old_card_state ^ new_card_state) {
+                       davinci_reinit_chan();
+                       init_mmcsd_host();
                        mmc_detect_change(host->mmc, 0);
                        spin_lock_irqsave(&mmc_lock, flags);
                        host->old_card_state = new_card_state;
@@ -1057,6 +1252,7 @@ static void init_mmcsd_host(void)
        mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl | 0x1;
        /* DAT line portion is diabled and in reset state */
        mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl | (1 << 1);
+       udelay(10);
 
        mmcsd_regs->mmc_clk = 0x0;
        mmcsd_regs->mmc_clk = mmcsd_regs->mmc_clk | (1 << 8);
@@ -1066,13 +1262,14 @@ static void init_mmcsd_host(void)
 
        mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl & ~(0x1);
        mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl & ~(1 << 1);
+       udelay(10);
 }
 
 static int davinci_mmcsd_probe(struct platform_device *pdev)
 {
        struct mmc_davinci_host *host;
        struct mmc_host *mmc;
-       int ret;
+       int ret = 0;
 
        mmc = mmc_alloc_host(sizeof(struct mmc_davinci_host), &pdev->dev);
        if (!mmc) {
@@ -1085,14 +1282,44 @@ static int davinci_mmcsd_probe(struct pl
 
        init_mmcsd_host();
 
+       if (mmcsd_cfg.use_4bit_mode) {
+               dev_warn(&mmc_dev, "Supporting 4-bit mode\n");
+               mmc->caps |= MMC_CAP_4_BIT_DATA;
+       } else
+               dev_warn(&mmc_dev, "Not Supporting 4-bit mode\n");
+
        mmc->ops = &mmc_davinci_ops;
        mmc->f_min = 312500;
-       mmc->f_max = 20000000;
+#ifdef CONFIG_MMC_HIGHSPEED
+       mmc->f_max = 50000000;
+#else
+       mmc->f_max = 25000000;
+#endif
        mmc->ocr_avail = MMC_VDD_32_33;
 
+       mmc->max_phys_segs = 2;
+       mmc->max_hw_segs   = 2;
+       mmc->max_blk_size  = 4095;  /* BLEN is 11 bits */
+       mmc->max_blk_count = 65535; /* NBLK is 16 bits */
+       mmc->max_req_size  = mmc->max_blk_size * mmc->max_blk_count;
+       mmc->max_seg_size  = mmc->max_req_size;
+
+       dev_dbg(&mmc_dev, "max_phys_segs=%d\n", mmc->max_phys_segs);
+       dev_dbg(&mmc_dev, "max_hw_segs=%d\n", mmc->max_hw_segs);
+       dev_dbg(&mmc_dev, "max_blk_size=%d\n", mmc->max_blk_size);
+       dev_dbg(&mmc_dev, "max_req_size=%d\n", mmc->max_req_size);
+       dev_dbg(&mmc_dev, "max_seg_size=%d\n", mmc->max_seg_size);
+
        host = mmc_priv(mmc);
        host->mmc = mmc;        /* Important */
 
+       if (mmcsd_cfg.use_dma) {
+               dev_dbg(&mmc_dev, "Using DMA mode\n");
+               if (davinci_acquire_dma_channels(host) != 0)
+                       goto out;
+       } else
+               dev_dbg(&mmc_dev, "Not Using DMA mode\n");
+
        host->use_dma = mmcsd_cfg.use_dma;
        host->irq = MMCINT_INTERRUPT;
        host->sd_support = 1;
@@ -1122,13 +1349,20 @@ out:
 static int davinci_mmcsd_remove(struct platform_device *pdev)
 {
        struct mmc_davinci_host *host = platform_get_drvdata(pdev);
+       unsigned long flags;
 
        platform_set_drvdata(pdev, NULL);
-       mmc_remove_host(host->mmc);
-       free_irq(host->irq, host);
-       del_timer(&host->timer);
-       davinci_free_dma(DAVINCI_DMA_MMCTXEVT);
-       davinci_free_dma(DAVINCI_DMA_MMCRXEVT);
+       if (host) {
+               mmc_remove_host(host->mmc);
+               free_irq(host->irq, host);
+
+               spin_lock_irqsave(&mmc_lock, flags);
+               del_timer(&host->timer);
+               spin_unlock_irqrestore(&mmc_lock, flags);
+
+               davinci_release_dma_channels(host);
+       }
+
        return 0;
 
 }
@@ -1222,14 +1456,26 @@ free1:
                platform_device_unregister(&mmc_davinci_device);
        }
 
+       if (clkp) {
+               mmc_clkp = NULL;
+               clk_put(clkp);
+       }
+
        return -ENODEV;
 }
 
 static void __exit davinci_mmcsd_exit(void)
 {
+       struct clk *clkp;
+
        platform_driver_unregister(&davinci_mmcsd_driver);
        platform_device_unregister(&mmc_davinci_device);
-       clk_disable(mmc_clkp);
+
+       clkp = mmc_clkp;
+       mmc_clkp = NULL;
+
+       clk_disable(clkp);
+       clk_put(clkp);
 }
 
 module_init(davinci_mmcsd_init);
diff --git a/drivers/mmc/host/davinci_mmc.h b/drivers/mmc/host/davinci_mmc.h
index a6c4557..5840ccf 100644
--- a/drivers/mmc/host/davinci_mmc.h
+++ b/drivers/mmc/host/davinci_mmc.h
@@ -132,6 +132,7 @@ #define DAVINCI_MMC_DATADIR_WRITE   2
        int power_pin;
 
        int use_dma;
+       int do_dma;
        struct completion dma_completion;
 
        struct timer_list timer;
@@ -143,10 +144,16 @@ #define DAVINCI_MMC_DATADIR_WRITE 2
 
        edma_ch_mmcsd edma_ch_details;
 
+       unsigned int sg_len;
+       int sg_idx;
+       unsigned int buffer_bytes_left;
+       unsigned int dma_len;
+       int dma_state;
 };
 typedef struct {
        unsigned short rw_threshold;
        unsigned short use_dma;
+       unsigned short use_4bit_mode;
 } mmcsd_config_def;
 
 typedef enum {
@@ -168,4 +175,20 @@ #define MMCSD_EVENT_CRC_ERROR \
 #define MMCSD_EVENT_ERROR \
  (MMCSD_EVENT_TIMEOUT_ERROR | MMCSD_EVENT_CRC_ERROR)
 
+static void init_mmcsd_host(void);
+
+static void davinci_fifo_data_trans(struct mmc_davinci_host *host);
+
+static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host);
+
+static int mmc_davinci_send_dma_request(struct mmc_davinci_host *host,
+                                       struct mmc_request *req);
+
+static void mmc_davinci_xfer_done(struct mmc_davinci_host *host,
+                                 struct mmc_data *data);
+
+static int mmc_davinci_get_ro(struct mmc_host *mmc);
+
+static void davinci_abort_dma(struct mmc_davinci_host *host);
+
 #endif /* DAVINCI_MMC_H_ */
_______________________________________________
Davinci-linux-open-source mailing list
Davinci-linux-open-source@linux.davincidsp.com
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to