Merge tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 21 Mar 2012 17:32:00 +0000 (10:32 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 21 Mar 2012 17:32:00 +0000 (10:32 -0700)
Pull SPI changes for v3.4 from Grant Likely:
 "Mostly a bunch of new drivers and driver bug fixes; but this also
  includes a few patches that create a core message queue infrastructure
  for the spi subsystem instead of making each driver open code it."

* tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6: (34 commits)
  spi/fsl-espi: Make sure pm is within 2..32
  spi/fsl-espi: make the clock computation easier to read
  spi: sh-hspi: modify write/read method
  spi: sh-hspi: control spi clock more correctly
  spi: sh-hspi: convert to using core message queue
  spi: s3c64xx: Fix build
  spi: s3c64xx: remove unnecessary callback msg->complete
  spi: remove redundant variable assignment
  spi: release lock on error path in spi_pump_messages()
  spi: Compatibility with direction which is used in samsung DMA operation
  spi-topcliff-pch: add recovery processing in case wait-event timeout
  spi-topcliff-pch: supports a spi mode setup and bit order setup by IO control
  spi-topcliff-pch: Fix issue for transmitting over 4KByte
  spi-topcliff-pch: Modify pci-bus number dynamically to get DMA device info
  spi/imx: simplify error handling to free gpios
  spi: Convert to DEFINE_PCI_DEVICE_TABLE
  spi: add Broadcom BCM63xx SPI controller driver
  SPI: add CSR SiRFprimaII SPI controller driver
  spi-topcliff-pch: fix -Wuninitialized warning
  spi: Mark spi_register_board_info() __devinit
  ...

1  2 
drivers/spi/Kconfig
drivers/spi/spi-pl022.c
drivers/spi/spi-topcliff-pch.c

diff --combined drivers/spi/Kconfig
index 8293658e7cf910d12942ff0581a7f50735256c92,3308c12785e6714dd2d2ee1bc8fab85dc013dfc2..0b06e360628a98f0e5e77c8ee163aa3cdf45bc38
@@@ -94,6 -94,12 +94,12 @@@ config SPI_AU155
          If you say yes to this option, support will be included for the
          PSC SPI controller found on Au1550, Au1200 and Au1300 series.
  
+ config SPI_BCM63XX
+       tristate "Broadcom BCM63xx SPI controller"
+       depends on BCM63XX
+       help
+           Enable support for the SPI controller on the Broadcom BCM63xx SoCs.
  config SPI_BITBANG
        tristate "Utilities for Bitbanging SPI masters"
        help
@@@ -126,7 -132,7 +132,7 @@@ config SPI_COLDFIRE_QSP
  
  config SPI_DAVINCI
        tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller"
-       depends on SPI_MASTER && ARCH_DAVINCI
+       depends on ARCH_DAVINCI
        select SPI_BITBANG
        help
          SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules.
@@@ -188,7 -194,7 +194,7 @@@ config SPI_MPC52xx_PS
  
  config SPI_MPC512x_PSC
        tristate "Freescale MPC512x PSC SPI controller"
-       depends on SPI_MASTER && PPC_MPC512x
+       depends on PPC_MPC512x
        help
          This enables using the Freescale MPC5121 Programmable Serial
          Controller in SPI master mode.
@@@ -238,7 -244,7 +244,7 @@@ config SPI_OMAP24X
  
  config SPI_OMAP_100K
        tristate "OMAP SPI 100K"
-       depends on SPI_MASTER && (ARCH_OMAP850 || ARCH_OMAP730)
+       depends on ARCH_OMAP850 || ARCH_OMAP730
        help
          OMAP SPI 100K master controller for omap7xx boards.
  
@@@ -262,7 -268,7 +268,7 @@@ config SPI_PL02
  
  config SPI_PPC4xx
        tristate "PPC4xx SPI Controller"
-       depends on PPC32 && 4xx && SPI_MASTER
+       depends on PPC32 && 4xx
        select SPI_BITBANG
        help
          This selects a driver for the PPC4xx SPI Controller.
@@@ -279,6 -285,12 +285,12 @@@ config SPI_PXA2X
  config SPI_PXA2XX_PCI
        def_bool SPI_PXA2XX && X86_32 && PCI
  
+ config SPI_RSPI
+       tristate "Renesas RSPI controller"
+       depends on SUPERH
+       help
+         SPI driver for Renesas RSPI blocks.
  config SPI_S3C24XX
        tristate "Samsung S3C24XX series SPI"
        depends on ARCH_S3C2410 && EXPERIMENTAL
@@@ -299,7 -311,7 +311,7 @@@ config SPI_S3C24XX_FI
  
  config SPI_S3C64XX
        tristate "Samsung S3C64XX series type SPI"
 -      depends on (ARCH_S3C64XX || ARCH_S5P64X0)
 +      depends on (ARCH_S3C64XX || ARCH_S5P64X0 || ARCH_EXYNOS)
        select S3C64XX_DMA if ARCH_S3C64XX
        help
          SPI driver for Samsung S3C64XX and newer SoCs.
@@@ -324,9 -336,22 +336,22 @@@ config SPI_SH_SC
        help
          SPI driver for SuperH SCI blocks.
  
+ config SPI_SH_HSPI
+       tristate "SuperH HSPI controller"
+       depends on ARCH_SHMOBILE
+       help
+         SPI driver for SuperH HSPI blocks.
+ config SPI_SIRF
+       tristate "CSR SiRFprimaII SPI controller"
+       depends on ARCH_PRIMA2
+       select SPI_BITBANG
+       help
+         SPI driver for CSR SiRFprimaII SoCs
  config SPI_STMP3XXX
        tristate "Freescale STMP37xx/378x SPI/SSP controller"
-       depends on ARCH_STMP3XXX && SPI_MASTER
+       depends on ARCH_STMP3XXX
        help
          SPI driver for Freescale STMP37xx/378x SoC SSP interface
  
@@@ -384,7 -409,6 +409,6 @@@ config SPI_NUC90
  
  config SPI_DESIGNWARE
        tristate "DesignWare SPI controller core support"
-       depends on SPI_MASTER
        help
          general driver for SPI controller core from DesignWare
  
diff --combined drivers/spi/spi-pl022.c
index f37ad2271ad53729ba857bb732b646ebe92333a7,ec17a7af7e282b366c02f0d899730992cf1e286c..dc8485d1e883adfa10fcded8710c2a8007ba991a
@@@ -29,7 -29,6 +29,6 @@@
  #include <linux/errno.h>
  #include <linux/interrupt.h>
  #include <linux/spi/spi.h>
- #include <linux/workqueue.h>
  #include <linux/delay.h>
  #include <linux/clk.h>
  #include <linux/err.h>
@@@ -330,12 -329,13 +329,13 @@@ struct vendor_data 
   * @clk: outgoing clock "SPICLK" for the SPI bus
   * @master: SPI framework hookup
   * @master_info: controller-specific data from machine setup
-  * @workqueue: a workqueue on which any spi_message request is queued
-  * @pump_messages: work struct for scheduling work to the workqueue
+  * @kworker: thread struct for message pump
+  * @kworker_task: pointer to task for message pump kworker thread
+  * @pump_messages: work struct for scheduling work to the message pump
   * @queue_lock: spinlock to syncronise access to message queue
   * @queue: message queue
-  * @busy: workqueue is busy
-  * @running: workqueue is running
+  * @busy: message pump is busy
+  * @running: message pump is running
   * @pump_transfers: Tasklet used in Interrupt Transfer mode
   * @cur_msg: Pointer to current spi_message being processed
   * @cur_transfer: Pointer to current spi_transfer
@@@ -365,14 -365,7 +365,7 @@@ struct pl022 
        struct clk                      *clk;
        struct spi_master               *master;
        struct pl022_ssp_controller     *master_info;
-       /* Driver message queue */
-       struct workqueue_struct         *workqueue;
-       struct work_struct              pump_messages;
-       spinlock_t                      queue_lock;
-       struct list_head                queue;
-       bool                            busy;
-       bool                            running;
-       /* Message transfer pump */
+       /* Message per-transfer pump */
        struct tasklet_struct           pump_transfers;
        struct spi_message              *cur_msg;
        struct spi_transfer             *cur_transfer;
        struct sg_table                 sgt_rx;
        struct sg_table                 sgt_tx;
        char                            *dummypage;
+       bool                            dma_running;
  #endif
  };
  
@@@ -448,8 -442,6 +442,6 @@@ static void null_cs_control(u32 command
  static void giveback(struct pl022 *pl022)
  {
        struct spi_transfer *last_transfer;
-       unsigned long flags;
-       struct spi_message *msg;
        pl022->next_msg_cs_active = false;
  
        last_transfer = list_entry(pl022->cur_msg->transfers.prev,
                 * sent the current message could be unloaded, which
                 * could invalidate the cs_control() callback...
                 */
                /* get a pointer to the next message, if any */
-               spin_lock_irqsave(&pl022->queue_lock, flags);
-               if (list_empty(&pl022->queue))
-                       next_msg = NULL;
-               else
-                       next_msg = list_entry(pl022->queue.next,
-                                       struct spi_message, queue);
-               spin_unlock_irqrestore(&pl022->queue_lock, flags);
+               next_msg = spi_get_next_queued_message(pl022->master);
  
                /*
                 * see if the next and current messages point
                        pl022->cur_chip->cs_control(SSP_CHIP_DESELECT);
                else
                        pl022->next_msg_cs_active = true;
        }
  
-       spin_lock_irqsave(&pl022->queue_lock, flags);
-       msg = pl022->cur_msg;
        pl022->cur_msg = NULL;
        pl022->cur_transfer = NULL;
        pl022->cur_chip = NULL;
-       queue_work(pl022->workqueue, &pl022->pump_messages);
-       spin_unlock_irqrestore(&pl022->queue_lock, flags);
-       msg->state = NULL;
-       if (msg->complete)
-               msg->complete(msg->context);
+       spi_finalize_current_message(pl022->master);
  }
  
  /**
@@@ -1063,6 -1042,7 +1042,7 @@@ static int configure_dma(struct pl022 *
        dmaengine_submit(txdesc);
        dma_async_issue_pending(rxchan);
        dma_async_issue_pending(txchan);
+       pl022->dma_running = true;
  
        return 0;
  
@@@ -1083,7 -1063,7 +1063,7 @@@ err_alloc_rx_sg
        return -ENOMEM;
  }
  
 -static int __init pl022_dma_probe(struct pl022 *pl022)
 +static int __devinit pl022_dma_probe(struct pl022 *pl022)
  {
        dma_cap_mask_t mask;
  
@@@ -1141,11 -1121,12 +1121,12 @@@ static void terminate_dma(struct pl022 
        dmaengine_terminate_all(rxchan);
        dmaengine_terminate_all(txchan);
        unmap_free_dma_scatter(pl022);
+       pl022->dma_running = false;
  }
  
  static void pl022_dma_remove(struct pl022 *pl022)
  {
-       if (pl022->busy)
+       if (pl022->dma_running)
                terminate_dma(pl022);
        if (pl022->dma_tx_channel)
                dma_release_channel(pl022->dma_tx_channel);
        return;
  }
  
- /**
-  * pump_messages - Workqueue function which processes spi message queue
-  * @data: pointer to private data of SSP driver
-  *
-  * This function checks if there is any spi message in the queue that
-  * needs processing and delegate control to appropriate function
-  * do_polling_transfer()/do_interrupt_dma_transfer()
-  * based on the kind of the transfer
-  *
-  */
- static void pump_messages(struct work_struct *work)
+ static int pl022_transfer_one_message(struct spi_master *master,
+                                     struct spi_message *msg)
  {
-       struct pl022 *pl022 =
-               container_of(work, struct pl022, pump_messages);
-       unsigned long flags;
-       bool was_busy = false;
-       /* Lock queue and check for queue work */
-       spin_lock_irqsave(&pl022->queue_lock, flags);
-       if (list_empty(&pl022->queue) || !pl022->running) {
-               if (pl022->busy) {
-                       /* nothing more to do - disable spi/ssp and power off */
-                       writew((readw(SSP_CR1(pl022->virtbase)) &
-                               (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
-                       if (pl022->master_info->autosuspend_delay > 0) {
-                               pm_runtime_mark_last_busy(&pl022->adev->dev);
-                               pm_runtime_put_autosuspend(&pl022->adev->dev);
-                       } else {
-                               pm_runtime_put(&pl022->adev->dev);
-                       }
-               }
-               pl022->busy = false;
-               spin_unlock_irqrestore(&pl022->queue_lock, flags);
-               return;
-       }
-       /* Make sure we are not already running a message */
-       if (pl022->cur_msg) {
-               spin_unlock_irqrestore(&pl022->queue_lock, flags);
-               return;
-       }
-       /* Extract head of queue */
-       pl022->cur_msg =
-           list_entry(pl022->queue.next, struct spi_message, queue);
-       list_del_init(&pl022->cur_msg->queue);
-       if (pl022->busy)
-               was_busy = true;
-       else
-               pl022->busy = true;
-       spin_unlock_irqrestore(&pl022->queue_lock, flags);
+       struct pl022 *pl022 = spi_master_get_devdata(master);
  
        /* Initial message state */
-       pl022->cur_msg->state = STATE_START;
-       pl022->cur_transfer = list_entry(pl022->cur_msg->transfers.next,
-                                           struct spi_transfer, transfer_list);
+       pl022->cur_msg = msg;
+       msg->state = STATE_START;
+       pl022->cur_transfer = list_entry(msg->transfers.next,
+                                        struct spi_transfer, transfer_list);
  
        /* Setup the SPI using the per chip configuration */
-       pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi);
-       if (!was_busy)
-               /*
-                * We enable the core voltage and clocks here, then the clocks
-                * and core will be disabled when this workqueue is run again
-                * and there is no more work to be done.
-                */
-               pm_runtime_get_sync(&pl022->adev->dev);
+       pl022->cur_chip = spi_get_ctldata(msg->spi);
  
        restore_state(pl022);
        flush(pl022);
                do_polling_transfer(pl022);
        else
                do_interrupt_dma_transfer(pl022);
- }
- static int __init init_queue(struct pl022 *pl022)
- {
-       INIT_LIST_HEAD(&pl022->queue);
-       spin_lock_init(&pl022->queue_lock);
-       pl022->running = false;
-       pl022->busy = false;
-       tasklet_init(&pl022->pump_transfers, pump_transfers,
-                       (unsigned long)pl022);
-       INIT_WORK(&pl022->pump_messages, pump_messages);
-       pl022->workqueue = create_singlethread_workqueue(
-                                       dev_name(pl022->master->dev.parent));
-       if (pl022->workqueue == NULL)
-               return -EBUSY;
  
        return 0;
  }
  
- static int start_queue(struct pl022 *pl022)
+ static int pl022_prepare_transfer_hardware(struct spi_master *master)
  {
-       unsigned long flags;
-       spin_lock_irqsave(&pl022->queue_lock, flags);
-       if (pl022->running || pl022->busy) {
-               spin_unlock_irqrestore(&pl022->queue_lock, flags);
-               return -EBUSY;
-       }
-       pl022->running = true;
-       pl022->cur_msg = NULL;
-       pl022->cur_transfer = NULL;
-       pl022->cur_chip = NULL;
-       pl022->next_msg_cs_active = false;
-       spin_unlock_irqrestore(&pl022->queue_lock, flags);
-       queue_work(pl022->workqueue, &pl022->pump_messages);
+       struct pl022 *pl022 = spi_master_get_devdata(master);
  
+       /*
+        * Just make sure we have all we need to run the transfer by syncing
+        * with the runtime PM framework.
+        */
+       pm_runtime_get_sync(&pl022->adev->dev);
        return 0;
  }
  
- static int stop_queue(struct pl022 *pl022)
+ static int pl022_unprepare_transfer_hardware(struct spi_master *master)
  {
-       unsigned long flags;
-       unsigned limit = 500;
-       int status = 0;
+       struct pl022 *pl022 = spi_master_get_devdata(master);
  
-       spin_lock_irqsave(&pl022->queue_lock, flags);
+       /* nothing more to do - disable spi/ssp and power off */
+       writew((readw(SSP_CR1(pl022->virtbase)) &
+               (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
  
-       /* This is a bit lame, but is optimized for the common execution path.
-        * A wait_queue on the pl022->busy could be used, but then the common
-        * execution path (pump_messages) would be required to call wake_up or
-        * friends on every SPI message. Do this instead */
-       while ((!list_empty(&pl022->queue) || pl022->busy) && limit--) {
-               spin_unlock_irqrestore(&pl022->queue_lock, flags);
-               msleep(10);
-               spin_lock_irqsave(&pl022->queue_lock, flags);
+       if (pl022->master_info->autosuspend_delay > 0) {
+               pm_runtime_mark_last_busy(&pl022->adev->dev);
+               pm_runtime_put_autosuspend(&pl022->adev->dev);
+       } else {
+               pm_runtime_put(&pl022->adev->dev);
        }
  
-       if (!list_empty(&pl022->queue) || pl022->busy)
-               status = -EBUSY;
-       else
-               pl022->running = false;
-       spin_unlock_irqrestore(&pl022->queue_lock, flags);
-       return status;
- }
- static int destroy_queue(struct pl022 *pl022)
- {
-       int status;
-       status = stop_queue(pl022);
-       /* we are unloading the module or failing to load (only two calls
-        * to this routine), and neither call can handle a return value.
-        * However, destroy_workqueue calls flush_workqueue, and that will
-        * block until all work is done.  If the reason that stop_queue
-        * timed out is that the work will never finish, then it does no
-        * good to call destroy_workqueue, so return anyway. */
-       if (status != 0)
-               return status;
-       destroy_workqueue(pl022->workqueue);
        return 0;
  }
  
@@@ -1776,38 -1646,6 +1646,6 @@@ static int verify_controller_parameters
        return 0;
  }
  
- /**
-  * pl022_transfer - transfer function registered to SPI master framework
-  * @spi: spi device which is requesting transfer
-  * @msg: spi message which is to handled is queued to driver queue
-  *
-  * This function is registered to the SPI framework for this SPI master
-  * controller. It will queue the spi_message in the queue of driver if
-  * the queue is not stopped and return.
-  */
- static int pl022_transfer(struct spi_device *spi, struct spi_message *msg)
- {
-       struct pl022 *pl022 = spi_master_get_devdata(spi->master);
-       unsigned long flags;
-       spin_lock_irqsave(&pl022->queue_lock, flags);
-       if (!pl022->running) {
-               spin_unlock_irqrestore(&pl022->queue_lock, flags);
-               return -ESHUTDOWN;
-       }
-       msg->actual_length = 0;
-       msg->status = -EINPROGRESS;
-       msg->state = STATE_START;
-       list_add_tail(&msg->queue, &pl022->queue);
-       if (pl022->running && !pl022->busy)
-               queue_work(pl022->workqueue, &pl022->pump_messages);
-       spin_unlock_irqrestore(&pl022->queue_lock, flags);
-       return 0;
- }
  static inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr)
  {
        return rate / (cpsdvsr * (1 + scr));
@@@ -2170,7 -2008,10 +2008,10 @@@ pl022_probe(struct amba_device *adev, c
        master->num_chipselect = platform_info->num_chipselect;
        master->cleanup = pl022_cleanup;
        master->setup = pl022_setup;
-       master->transfer = pl022_transfer;
+       master->prepare_transfer_hardware = pl022_prepare_transfer_hardware;
+       master->transfer_one_message = pl022_transfer_one_message;
+       master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
+       master->rt = platform_info->rt;
  
        /*
         * Supports mode 0-3, loopback, and active low CS. Transfers are
                goto err_no_clk_en;
        }
  
+       /* Initialize transfer pump */
+       tasklet_init(&pl022->pump_transfers, pump_transfers,
+                    (unsigned long)pl022);
        /* Disable SSP */
        writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
               SSP_CR1(pl022->virtbase));
                        platform_info->enable_dma = 0;
        }
  
-       /* Initialize and start queue */
-       status = init_queue(pl022);
-       if (status != 0) {
-               dev_err(&adev->dev, "probe - problem initializing queue\n");
-               goto err_init_queue;
-       }
-       status = start_queue(pl022);
-       if (status != 0) {
-               dev_err(&adev->dev, "probe - problem starting queue\n");
-               goto err_start_queue;
-       }
        /* Register with the SPI framework */
        amba_set_drvdata(adev, pl022);
        status = spi_register_master(master);
        return 0;
  
   err_spi_register:
-  err_start_queue:
-  err_init_queue:
-       destroy_queue(pl022);
        if (platform_info->enable_dma)
                pl022_dma_remove(pl022);
  
@@@ -2307,9 -2138,6 +2138,6 @@@ pl022_remove(struct amba_device *adev
         */
        pm_runtime_get_noresume(&adev->dev);
  
-       /* Remove the queue */
-       if (destroy_queue(pl022) != 0)
-               dev_err(&adev->dev, "queue remove failed\n");
        load_ssp_default_config(pl022);
        if (pl022->master_info->enable_dma)
                pl022_dma_remove(pl022);
  static int pl022_suspend(struct device *dev)
  {
        struct pl022 *pl022 = dev_get_drvdata(dev);
-       int status = 0;
+       int ret;
  
-       status = stop_queue(pl022);
-       if (status) {
-               dev_warn(dev, "suspend cannot stop queue\n");
-               return status;
+       ret = spi_master_suspend(pl022->master);
+       if (ret) {
+               dev_warn(dev, "cannot suspend master\n");
+               return ret;
        }
  
        dev_dbg(dev, "suspended\n");
  static int pl022_resume(struct device *dev)
  {
        struct pl022 *pl022 = dev_get_drvdata(dev);
-       int status = 0;
+       int ret;
  
        /* Start the queue running */
-       status = start_queue(pl022);
-       if (status)
-               dev_err(dev, "problem starting queue (%d)\n", status);
+       ret = spi_master_resume(pl022->master);
+       if (ret)
+               dev_err(dev, "problem starting queue (%d)\n", ret);
        else
                dev_dbg(dev, "resumed\n");
  
-       return status;
+       return ret;
  }
  #endif        /* CONFIG_PM */
  
index 10182eb500681719fc0f4db5e017c76d56f60370,c9e1fcc923bca826254de2e1dd55e8758ea11691..5c6fa5ed3366fef69b7cef2b8b49ce67a0620935
@@@ -196,6 -196,7 +196,7 @@@ struct pch_spi_data 
        struct pch_spi_dma_ctrl dma;
        int use_dma;
        u8 irq_reg_sts;
+       int save_total_len;
  };
  
  /**
@@@ -216,7 -217,7 +217,7 @@@ struct pch_pd_dev_save 
        struct pch_spi_board_data *board_dat;
  };
  
- static struct pci_device_id pch_spi_pcidev_id[] = {
+ static DEFINE_PCI_DEVICE_TABLE(pch_spi_pcidev_id) = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_GE_SPI),    1, },
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_SPI), 2, },
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_SPI), 1, },
@@@ -318,22 -319,23 +319,23 @@@ static void pch_spi_handler_sub(struct 
                data->tx_index = tx_index;
                data->rx_index = rx_index;
  
-       }
-       /* if transfer complete interrupt */
-       if (reg_spsr_val & SPSR_FI_BIT) {
-               if ((tx_index == bpw_len) && (rx_index == tx_index)) {
-                       /* disable interrupts */
-                       pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
-                       /* transfer is completed;
-                          inform pch_spi_process_messages */
-                       data->transfer_complete = true;
-                       data->transfer_active = false;
-                       wake_up(&data->wait);
-               } else {
-                       dev_err(&data->master->dev,
-                               "%s : Transfer is not completed", __func__);
+               /* if transfer complete interrupt */
+               if (reg_spsr_val & SPSR_FI_BIT) {
+                       if ((tx_index == bpw_len) && (rx_index == tx_index)) {
+                               /* disable interrupts */
+                               pch_spi_setclr_reg(data->master, PCH_SPCR, 0,
+                                                  PCH_ALL);
+                               /* transfer is completed;
+                                  inform pch_spi_process_messages */
+                               data->transfer_complete = true;
+                               data->transfer_active = false;
+                               wake_up(&data->wait);
+                       } else {
+                               dev_err(&data->master->dev,
+                                       "%s : Transfer is not completed",
+                                       __func__);
+                       }
                }
        }
  }
@@@ -822,11 -824,13 +824,13 @@@ static void pch_spi_copy_rx_data_for_dm
                rx_dma_buf = data->dma.rx_buf_virt;
                for (j = 0; j < data->bpw_len; j++)
                        *rx_buf++ = *rx_dma_buf++ & 0xFF;
+               data->cur_trans->rx_buf = rx_buf;
        } else {
                rx_sbuf = data->cur_trans->rx_buf;
                rx_dma_sbuf = data->dma.rx_buf_virt;
                for (j = 0; j < data->bpw_len; j++)
                        *rx_sbuf++ = *rx_dma_sbuf++;
+               data->cur_trans->rx_buf = rx_sbuf;
        }
  }
  
@@@ -852,6 -856,9 +856,9 @@@ static int pch_spi_start_transfer(struc
        rtn = wait_event_interruptible_timeout(data->wait,
                                               data->transfer_complete,
                                               msecs_to_jiffies(2 * HZ));
+       if (!rtn)
+               dev_err(&data->master->dev,
+                       "%s wait-event timeout\n", __func__);
  
        dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent,
                            DMA_FROM_DEVICE);
@@@ -923,7 -930,8 +930,8 @@@ static void pch_spi_request_dma(struct 
        dma_cap_set(DMA_SLAVE, mask);
  
        /* Get DMA's dev information */
-       dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(12, 0));
+       dma_dev = pci_get_bus_and_slot(data->board_dat->pdev->bus->number,
+                                      PCI_DEVFN(12, 0));
  
        /* Set Tx DMA */
        param = &dma->param_tx;
@@@ -987,6 -995,7 +995,7 @@@ static void pch_spi_handle_dma(struct p
        int i;
        int size;
        int rem;
+       int head;
        unsigned long flags;
        struct pch_spi_dma_ctrl *dma;
  
        }
        data->bpw_len = data->cur_trans->len / (*bpw / 8);
  
+       if (data->bpw_len > PCH_BUF_SIZE) {
+               data->bpw_len = PCH_BUF_SIZE;
+               data->cur_trans->len -= PCH_BUF_SIZE;
+       }
        /* copy Tx Data */
        if (data->cur_trans->tx_buf != NULL) {
                if (*bpw == 8) {
                                *tx_dma_sbuf++ = *tx_sbuf++;
                }
        }
+       /* Calculate Rx parameter for DMA transmitting */
        if (data->bpw_len > PCH_DMA_TRANS_SIZE) {
-               num = data->bpw_len / PCH_DMA_TRANS_SIZE + 1;
+               if (data->bpw_len % PCH_DMA_TRANS_SIZE) {
+                       num = data->bpw_len / PCH_DMA_TRANS_SIZE + 1;
+                       rem = data->bpw_len % PCH_DMA_TRANS_SIZE;
+               } else {
+                       num = data->bpw_len / PCH_DMA_TRANS_SIZE;
+                       rem = PCH_DMA_TRANS_SIZE;
+               }
                size = PCH_DMA_TRANS_SIZE;
-               rem = data->bpw_len % PCH_DMA_TRANS_SIZE;
        } else {
                num = 1;
                size = data->bpw_len;
        dma->nent = num;
        dma->desc_rx = desc_rx;
  
-       /* TX */
-       if (data->bpw_len > PCH_DMA_TRANS_SIZE) {
-               num = data->bpw_len / PCH_DMA_TRANS_SIZE;
+       /* Calculate Tx parameter for DMA transmitting */
+       if (data->bpw_len > PCH_MAX_FIFO_DEPTH) {
+               head = PCH_MAX_FIFO_DEPTH - PCH_DMA_TRANS_SIZE;
+               if (data->bpw_len % PCH_DMA_TRANS_SIZE > 4) {
+                       num = data->bpw_len / PCH_DMA_TRANS_SIZE + 1;
+                       rem = data->bpw_len % PCH_DMA_TRANS_SIZE - head;
+               } else {
+                       num = data->bpw_len / PCH_DMA_TRANS_SIZE;
+                       rem = data->bpw_len % PCH_DMA_TRANS_SIZE +
+                             PCH_DMA_TRANS_SIZE - head;
+               }
                size = PCH_DMA_TRANS_SIZE;
-               rem = 16;
        } else {
                num = 1;
                size = data->bpw_len;
                rem = data->bpw_len;
+               head = 0;
        }
  
        dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
        for (i = 0; i < num; i++, sg++) {
                if (i == 0) {
                        sg->offset = 0;
+                       sg_set_page(sg, virt_to_page(dma->tx_buf_virt), size + head,
+                                   sg->offset);
+                       sg_dma_len(sg) = size + head;
+               } else if (i == (num - 1)) {
+                       sg->offset = head + size * i;
+                       sg->offset = sg->offset * (*bpw / 8);
                        sg_set_page(sg, virt_to_page(dma->tx_buf_virt), rem,
                                    sg->offset);
                        sg_dma_len(sg) = rem;
                } else {
-                       sg->offset = rem + size * (i - 1);
+                       sg->offset = head + size * i;
                        sg->offset = sg->offset * (*bpw / 8);
                        sg_set_page(sg, virt_to_page(dma->tx_buf_virt), size,
                                    sg->offset);
@@@ -1202,6 -1237,7 +1237,7 @@@ static void pch_spi_process_messages(st
                                    data->current_msg->spi->bits_per_word);
        pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
        do {
+               int cnt;
                /* If we are already processing a message get the next
                transfer structure from the message otherwise retrieve
                the 1st transfer request from the message. */
                }
                spin_unlock(&data->lock);
  
+               if (!data->cur_trans->len)
+                       goto out;
+               cnt = (data->cur_trans->len - 1) / PCH_BUF_SIZE + 1;
+               data->save_total_len = data->cur_trans->len;
                if (data->use_dma) {
-                       pch_spi_handle_dma(data, &bpw);
-                       if (!pch_spi_start_transfer(data))
-                               goto out;
-                       pch_spi_copy_rx_data_for_dma(data, bpw);
+                       int i;
+                       char *save_rx_buf = data->cur_trans->rx_buf;
+                       for (i = 0; i < cnt; i ++) {
+                               pch_spi_handle_dma(data, &bpw);
+                               if (!pch_spi_start_transfer(data)) {
+                                       data->transfer_complete = true;
+                                       data->current_msg->status = -EIO;
+                                       data->current_msg->complete
+                                                  (data->current_msg->context);
+                                       data->bcurrent_msg_processing = false;
+                                       data->current_msg = NULL;
+                                       data->cur_trans = NULL;
+                                       goto out;
+                               }
+                               pch_spi_copy_rx_data_for_dma(data, bpw);
+                       }
+                       data->cur_trans->rx_buf = save_rx_buf;
                } else {
                        pch_spi_set_tx(data, &bpw);
                        pch_spi_set_ir(data);
                        data->pkt_tx_buff = NULL;
                }
                /* increment message count */
+               data->cur_trans->len = data->save_total_len;
                data->current_msg->actual_length += data->cur_trans->len;
  
                dev_dbg(&data->master->dev,
@@@ -1388,6 -1442,7 +1442,7 @@@ static int __devinit pch_spi_pd_probe(s
        master->num_chipselect = PCH_MAX_CS;
        master->setup = pch_spi_setup;
        master->transfer = pch_spi_transfer;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
  
        data->board_dat = board_dat;
        data->plat_dev = plat_dev;
@@@ -1720,7 -1775,7 +1775,7 @@@ static int pch_spi_resume(struct pci_de
  
  #endif
  
 -static struct pci_driver pch_spi_pcidev = {
 +static struct pci_driver pch_spi_pcidev_driver = {
        .name = "pch_spi",
        .id_table = pch_spi_pcidev_id,
        .probe = pch_spi_probe,
@@@ -1736,7 -1791,7 +1791,7 @@@ static int __init pch_spi_init(void
        if (ret)
                return ret;
  
 -      ret = pci_register_driver(&pch_spi_pcidev);
 +      ret = pci_register_driver(&pch_spi_pcidev_driver);
        if (ret)
                return ret;
  
@@@ -1746,7 -1801,7 +1801,7 @@@ module_init(pch_spi_init)
  
  static void __exit pch_spi_exit(void)
  {
 -      pci_unregister_driver(&pch_spi_pcidev);
 +      pci_unregister_driver(&pch_spi_pcidev_driver);
        platform_driver_unregister(&pch_spi_pd_driver);
  }
  module_exit(pch_spi_exit);