spi: improve spi driver
authorlyx <lyx@rock-chips.com>
Thu, 9 Sep 2010 10:23:23 +0000 (03:23 -0700)
committerlyx <lyx@rock-chips.com>
Thu, 9 Sep 2010 10:32:28 +0000 (03:32 -0700)
drivers/spi/rk2818_spim.c
drivers/spi/rk2818_spim.h
include/linux/spi/spi.h

index 8b03031a78fc951db4e0bb08a6a745c6bdb35d79..3edc86a9ded7f81c36027d3cddfa4dd00e22d5c6 100755 (executable)
 #include <linux/debugfs.h>
 #endif
 
+/*Ô­ÓеÄspiÇý¶¯Ð§ÂʱȽϵͣ¬
+ÎÞ·¨Âú×ã´óÊý¾ÝÁ¿µÄ´«Ê䣻
+ÏÂÃæÌá¸ßÁ½ÖÖÓÅ»¯ºóµÄspiÇý¶¯£¬
+QUICK_INT_TRANSFERʹÓÃÖжϣ¬QUICK_TRANSFERÖ±½Ó´¦Àí£¬
+Á½ÖÖ·½Ê½×î¶àÖ»ÄÜ´ò¿ªÒ»ÖÖ*/
+
+#define QUICK_TRANSFER         
+//#define QUICK_INT_TRANSFER
+
+#if 0
+#define DBG(x...)   printk(x)
+#else
+#define DBG(x...)
+#endif
+
+
 #define START_STATE    ((void *)0)
 #define RUNNING_STATE  ((void *)1)
 #define DONE_STATE     ((void *)2)
 #define MRST_SPI_ASSERT                1  ///CS0
 #define MRST_SPI_ASSERT1       2  ///CS1
 
-#if 0
-#define DBG(x...)   printk(x)
-#else
-#define DBG(x...)
-#endif
-
 /* Slave spi_dev related */
 struct chip_data {
        u16 cr0;
@@ -69,7 +79,7 @@ struct chip_data {
        u32 speed_hz;           /* baud rate */
        int (*write)(struct rk2818_spi *dws);
        int (*read)(struct rk2818_spi *dws);
-       void (*cs_control)(struct rk2818_spi *dws, u32 cs);
+       void (*cs_control)(struct rk2818_spi *dws, u32 cs, u8 flag);
 };
 
 #ifdef CONFIG_DEBUG_FS
@@ -182,6 +192,18 @@ static void wait_till_not_busy(struct rk2818_spi *dws)
                "DW SPI: Status keeps busy for 1000us after a read/write!\n");
 }
 
+static void wait_till_tf_empty(struct rk2818_spi *dws)
+{
+       unsigned long end = jiffies + 1 + usecs_to_jiffies(1000);
+
+       while (time_before(jiffies, end)) {
+               if (rk2818_readw(dws, SPIM_SR) & SR_TF_EMPT)
+                       return;
+       }
+       dev_err(&dws->master->dev,
+               "DW SPI: Status keeps busy for 1000us after a read/write!\n");
+}
+
 static void flush(struct rk2818_spi *dws)
 {
        while (rk2818_readw(dws, SPIM_SR) & SR_RF_NOT_EMPT)
@@ -190,20 +212,18 @@ static void flush(struct rk2818_spi *dws)
        wait_till_not_busy(dws);
 }
 
-static void spi_cs_control(struct rk2818_spi *dws, u32 cs)
+static void spi_cs_control(struct rk2818_spi *dws, u32 cs, u8 flag)
 {
        #ifdef CONFIG_MACH_RK2818INFO_IT50
        return;
        #else 
        struct rk2818_spi_platform_data *pdata = dws->master->dev.platform_data;
        struct spi_cs_gpio *cs_gpios = pdata->chipselect_gpios;
-       int i;
-       
-       if (cs == 0)
-               for (i=0; i<pdata->num_chipselect; i++)
-                       gpio_direction_output(cs_gpios[i].cs_gpio, GPIO_HIGH);
+
+       if (flag == 0)
+               gpio_direction_output(cs_gpios[cs].cs_gpio, GPIO_HIGH);
        else
-               gpio_direction_output(cs_gpios[cs-1].cs_gpio, GPIO_LOW);
+               gpio_direction_output(cs_gpios[cs].cs_gpio, GPIO_LOW);
        #endif
 }
 
@@ -217,7 +237,7 @@ static int null_writer(struct rk2818_spi *dws)
        rk2818_writew(dws, SPIM_DR0, 0);
        dws->tx += n_bytes;
 
-       wait_till_not_busy(dws);
+       //wait_till_not_busy(dws);
        return 1;
 }
 
@@ -241,7 +261,7 @@ static int u8_writer(struct rk2818_spi *dws)
        rk2818_writew(dws, SPIM_DR0, *(u8 *)(dws->tx));
        ++dws->tx;
 
-       wait_till_not_busy(dws);
+       //wait_till_not_busy(dws);
        return 1;
 }
 
@@ -266,7 +286,7 @@ static int u16_writer(struct rk2818_spi *dws)
        rk2818_writew(dws, SPIM_DR0, *(u16 *)(dws->tx));
        dws->tx += 2;
 
-       wait_till_not_busy(dws);
+       //wait_till_not_busy(dws);
        return 1;
 }
 
@@ -327,24 +347,23 @@ static void giveback(struct rk2818_spi *dws)
        struct spi_transfer *last_transfer;
        unsigned long flags;
        struct spi_message *msg;
-       DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__);
-       //spin_lock_irqsave(&dws->lock, flags);
+
+       spin_lock_irqsave(&dws->lock, flags);
        msg = dws->cur_msg;
        dws->cur_msg = NULL;
        dws->cur_transfer = NULL;
        dws->prev_chip = dws->cur_chip;
        dws->cur_chip = NULL;
        dws->dma_mapped = 0;
-       //queue_work(dws->workqueue, &dws->pump_messages);
-       //spin_unlock_irqrestore(&dws->lock, flags);
-       dws->busy = 0;
+       queue_work(dws->workqueue, &dws->pump_messages);
+       spin_unlock_irqrestore(&dws->lock, flags);
 
        last_transfer = list_entry(msg->transfers.prev,
                                        struct spi_transfer,
                                        transfer_list);
 
        if (!last_transfer->cs_change)
-               dws->cs_control(dws,MRST_SPI_DEASSERT);
+               dws->cs_control(dws,msg->spi->chip_select,MRST_SPI_DEASSERT);
 
        msg->state = NULL;
        if (msg->complete)
@@ -362,12 +381,8 @@ static void int_error_stop(struct rk2818_spi *dws, const char *msg)
        tasklet_schedule(&dws->pump_transfers);
 }
 
-static int pump_transfers(unsigned long data);
-
 static void transfer_complete(struct rk2818_spi *dws)
 {
-       DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__);
-
        /* Update total byte transfered return count actual bytes read */
        dws->cur_msg->actual_length += dws->len;
 
@@ -379,8 +394,7 @@ static void transfer_complete(struct rk2818_spi *dws)
                dws->cur_msg->status = 0;
                giveback(dws);
        } else
-               //tasklet_schedule(&dws->pump_transfers);
-               pump_transfers((unsigned long)dws);
+               tasklet_schedule(&dws->pump_transfers);
 }
 
 static irqreturn_t interrupt_transfer(struct rk2818_spi *dws)
@@ -388,8 +402,7 @@ static irqreturn_t interrupt_transfer(struct rk2818_spi *dws)
        u16 irq_status, irq_mask = 0x3f;
        u32 int_level = dws->fifo_len / 2;
        u32 left;
-       DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__);
-
+       
        irq_status = rk2818_readw(dws, SPIM_ISR) & irq_mask;
        /* Error handling */
        if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {
@@ -400,22 +413,24 @@ static irqreturn_t interrupt_transfer(struct rk2818_spi *dws)
                return IRQ_HANDLED;
        }
 
-               spi_mask_intr(dws, 0xff);
+       if (irq_status & SPI_INT_TXEI) {
+               spi_mask_intr(dws, SPI_INT_TXEI);
 
                left = (dws->tx_end - dws->tx) / dws->n_bytes;
                left = (left > int_level) ? int_level : left;
 
-               //DBG("+++++++++++++++left = %d++++++++++++++++++\n", left);
-
-               while (left--)
+               while (left--) {
                        dws->write(dws);
+                       wait_till_not_busy(dws);
+               }
                dws->read(dws);
 
                /* Re-enable the IRQ if there is still data left to tx */
                if (dws->tx_end > dws->tx)
-                       spi_umask_intr(dws, 0xff);
+                       spi_umask_intr(dws, SPI_INT_TXEI);
                else
                        transfer_complete(dws);
+       }
 
        return IRQ_HANDLED;
 }
@@ -425,7 +440,7 @@ static irqreturn_t rk2818_spi_irq(int irq, void *dev_id)
        struct rk2818_spi *dws = dev_id;
 
        if (!dws->cur_msg) {
-               spi_mask_intr(dws, 0xff);
+               spi_mask_intr(dws, SPI_INT_TXEI);
                /* Never fail */
                return IRQ_HANDLED;
        }
@@ -434,59 +449,13 @@ static irqreturn_t rk2818_spi_irq(int irq, void *dev_id)
 }
 
 /* Must be called inside pump_transfers() */
-static int poll_transfer(struct rk2818_spi *dws)
+static void poll_transfer(struct rk2818_spi *dws)
 {
-#if 0
-       int level = dws->fifo_len;
-       int left = (dws->tx_end - dws->tx)/dws->n_bytes;
-       int length = left > level ? level : left;
-       DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__);
-
-       while (left>0) {                
-               left -= length;
-               while (length--)
-                       dws->write(dws);
-               while(!(rk2818_readw(dws, SPIM_SR)& SR_TF_EMPT));
-                       cpu_relax();
-               //while(rk2818_readw(dws, SPIM_SR) & SR_BUSY);
-                       //cpu_relax();
+       while (dws->write(dws)) {
+               wait_till_not_busy(dws);
                dws->read(dws);
-
-               length = left > level ? level : left;
        }
-
        transfer_complete(dws);
-#else
-       if ((dws->read(dws))) {
-               goto comple;
-       }
-       
-       while (dws->tx<dws->tx_end){
-               dws->write(dws);
-               dws->read(dws);
-       }
-       
-       if (dws->rx < dws->rx_end) {
-               dws->read(dws);
-       }
-
-comple:
-       
-       dws->cur_msg->actual_length += dws->len;
-       
-       /* Move to next transfer */
-       dws->cur_msg->state = next_transfer(dws);
-                                       
-       if (dws->cur_msg->state == DONE_STATE) {
-               dws->cur_msg->status = 0;
-               giveback(dws);
-               return 0;
-       }
-       else {
-               return -1;
-       }
-       
-#endif
 }
 
 static void dma_transfer(struct rk2818_spi *dws, struct spi_transfer *xfer) //int cs_change)
@@ -500,13 +469,13 @@ static void spi_chip_sel(struct rk2818_spi *dws, u16 cs)
                return;
 
        if (dws->cs_control){
-           dws->cs_control(dws, cs+1);
+           dws->cs_control(dws, cs1);
        }
        //rk2818_writel(dws, SPIM_SER, 1 << cs);
        rk2818_writel(dws, SPIM_SER, 1 << 0);
 }
 
-static int pump_transfers(unsigned long data)
+static void pump_transfers(unsigned long data)
 {
        struct rk2818_spi *dws = (struct rk2818_spi *)data;
        struct spi_message *message = NULL;
@@ -521,15 +490,12 @@ static int pump_transfers(unsigned long data)
        u16 clk_div = 0;
        u32 speed = 0;
        u32 cr0 = 0;
-       
-       DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__);
 
        /* Get current state information */
        message = dws->cur_msg;
        transfer = dws->cur_transfer;
        chip = dws->cur_chip;
        spi = message->spi;     
-
        if (unlikely(!chip->clk_div))
                chip->clk_div = clk_get_rate(dws->clock_spim) / chip->speed_hz; 
        if (message->state == ERROR_STATE) {
@@ -648,7 +614,6 @@ static int pump_transfers(unsigned long data)
         * Interrupt mode
         * we only need set the TXEI IRQ, as TX/RX always happen syncronizely
         */
-       chip->poll_mode = 1;
        if (!dws->dma_mapped && !chip->poll_mode) {
                int templen = dws->len / dws->n_bytes;
                txint_level = dws->fifo_len / 2;
@@ -673,8 +638,8 @@ static int pump_transfers(unsigned long data)
                spi_chip_sel(dws, spi->chip_select);
                /* Set the interrupt mask, for poll mode just diable all int */
                spi_mask_intr(dws, 0xff);
-               //if (imask)
-                       //spi_umask_intr(dws, 0xff);
+               if (imask)
+                       spi_umask_intr(dws, imask);
                if (txint_level)
                        rk2818_writew(dws, SPIM_TXFTLR, txint_level);
 
@@ -686,15 +651,14 @@ static int pump_transfers(unsigned long data)
        if (dws->dma_mapped)
                dma_transfer(dws, transfer); ///cs_change);
 
-       if (chip->poll_mode) {
-               return poll_transfer(dws);
-       }
-       
-       return 0;
+       if (chip->poll_mode)
+               poll_transfer(dws);
+
+       return;
 
 early_exit:
        giveback(dws);
-       return 0;
+       return;
 }
 
 static void pump_messages(struct work_struct *work)
@@ -702,19 +666,18 @@ static void pump_messages(struct work_struct *work)
        struct rk2818_spi *dws =
                container_of(work, struct rk2818_spi, pump_messages);
        unsigned long flags;
-       DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__);
 
        /* Lock queue and check for queue work */
-       //spin_lock_irqsave(&dws->lock, flags);
+       spin_lock_irqsave(&dws->lock, flags);
        if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) {
                dws->busy = 0;
-               //spin_unlock_irqrestore(&dws->lock, flags);
+               spin_unlock_irqrestore(&dws->lock, flags);
                return;
        }
 
        /* Make sure we are not already running a message */
        if (dws->cur_msg) {
-               //spin_unlock_irqrestore(&dws->lock, flags);
+               spin_unlock_irqrestore(&dws->lock, flags);
                return;
        }
 
@@ -731,18 +694,10 @@ static void pump_messages(struct work_struct *work)
     dws->prev_chip = NULL; //ÿ¸öpump messageʱǿÖƸüÐÂcs dxj
     
        /* Mark as busy and launch transfers */
-       #if 0
        tasklet_schedule(&dws->pump_transfers);
 
        dws->busy = 1;
-       //spin_unlock_irqrestore(&dws->lock, flags);
-
-       #else
-       dws->busy = 1;
-       //spin_unlock_irqrestore(&dws->lock, flags);
-
-       while (pump_transfers((unsigned long)dws)) ;
-       #endif
+       spin_unlock_irqrestore(&dws->lock, flags);
 }
 
 /* spi_device use this to queue in their spi_msg */
@@ -750,7 +705,7 @@ static int rk2818_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 {
        struct rk2818_spi *dws = spi_master_get_devdata(spi->master);
        unsigned long flags;
-       DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__);
+
        spin_lock_irqsave(&dws->lock, flags);
 
        if (dws->run == QUEUE_STOPPED) {
@@ -766,9 +721,6 @@ static int rk2818_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 
        if (dws->run == QUEUE_RUNNING && !dws->busy) {
 
-               //DBG("+++++++++++++++add message++++++++++++++++++\n");
-
-               #if 0
                if (dws->cur_transfer || dws->cur_msg)
                        queue_work(dws->workqueue,
                                        &dws->pump_messages);
@@ -778,169 +730,855 @@ static int rk2818_spi_transfer(struct spi_device *spi, struct spi_message *msg)
                        pump_messages(&dws->pump_messages);
                        return 0;
                }
-               #else
-               //spin_unlock_irqrestore(&dws->lock, flags);            
-               //mutex_lock(&dws->mutex_lock);
-               pump_messages(&dws->pump_messages);
-               //mutex_unlock(&dws->mutex_lock);
-               //return 0;
-               #endif
        }
 
        spin_unlock_irqrestore(&dws->lock, flags);
-       DBG("+++++++++++++++quit %s++++++++++++++++++\n", __func__);
+       
        return 0;
 }
 
-/* This may be called twice for each spi dev */
-static int rk2818_spi_setup(struct spi_device *spi)
+static void do_read(struct rk2818_spi *dws)
 {
-       struct rk2818_spi_chip *chip_info = NULL;
-       struct chip_data *chip;
-
-       if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
-               return -EINVAL;
-
-       /* Only alloc on first setup */
-       chip = spi_get_ctldata(spi);
-       if (!chip) {
-               chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
-               if (!chip)
-                       return -ENOMEM;
-
-               chip->cs_control = spi_cs_control;
-               chip->enable_dma = 1;  //0;
-       }
-
-       /*
-        * Protocol drivers may change the chip settings, so...
-        * if chip_info exists, use it
-        */
-       chip_info = spi->controller_data;
-
-       /* chip_info doesn't always exist */
-       if (chip_info) {
-               if (chip_info->cs_control)
-                       chip->cs_control = chip_info->cs_control;
-
-               chip->poll_mode = chip_info->poll_mode;
-               chip->type = chip_info->type;
-
-               chip->rx_threshold = 0;
-               chip->tx_threshold = 0;
-
-               chip->enable_dma = chip_info->enable_dma;
-       }
-
-       if (spi->bits_per_word <= 8) {
-               chip->n_bytes = 1;
-               chip->dma_width = 1;
-               chip->read = u8_reader;
-               chip->write = u8_writer;
-       } else if (spi->bits_per_word <= 16) {
-               chip->n_bytes = 2;
-               chip->dma_width = 2;
-               chip->read = u16_reader;
-               chip->write = u16_writer;
-       } else {
-               /* Never take >16b case for MRST SPIC */
-               dev_err(&spi->dev, "invalid wordsize\n");
-               return -EINVAL;
-       }
-       chip->bits_per_word = spi->bits_per_word;
+       int count = 0;
 
-       if (!spi->max_speed_hz) {
-               dev_err(&spi->dev, "No max speed HZ parameter\n");
-               return -EINVAL;
+       spi_enable_chip(dws, 0);
+       rk2818_writew(dws, SPIM_CTRLR1, dws->rx_end-dws->rx-1);
+       spi_enable_chip(dws, 1);                
+       rk2818_writew(dws, SPIM_DR0, 0);
+       while (1) {
+               if (dws->read(dws))
+                       break;
+               if (count ++ == 0x10) {
+                       printk("+++++++++++spi receive data time out+++++++++++++\n");
+                       break;
+               }
+               
        }
-       chip->speed_hz = spi->max_speed_hz;
-
-       chip->tmode = 0; /* Tx & Rx */
-       /* Default SPI mode is SCPOL = 0, SCPH = 0 */
-       chip->cr0 = (chip->bits_per_word - 1)
-                       | (chip->type << SPI_FRF_OFFSET)
-                       | (spi->mode  << SPI_MODE_OFFSET)
-                       | (chip->tmode << SPI_TMOD_OFFSET);
-
-       spi_set_ctldata(spi, chip);
-       return 0;
 }
 
-static void rk2818_spi_cleanup(struct spi_device *spi)
+static void do_write(struct rk2818_spi *dws)
 {
-       struct chip_data *chip = spi_get_ctldata(spi);
-       kfree(chip);
+       while (dws->tx<dws->tx_end) {
+               dws->write(dws);
+       }
 }
 
-static int __devinit init_queue(struct rk2818_spi *dws)
-{
-       INIT_LIST_HEAD(&dws->queue);
-       spin_lock_init(&dws->lock);
-
-       dws->run = QUEUE_STOPPED;
-       dws->busy = 0;
-
-       tasklet_init(&dws->pump_transfers,
-                       pump_transfers, (unsigned long)dws);
-
-       INIT_WORK(&dws->pump_messages, pump_messages);
-       dws->workqueue = create_singlethread_workqueue(
-                                       dev_name(dws->master->dev.parent));
-       if (dws->workqueue == NULL)
-               return -EBUSY;
 
-       return 0;
-}
+#if defined(QUICK_TRANSFER)
 
-static int start_queue(struct rk2818_spi *dws)
+/* Caller already set message->status; dma and pio irqs are blocked */
+static void msg_giveback(struct rk2818_spi *dws)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&dws->lock, flags);
-
-       if (dws->run == QUEUE_RUNNING || dws->busy) {
-               spin_unlock_irqrestore(&dws->lock, flags);
-               return -EBUSY;
-       }
-
-       dws->run = QUEUE_RUNNING;
+       struct spi_transfer *last_transfer;
+       struct spi_message *msg;
+       DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__);
+       msg = dws->cur_msg;
        dws->cur_msg = NULL;
        dws->cur_transfer = NULL;
+       dws->prev_chip = dws->cur_chip;
        dws->cur_chip = NULL;
-       dws->prev_chip = NULL;
-       spin_unlock_irqrestore(&dws->lock, flags);
-
-       //queue_work(dws->workqueue, &dws->pump_messages);
-
-       return 0;
-}
-
-static int stop_queue(struct rk2818_spi *dws)
-{
-       unsigned long flags;
-       unsigned limit = 50;
-       int status = 0;
+       dws->dma_mapped = 0;
+       dws->busy = 0;
 
-       spin_lock_irqsave(&dws->lock, flags);
-       dws->run = QUEUE_STOPPED;
-       while (!list_empty(&dws->queue) && dws->busy && limit--) {
-               spin_unlock_irqrestore(&dws->lock, flags);
-               msleep(10);
-               spin_lock_irqsave(&dws->lock, flags);
-       }
+       last_transfer = list_entry(msg->transfers.prev,
+                                       struct spi_transfer,
+                                       transfer_list);
 
-       if (!list_empty(&dws->queue) || dws->busy)
-               status = -EBUSY;
-       spin_unlock_irqrestore(&dws->lock, flags);
+       if (!last_transfer->cs_change)
+               dws->cs_control(dws,msg->spi->chip_select,MRST_SPI_DEASSERT);
 
-       return status;
+       msg->state = NULL;
+       if (msg->complete)
+               msg->complete(msg->context);
 }
 
-static int destroy_queue(struct rk2818_spi *dws)
+/* Must be called inside pump_transfers() */
+static int do_transfer(struct rk2818_spi *dws)
 {
-       int status;
+       if (dws->rx) {
+               if (dws->tx) {
+                       do_write(dws);
+               }
+               do_read(dws);
+       }
+       else {
+               do_write(dws);
+       }
 
-       status = stop_queue(dws);
+       wait_till_tf_empty(dws);
+       wait_till_not_busy(dws);
+       
+       dws->cur_msg->actual_length += dws->len;
+       
+       /* Move to next transfer */
+       dws->cur_msg->state = next_transfer(dws);
+                                       
+       if (dws->cur_msg->state == DONE_STATE) {
+               dws->cur_msg->status = 0;
+               msg_giveback(dws);
+               return 0;
+       }
+       else {
+               return -1;
+       }
+       
+}
+
+static int rk2818_pump_transfers(struct rk2818_spi *dws)
+{
+       struct spi_message *message = NULL;
+       struct spi_transfer *transfer = NULL;
+       struct spi_transfer *previous = NULL;
+       struct spi_device *spi = NULL;
+       struct chip_data *chip = NULL;
+       u8 bits = 0;
+       u8 cs_change = 0;
+       u16 clk_div = 0;
+       u32 speed = 0;
+       u32 cr0 = 0;
+       
+       DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__);
+
+       /* Get current state information */
+       message = dws->cur_msg;
+       transfer = dws->cur_transfer;
+       chip = dws->cur_chip;
+       spi = message->spi;     
+
+       if (unlikely(!chip->clk_div))
+               chip->clk_div = clk_get_rate(dws->clock_spim) / chip->speed_hz; 
+       if (message->state == ERROR_STATE) {
+               message->status = -EIO;
+               goto early_exit;
+       }
+
+       /* Handle end of message */
+       if (message->state == DONE_STATE) {
+               message->status = 0;
+               goto early_exit;
+       }
+
+       /* Delay if requested at end of transfer*/
+       if (message->state == RUNNING_STATE) {
+               previous = list_entry(transfer->transfer_list.prev,
+                                       struct spi_transfer,
+                                       transfer_list);
+               if (previous->delay_usecs)
+                       udelay(previous->delay_usecs);
+       }
+
+       dws->n_bytes = chip->n_bytes;
+       dws->dma_width = chip->dma_width;
+       dws->cs_control = chip->cs_control;
+
+       dws->rx_dma = transfer->rx_dma;
+       dws->tx_dma = transfer->tx_dma;
+       dws->tx = (void *)transfer->tx_buf;
+       dws->tx_end = dws->tx + transfer->len;
+       dws->rx = transfer->rx_buf;
+       dws->rx_end = dws->rx + transfer->len;
+       dws->write = dws->tx ? chip->write : null_writer;
+       dws->read = dws->rx ? chip->read : null_reader;
+       if (dws->rx && dws->tx) {
+               int temp_len = transfer->len;
+               int len;
+               unsigned char *tx_buf;
+               for (len=0; *tx_buf++ != 0; len++);
+               dws->tx_end = dws->tx + len;
+               dws->rx_end = dws->rx + temp_len - len;
+       }
+       dws->cs_change = transfer->cs_change;
+       dws->len = dws->cur_transfer->len;
+       if (chip != dws->prev_chip)
+               cs_change = 1;
+
+       cr0 = chip->cr0;
+
+       /* Handle per transfer options for bpw and speed */
+       if (transfer->speed_hz) {
+               speed = chip->speed_hz;
+
+               if (transfer->speed_hz != speed) {
+                       speed = transfer->speed_hz;
+                       if (speed > clk_get_rate(dws->clock_spim)) {
+                               printk(KERN_ERR "MRST SPI0: unsupported"
+                                       "freq: %dHz\n", speed);
+                               message->status = -EIO;
+                               goto early_exit;
+                       }
+
+                       /* clk_div doesn't support odd number */
+                       clk_div = clk_get_rate(dws->clock_spim) / speed;
+                       clk_div = (clk_div + 1) & 0xfffe;
+
+                       chip->speed_hz = speed;
+                       chip->clk_div = clk_div;
+               }
+       }
+       if (transfer->bits_per_word) {
+               bits = transfer->bits_per_word;
+
+               switch (bits) {
+               case 8:
+                       dws->n_bytes = 1;
+                       dws->dma_width = 1;
+                       dws->read = (dws->read != null_reader) ?
+                                       u8_reader : null_reader;
+                       dws->write = (dws->write != null_writer) ?
+                                       u8_writer : null_writer;
+                       break;
+               case 16:
+                       dws->n_bytes = 2;
+                       dws->dma_width = 2;
+                       dws->read = (dws->read != null_reader) ?
+                                       u16_reader : null_reader;
+                       dws->write = (dws->write != null_writer) ?
+                                       u16_writer : null_writer;
+                       break;
+               default:
+                       printk(KERN_ERR "MRST SPI0: unsupported bits:"
+                               "%db\n", bits);
+                       message->status = -EIO;
+                       goto early_exit;
+               }
+
+               cr0 = (bits - 1)
+                       | (chip->type << SPI_FRF_OFFSET)
+                       | (spi->mode << SPI_MODE_OFFSET)
+                       | (chip->tmode << SPI_TMOD_OFFSET);
+       }
+       message->state = RUNNING_STATE;
+       /*
+        * Adjust transfer mode if necessary. Requires platform dependent
+        * chipselect mechanism.
+        */
+       if (dws->cs_control) {
+               if (dws->rx && dws->tx)
+                       chip->tmode = 0x00;
+               else if (dws->rx)
+                       chip->tmode = 0x02;
+               else
+                       chip->tmode = 0x01;
+
+               cr0 &= ~(0x3 << SPI_MODE_OFFSET);
+               cr0 |= (chip->tmode << SPI_TMOD_OFFSET);
+       }
+
+       /*
+        * Reprogram registers only if
+        *      1. chip select changes
+        *      2. clk_div is changed
+        *      3. control value changes
+        */
+       if (rk2818_readw(dws, SPIM_CTRLR0) != cr0 || cs_change || clk_div) {
+               spi_enable_chip(dws, 0);
+               if (rk2818_readw(dws, SPIM_CTRLR0) != cr0)
+                       rk2818_writew(dws, SPIM_CTRLR0, cr0);
+
+               spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);            
+               spi_chip_sel(dws, spi->chip_select);
+               spi_enable_chip(dws, 1);
+               if (cs_change)
+                       dws->prev_chip = chip;
+       }
+
+       return do_transfer(dws);
+       
+early_exit:
+       
+       msg_giveback(dws);
+       
+       return 0;
+}
+
+static void rk2818_pump_messages(struct work_struct *work)
+{
+       struct rk2818_spi *dws =
+               container_of(work, struct rk2818_spi, pump_messages);
+       DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__);
+
+       if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) {
+               dws->busy = 0;
+               return;
+       }
+
+       /* Make sure we are not already running a message */
+       if (dws->cur_msg) {
+               return;
+       }
+
+       /* Extract head of queue */
+       dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue);
+       list_del_init(&dws->cur_msg->queue);
+
+       /* Initial message state*/
+       dws->cur_msg->state = START_STATE;
+       dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,
+                                               struct spi_transfer,
+                                               transfer_list);
+       dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi);
+    dws->prev_chip = NULL; //ÿ¸öpump messageʱǿÖƸüÐÂcs dxj
+    
+       /* Mark as busy and launch transfers */
+       dws->busy = 1;
+
+       while (rk2818_pump_transfers(dws)) ;
+}
+
+/* spi_device use this to queue in their spi_msg */
+static int rk2818_spi_quick_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+       struct rk2818_spi *dws = spi_master_get_devdata(spi->master);
+       unsigned long flags;
+       
+       DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__);
+       
+       spin_lock_irqsave(&dws->lock, flags);
+
+       if (dws->run == QUEUE_STOPPED) {
+               spin_unlock_irqrestore(&dws->lock, flags);
+               return -ESHUTDOWN;
+       }
+
+       msg->actual_length = 0;
+       msg->status = -EINPROGRESS;
+       msg->state = START_STATE;
+
+       list_add_tail(&msg->queue, &dws->queue);
+
+       if (dws->run == QUEUE_RUNNING && !dws->busy) {
+               rk2818_pump_messages(&dws->pump_messages);
+       }
+
+       spin_unlock_irqrestore(&dws->lock, flags);
+       return 0;
+}
+
+#elif defined(QUICK_INT_TRANSFER)
+
+/* Caller already set message->status; dma and pio irqs are blocked */
+static void msg_giveback(struct rk2818_spi *dws)
+{
+       struct spi_transfer *last_transfer;
+       unsigned long flags;
+       struct spi_message *msg;
+
+       spin_lock_irqsave(&dws->lock, flags);
+       msg = dws->cur_msg;
+       dws->cur_msg = NULL;
+       dws->cur_transfer = NULL;
+       dws->prev_chip = dws->cur_chip;
+       dws->cur_chip = NULL;
+       dws->dma_mapped = 0;
+       spin_unlock_irqrestore(&dws->lock, flags);
+
+       last_transfer = list_entry(msg->transfers.prev,
+                                       struct spi_transfer,
+                                       transfer_list);
+
+       if (!last_transfer->cs_change)
+               dws->cs_control(dws,msg->spi->chip_select,MRST_SPI_DEASSERT);
+
+       msg->state = NULL;
+       if (msg->complete)
+               msg->complete(msg->context);
+}
+
+static void *get_next_transfer(struct rk2818_spi *dws)
+{
+       struct spi_message *msg = dws->cur_msg;
+       struct spi_transfer *trans = dws->cur_transfer;
+
+       /* Move to next transfer */
+       if (trans->transfer_list.next != &msg->transfers) {
+               dws->cur_transfer =
+                       list_entry(trans->transfer_list.next,
+                                       struct spi_transfer,
+                                       transfer_list);
+               dws->cur_transfer->state = START_STATE;
+               return RUNNING_STATE;
+       } else
+               return DONE_STATE;
+}
+
+static void msg_transfer_complete(struct rk2818_spi *dws)
+{
+       /* Update total byte transfered return count actual bytes read */
+       dws->cur_msg->actual_length += dws->len;
+
+       /* Move to next transfer */
+       dws->cur_msg->state = get_next_transfer(dws);
+
+       /* Handle end of message */
+       if (dws->cur_msg->state == DONE_STATE) {
+               dws->cur_msg->status = 0;
+               msg_giveback(dws);
+       }
+}
+
+static void spi_set_transfers(struct rk2818_spi *dws)
+{
+       struct spi_message *message = NULL;
+       struct spi_transfer *transfer = NULL;
+       struct spi_device *spi = NULL;
+       struct chip_data *chip = NULL;
+       u8 bits = 0;
+       u8 imask = 0;
+       u8 cs_change = 0;
+       u16 txint_level = 0;
+       u16 clk_div = 0;
+       u32 speed = 0;
+       u32 cr0 = 0;
+
+       /* Get current state information */
+       message = dws->cur_msg;
+       transfer = dws->cur_transfer;
+       chip = dws->cur_chip;
+       spi = message->spi;     
+       if (unlikely(!chip->clk_div))
+               chip->clk_div = clk_get_rate(dws->clock_spim) / chip->speed_hz; 
+
+       dws->n_bytes = chip->n_bytes;
+       dws->dma_width = chip->dma_width;
+       dws->cs_control = chip->cs_control;
+
+       dws->rx_dma = transfer->rx_dma;
+       dws->tx_dma = transfer->tx_dma;
+       dws->tx = (void *)transfer->tx_buf;
+       dws->tx_end = dws->tx + transfer->len;
+       dws->rx = transfer->rx_buf;
+       dws->rx_end = dws->rx + transfer->len;
+       dws->write = dws->tx ? chip->write : null_writer;
+       dws->read = dws->rx ? chip->read : null_reader; 
+       if (dws->rx && dws->tx) {
+               int temp_len = transfer->len;
+               int len;
+               unsigned char *tx_buf;
+               for (len=0; *tx_buf++ != 0; len++);
+               dws->tx_end = dws->tx + len;
+               dws->rx_end = dws->rx + temp_len - len;
+       }
+       dws->cs_change = transfer->cs_change;
+       dws->len = dws->cur_transfer->len;
+       if (chip != dws->prev_chip)
+               cs_change = 1;
+
+       cr0 = chip->cr0;
+
+       /* Handle per transfer options for bpw and speed */
+       if (transfer->speed_hz) {
+               speed = chip->speed_hz;
+
+               if (transfer->speed_hz != speed) {
+                       speed = transfer->speed_hz;
+                       if (speed > clk_get_rate(dws->clock_spim)) {
+                               printk(KERN_ERR "MRST SPI0: unsupported"
+                                       "freq: %dHz\n", speed);
+                               message->status = -EIO;
+                               goto early_exit;
+                       }
+
+                       /* clk_div doesn't support odd number */
+                       clk_div = clk_get_rate(dws->clock_spim) / speed;
+                       clk_div = (clk_div + 1) & 0xfffe;
+
+                       chip->speed_hz = speed;
+                       chip->clk_div = clk_div;
+               }
+       }
+       if (transfer->bits_per_word) {
+               bits = transfer->bits_per_word;
+
+               switch (bits) {
+               case 8:
+                       dws->n_bytes = 1;
+                       dws->dma_width = 1;
+                       dws->read = (dws->read != null_reader) ?
+                                       u8_reader : null_reader;
+                       dws->write = (dws->write != null_writer) ?
+                                       u8_writer : null_writer;
+                       break;
+               case 16:
+                       dws->n_bytes = 2;
+                       dws->dma_width = 2;
+                       dws->read = (dws->read != null_reader) ?
+                                       u16_reader : null_reader;
+                       dws->write = (dws->write != null_writer) ?
+                                       u16_writer : null_writer;
+                       break;
+               default:
+                       printk(KERN_ERR "MRST SPI0: unsupported bits:"
+                               "%db\n", bits);
+                       message->status = -EIO;
+                       goto early_exit;
+               }
+
+               cr0 = (bits - 1)
+                       | (chip->type << SPI_FRF_OFFSET)
+                       | (spi->mode << SPI_MODE_OFFSET)
+                       | (chip->tmode << SPI_TMOD_OFFSET);
+       }
+       
+       /*
+        * Adjust transfer mode if necessary. Requires platform dependent
+        * chipselect mechanism.
+        */
+       if (dws->cs_control) {
+               if (dws->rx && dws->tx)
+                       chip->tmode = 0x00;
+               else if (dws->rx)
+                       chip->tmode = 0x02;
+               else
+                       chip->tmode = 0x01;
+
+               cr0 &= ~(0x3 << SPI_MODE_OFFSET);
+               cr0 |= (chip->tmode << SPI_TMOD_OFFSET);
+       }
+
+       //set state
+       dws->cur_msg->state = RUNNING_STATE;
+       dws->cur_transfer->state = RUNNING_STATE;
+
+       dws->busy = 1;
+
+       /*
+        * Interrupt mode
+        * we only need set the TXEI IRQ, as TX/RX always happen syncronizely
+        */
+       txint_level = dws->fifo_len / 2;
+       imask |= SPI_INT_TXEI;
+       
+       /*
+        * Reprogram registers only if
+        *      1. chip select changes
+        *      2. clk_div is changed
+        *      3. control value changes
+        */
+       if (rk2818_readw(dws, SPIM_CTRLR0) != cr0 || cs_change || clk_div || imask) {           
+               DBG("[function: %s] [line: %d] [reprogram registers]\n", __func__, __LINE__);
+
+               spi_enable_chip(dws, 0);
+               if (rk2818_readw(dws, SPIM_CTRLR0) != cr0)
+                       rk2818_writew(dws, SPIM_CTRLR0, cr0);
+
+               spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);    
+               
+
+               spi_chip_sel(dws, spi->chip_select);
+               /* Set the interrupt mask, for poll mode just diable all int */
+               spi_mask_intr(dws, 0xff);
+               if (imask)
+                       spi_umask_intr(dws, SPI_INT_TXEI | SPI_INT_RXFI);
+               if (txint_level) {
+                       rk2818_writew(dws, SPIM_TXFTLR, txint_level);                   
+                       rk2818_writew(dws, SPIM_RXFTLR, txint_level);
+               }
+               if (cs_change)
+                       dws->prev_chip = chip;
+                               
+               spi_enable_chip(dws, 1);
+               
+       }
+       
+
+       return;
+
+early_exit:
+       giveback(dws);
+       dws->busy = 0;
+
+       return;
+}
+
+static void transfer_delay(struct rk2818_spi *dws)
+{
+       /* Delay if requested at end of transfer*/
+       if (dws->cur_msg->state == RUNNING_STATE) {
+               if (dws->cur_transfer->state == RUNNING_STATE) {
+                       DBG("[function: %s] [line: %d] [msg is under transfer]\n", __func__, __LINE__);
+                       return ;
+               }
+               else {                                  
+                       /* Delay if requested at end of transfer*/
+                       struct spi_transfer *previous = list_entry(dws->cur_transfer->transfer_list.prev,
+                                               struct spi_transfer,
+                                               transfer_list);
+                       if (previous->delay_usecs)
+                               udelay(previous->delay_usecs);
+               }
+       }
+
+}
+
+static void rk2818_pump_transfers(struct rk2818_spi *dws)
+{
+       unsigned long flags;
+
+       DBG("enter [function: %s] [line: %d]\n", __func__, __LINE__);
+
+       /* Lock queue and check for queue work */
+       spin_lock_irqsave(&dws->lock, flags);
+       
+       if (!(dws->cur_msg)) {          
+               //check for queue work
+               if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) {                     
+                       DBG("[function: %s] [line: %d] [queue is empty]\n", __func__, __LINE__);
+                       dws->busy = 0;
+                       spin_unlock_irqrestore(&dws->lock, flags);
+                       return;
+               }
+               DBG("[function: %s] [line: %d]\n", __func__, __LINE__);
+               /* Extract head of queue */
+               dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue);
+               list_del_init(&dws->cur_msg->queue);
+               
+               /* Initial message state*/
+               dws->cur_msg->state = START_STATE;
+               dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,
+                                                       struct spi_transfer,
+                                                       transfer_list);
+               dws->cur_transfer->state = START_STATE;
+               dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi);
+               dws->prev_chip = NULL; //ÿ¸öpump messageʱǿÖƸüÐÂcs dxj
+       }
+       
+       spin_unlock_irqrestore(&dws->lock, flags);
+       
+       //init transfer 
+       transfer_delay(dws);
+       return spi_set_transfers(dws);
+}
+
+static irqreturn_t rk2818_spi_irq_handle(int irq, void *dev_id)
+{
+       struct rk2818_spi *dws = dev_id;
+       u16 irq_status, irq_mask = 0x3f;
+       
+       DBG("enter [function: %s] [line: %d]\n", __func__, __LINE__);
+       
+       if (!dws->cur_msg) {
+               spi_mask_intr(dws, SPI_INT_TXEI);               
+               rk2818_pump_transfers(dws);
+               return IRQ_HANDLED;
+       }
+       
+       irq_status = rk2818_readw(dws, SPIM_ISR) & irq_mask;
+       /* Error handling */
+       if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {                
+               DBG("[function: %s] [line: %d] [Error handling]\n", __func__, __LINE__);
+               rk2818_readw(dws, SPIM_TXOICR);
+               rk2818_readw(dws, SPIM_RXOICR);
+               rk2818_readw(dws, SPIM_RXUICR);
+               int_error_stop(dws, "interrupt_transfer: fifo overrun");
+               rk2818_pump_transfers(dws);
+               return IRQ_HANDLED;
+       }
+       
+       spi_mask_intr(dws, SPI_INT_TXEI | SPI_INT_RXFI);
+
+       if (dws->rx) {
+               if (dws->tx) {
+                       do_write(dws);
+               }
+               do_read(dws);
+       }
+       else {
+               do_write(dws);
+       }
+       
+       wait_till_tf_empty(dws);
+       wait_till_not_busy(dws);
+
+       msg_transfer_complete(dws);
+       rk2818_pump_transfers(dws);
+
+       return IRQ_HANDLED;
+
+}
+
+static int rk2818_spi_quick_int_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+       struct rk2818_spi *dws = spi_master_get_devdata(spi->master);
+       unsigned long flags;
+
+       spin_lock_irqsave(&dws->lock, flags);
+
+       if (dws->run == QUEUE_STOPPED) {
+               spin_unlock_irqrestore(&dws->lock, flags);
+               return -ESHUTDOWN;
+       }
+
+       msg->actual_length = 0;
+       msg->status = -EINPROGRESS;
+       msg->state = START_STATE;
+
+       list_add_tail(&msg->queue, &dws->queue);
+
+       DBG("[function: %s] [line: %d] [post msg]\n", __func__, __LINE__);
+
+       spin_unlock_irqrestore(&dws->lock, flags);
+
+       if (dws->run == QUEUE_RUNNING && !dws->busy) {          
+               dws->busy = 1;
+               rk2818_pump_transfers(dws);
+       }
+
+       
+       return 0;
+}
+
+#endif
+
+/* This may be called twice for each spi dev */
+static int rk2818_spi_setup(struct spi_device *spi)
+{
+       struct rk2818_spi_chip *chip_info = NULL;
+       struct chip_data *chip;
+
+       if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
+               return -EINVAL;
+
+       /* Only alloc on first setup */
+       chip = spi_get_ctldata(spi);
+       if (!chip) {
+               chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+               if (!chip)
+                       return -ENOMEM;
+
+               chip->cs_control = spi_cs_control;
+               chip->enable_dma = 1;  //0;
+       }
+
+       /*
+        * Protocol drivers may change the chip settings, so...
+        * if chip_info exists, use it
+        */
+       chip_info = spi->controller_data;
+
+       /* chip_info doesn't always exist */
+       if (chip_info) {
+               if (chip_info->cs_control)
+                       chip->cs_control = chip_info->cs_control;
+
+               chip->poll_mode = chip_info->poll_mode;
+               chip->type = chip_info->type;
+
+               chip->rx_threshold = 0;
+               chip->tx_threshold = 0;
+
+               chip->enable_dma = chip_info->enable_dma;
+       }
+
+       if (spi->bits_per_word <= 8) {
+               chip->n_bytes = 1;
+               chip->dma_width = 1;
+               chip->read = u8_reader;
+               chip->write = u8_writer;
+       } else if (spi->bits_per_word <= 16) {
+               chip->n_bytes = 2;
+               chip->dma_width = 2;
+               chip->read = u16_reader;
+               chip->write = u16_writer;
+       } else {
+               /* Never take >16b case for MRST SPIC */
+               dev_err(&spi->dev, "invalid wordsize\n");
+               return -EINVAL;
+       }
+       chip->bits_per_word = spi->bits_per_word;
+
+       if (!spi->max_speed_hz) {
+               dev_err(&spi->dev, "No max speed HZ parameter\n");
+               return -EINVAL;
+       }
+       chip->speed_hz = spi->max_speed_hz;
+
+       chip->tmode = 0; /* Tx & Rx */
+       /* Default SPI mode is SCPOL = 0, SCPH = 0 */
+       chip->cr0 = (chip->bits_per_word - 1)
+                       | (chip->type << SPI_FRF_OFFSET)
+                       | (spi->mode  << SPI_MODE_OFFSET)
+                       | (chip->tmode << SPI_TMOD_OFFSET);
+
+       spi_set_ctldata(spi, chip);
+       return 0;
+}
+
+static void rk2818_spi_cleanup(struct spi_device *spi)
+{
+       struct chip_data *chip = spi_get_ctldata(spi);
+       kfree(chip);
+}
+
+static int __devinit init_queue(struct rk2818_spi *dws)
+{
+       INIT_LIST_HEAD(&dws->queue);
+       spin_lock_init(&dws->lock);
+
+       dws->run = QUEUE_STOPPED;
+       dws->busy = 0;
+
+       tasklet_init(&dws->pump_transfers,
+                       pump_transfers, (unsigned long)dws);
+
+       INIT_WORK(&dws->pump_messages, pump_messages);
+       dws->workqueue = create_singlethread_workqueue(
+                                       dev_name(dws->master->dev.parent));
+       if (dws->workqueue == NULL)
+               return -EBUSY;
+
+       return 0;
+}
+
+static int start_queue(struct rk2818_spi *dws)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dws->lock, flags);
+
+       if (dws->run == QUEUE_RUNNING || dws->busy) {
+               spin_unlock_irqrestore(&dws->lock, flags);
+               return -EBUSY;
+       }
+
+       dws->run = QUEUE_RUNNING;
+       dws->cur_msg = NULL;
+       dws->cur_transfer = NULL;
+       dws->cur_chip = NULL;
+       dws->prev_chip = NULL;
+       spin_unlock_irqrestore(&dws->lock, flags);
+
+       queue_work(dws->workqueue, &dws->pump_messages);
+
+       return 0;
+}
+
+static int stop_queue(struct rk2818_spi *dws)
+{
+       unsigned long flags;
+       unsigned limit = 50;
+       int status = 0;
+
+       spin_lock_irqsave(&dws->lock, flags);
+       dws->run = QUEUE_STOPPED;
+       while (!list_empty(&dws->queue) && dws->busy && limit--) {
+               spin_unlock_irqrestore(&dws->lock, flags);
+               msleep(10);
+               spin_lock_irqsave(&dws->lock, flags);
+       }
+
+       if (!list_empty(&dws->queue) || dws->busy)
+               status = -EBUSY;
+       spin_unlock_irqrestore(&dws->lock, flags);
+
+       return status;
+}
+
+static int destroy_queue(struct rk2818_spi *dws)
+{
+       int status;
+
+       status = stop_queue(dws);
        if (status != 0)
                return status;
        destroy_workqueue(dws->workqueue);
@@ -1014,7 +1652,7 @@ static int __init rk2818_spim_probe(struct platform_device *pdev)
        struct rk2818_spi   *dws;
        struct spi_master   *master;
        int                     irq; 
-       int         ret;
+       int ret;
        struct rk2818_spi_platform_data *pdata = pdev->dev.platform_data;
 
        if (pdata && pdata->io_init) {
@@ -1054,8 +1692,13 @@ static int __init rk2818_spim_probe(struct platform_device *pdev)
        dws->prev_chip = NULL;
        dws->dma_inited = 1;  ///0;     
        ///dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60);
+       #ifndef QUICK_INT_TRANSFER
        ret = request_irq(dws->irq, rk2818_spi_irq, 0,
                        "rk2818_spim", dws);
+       #else
+       ret = request_irq(dws->irq, rk2818_spi_irq_handle, 0,
+                       "rk2818_spim", dws);
+       #endif
        if (ret < 0) {
                dev_err(&master->dev, "can not get IRQ\n");
                goto err_free_master;
@@ -1066,7 +1709,14 @@ static int __init rk2818_spim_probe(struct platform_device *pdev)
        master->dev.platform_data = pdata;
        master->cleanup = rk2818_spi_cleanup;
        master->setup = rk2818_spi_setup;
+       #if defined(QUICK_TRANSFER)
+       master->transfer = rk2818_spi_quick_transfer;
+       #elif defined(QUICK_INT_TRANSFER)
+       master->transfer = rk2818_spi_quick_int_transfer;
+       #else
        master->transfer = rk2818_spi_transfer;
+       #endif
+       
        dws->pdev = pdev;
        /* Basic HW init */
        spi_hw_init(dws);
@@ -1201,3 +1851,4 @@ module_exit(rk2818_spim_exit);
 MODULE_AUTHOR("lhh lhh@rock-chips.com");
 MODULE_DESCRIPTION("Rockchip RK2818 spim port driver");
 MODULE_LICENSE("GPL");;
+
index 66b86ffb64c86d299c7d8cd53847e6125014e92b..38bf6da57dfbb143d52f6c289775b74249710d5f 100755 (executable)
@@ -136,7 +136,7 @@ struct rk2818_spi {
        int                     (*write)(struct rk2818_spi *dws);
        int                     (*read)(struct rk2818_spi *dws);
        irqreturn_t             (*transfer_handler)(struct rk2818_spi *dws);
-       void (*cs_control)(struct rk2818_spi *dws, u32 cs);
+       void (*cs_control)(struct rk2818_spi *dws, u32 cs, u8 flag);
 
        /* Dma info */
        int                     dma_inited;
@@ -206,7 +206,7 @@ struct rk2818_spi_chip {
        u8 poll_mode;   /* 0 for contoller polling mode */
        u8 type;        /* SPI/SSP/Micrwire */
        u8 enable_dma;
-       void (*cs_control)(struct rk2818_spi *dws, u32 cs);
+       void (*cs_control)(struct rk2818_spi *dws, u32 cs, u8 flag);
 };
 
 #endif /* __DRIVERS_SPIM_RK2818_HEADER_H */
index 97b60b37f445dca6cad09959e5838b2206280149..662bc778bcfbb7476d91c5d9aa374716c4b02fa9 100644 (file)
@@ -430,6 +430,7 @@ struct spi_transfer {
        u8              bits_per_word;
        u16             delay_usecs;
        u32             speed_hz;
+       void                    *state;
 
        struct list_head transfer_list;
 };