File linux-2.6.34-moorestown-spi-slave-controller-driver-1.1.patch of Package kernel

From f52838cd03de045aa67cc1a0c1614ea5bfb30fcc Mon Sep 17 00:00:00 2001
From: Alan Olsen <alan.r.olsen@intel.com>
Date: Wed, 11 Nov 2009 13:12:42 -0800
Subject: [PATCH 065/104] Moorestown SPI Slave Controller driver v1.1 consolidation patch

This patch contains the following patches:

Alpha2-1.0-1-1-mrst-SPI-Slave-Core-Driver-K29.patch

   [PATCH] SPI Slave Support Added to SPI Core Driver

   Signed-off-by: Pranav K. Sanghadia <pranav.k.sanghadia@intel.com>

Alpha2-1.0-1-1-mrst-SPI-Slave-controller-driver.patch

   [PATCH]     SPI slave controller driver for Moorestown platform

   This driver currently supports only programmed IO mode.

   Config settings are:

        CONFIG_SPI_MRST_SLAVE=y
        CONFIG_SPI_MRST_SLAVE_DMA is not set

   Signed-off-by: Ken Mills <ken.k.mills@intel.com>

Alpha2-1.0-1-1-DMA-Support-added-in-SPI-Slave-Controller-Driver.patch

   [PATCH] This patch adds DMA support for SPI Slave Controller Driver. DMA provides
   highspeed data transfer between SPI-SSP and external Master mode device

   Signed-off-by: Pranav K. Sanghadia <pranav.k.sanghadia@intel.com>

Alpha2-1.0-1-1-mrst-SPI-Slave-controller-fix-DMA-Issue.patch

   [PATCH] Alpha2-1.0-1-1-mrst-SPI-Slave-controller-fix-DMA-Issue.patch

[PATCH] Optimized SSP clock bitbang routine

Signed-off-by: Ken Mills <ken.k.mills@intel.com>

Signed-off-by: Alan Olsen <alan.r.olsen@intel.com>
---
 drivers/spi/Kconfig                |   11 +
 drivers/spi/Makefile               |    1 +
 drivers/spi/mrst_spi_slave.c       | 1227 ++++++++++++++++++++++++++++++++++++
 drivers/spi/spi.c                  |  403 +++++++++++-
 include/linux/spi/mrst_spi_slave.h |  143 +++++
 include/linux/spi/spi.h            |   98 +++-
 6 files changed, 1862 insertions(+), 21 deletions(-)
 create mode 100644 drivers/spi/mrst_spi_slave.c
 create mode 100644 include/linux/spi/mrst_spi_slave.h

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 9d4ff53..b94445b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -360,5 +360,16 @@ config SPI_TLE62X0
 endif # SPI_MASTER
 
 # (slave support would go here)
+config SPI_MRST_SLAVE
+          tristate "SPI slave controller driver for Intel Moorestown platform "
+          depends on SPI_MASTER
+          help
+            This is the SPI slave controller driver for Intel Moorestown platform
+
+config SPI_MRST_SLAVE_DMA
+          boolean "Enable DMA for MRST SPI Slave Controller"
+          depends on INTEL_LNW_DMAC1
+          help
+            This has to be enabled after Moorestown DMAC1 driver is enabled
 
 endif # SPI
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index c78cb77..8acdd96 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_SPI_TLE62X0)	+= tle62x0.o
 # 	... add above this line ...
 
 # SPI slave controller drivers (upstream link)
+obj-$(CONFIG_SPI_MRST_SLAVE)                  += mrst_spi_slave.o
 # 	... add above this line ...
 
 # SPI slave drivers (protocol for that link)
diff --git a/drivers/spi/mrst_spi_slave.c b/drivers/spi/mrst_spi_slave.c
new file mode 100644
index 0000000..82a50b7
--- /dev/null
+++ b/drivers/spi/mrst_spi_slave.c
@@ -0,0 +1,1227 @@
+/*
+ *  mrst_spi_slave.c - Moorestown SPI slave controller driver
+ *  based on pxa2xx_spi.c
+ *
+ *  Copyright (C) Intel 2009
+ *  Ken Mills <ken.k.mills@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+/*
+ * Note:
+ *
+ * Supports interrupt programmed I/O, DMA and non-interrupt polled transfers.
+ * 
+ */
+
+#include <linux/delay.h>
+#include <linux/highmem.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#ifdef CONFIG_SPI_MRST_SLAVE_DMA
+#include <linux/dma-mapping.h>
+#include <linux/lnw_dma.h>
+#endif
+
+#include <linux/spi/spi.h>
+#include <linux/spi/mrst_spi_slave.h>
+
+
+#define DRIVER_NAME "mrst_spi_slave"
+
+#define SSP_NOT_SYNC 0x400000
+
+MODULE_AUTHOR("");
+MODULE_DESCRIPTION("Moorestown SPI Slave Contoller");
+MODULE_LICENSE("GPL");
+
+/*
+ * For testing SSCR1 changes that require SSP restart, basically
+ * everything except the service and interrupt enables
+ */
+#define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_EBCEI | SSCR1_SCFR \
+                                              | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
+                                              | SSCR1_SFRMDIR \
+                                              | SSCR1_RWOT | SSCR1_TRAIL | SSCR1_PINTE \
+                                              | SSCR1_STRF | SSCR1_EFWR | SSCR1_RFT \
+                                              | SSCR1_TFT | SSCR1_SPH | SSCR1_SPO)
+
+#define DEFINE_SSP_REG(reg, off) \
+static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \
+static inline void write_##reg(u32 v, void *p) { __raw_writel(v, p + (off)); }
+
+DEFINE_SSP_REG(SSCR0, 0x00)
+DEFINE_SSP_REG(SSCR1, 0x04)
+DEFINE_SSP_REG(SSSR, 0x08)
+DEFINE_SSP_REG(SSITR, 0x0c)
+DEFINE_SSP_REG(SSDR, 0x10)
+DEFINE_SSP_REG(SSTO, 0x28)
+DEFINE_SSP_REG(SSPSP, 0x2c)
+
+DEFINE_SSP_REG(IPCCSR, 0x00);
+DEFINE_SSP_REG(IPCPISR, 0x08);
+DEFINE_SSP_REG(IPCPIMR, 0x10);
+
+DEFINE_SSP_REG(I2CCTRL, 0x00);
+DEFINE_SSP_REG(I2CDATA, 0x04);
+
+DEFINE_SSP_REG(GPLR1, 0x04);
+DEFINE_SSP_REG(GPDR1, 0x0c);
+DEFINE_SSP_REG(GPSR1, 0x14);
+DEFINE_SSP_REG(GPCR1, 0x1C);
+DEFINE_SSP_REG(GAFR1_U, 0x44);
+
+#define START_STATE ((void *)0)
+#define RUNNING_STATE ((void *)1)
+#define DONE_STATE ((void *)2)
+#define ERROR_STATE ((void *)-1)
+
+struct driver_data {
+          /* Driver model hookup */
+          struct pci_dev *pdev;
+
+          /* SPI framework hookup */
+          struct spi_slave *slave;
+
+          /* SSP register addresses */
+          void *paddr;
+          void *ioaddr;
+          u32 iolen;
+          int irq;
+
+          /* IPC registers */
+          void *IPC_paddr;
+          void *IPC_ioaddr;
+
+          /* I2C registers */
+          void *I2C_paddr;
+          void *I2C_ioaddr;
+
+          /* SSP masks*/
+          u32 dma_cr1;
+          u32 int_cr1;
+          u32 clear_sr;
+          u32 mask_sr;
+
+          struct tasklet_struct poll_transfer;
+
+          spinlock_t lock;
+          int busy;
+          int run;
+
+          /* Current message transfer state info */
+          struct spi_message *cur_msg;
+          size_t len;
+          void *tx;
+          void *tx_end;
+          void *rx;
+          void *rx_end;
+          int dma_mapped;
+          dma_addr_t rx_dma;
+          dma_addr_t tx_dma;
+          size_t rx_map_len;
+          size_t tx_map_len;
+          u8 n_bytes;
+          int (*write)(struct driver_data *drv_data);
+          int (*read)(struct driver_data *drv_data);
+          irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
+          void (*cs_control)(u32 command);
+
+#ifdef CONFIG_SPI_MRST_SLAVE_DMA
+          struct lnw_dma_slave    dmas_tx;
+          struct lnw_dma_slave    dmas_rx;
+          struct dma_chan                        *txchan;
+          struct dma_chan                        *rxchan;
+
+          int txdma_done;
+          int rxdma_done;
+       u64 tx_param;
+       u64 rx_param;
+       struct pci_dev *dmac1;
+#endif
+};
+
+struct chip_data {
+          u32 cr0;
+          u32 cr1;
+          u32 psp;
+          u32 timeout;
+          u8 n_bytes;
+          u32 threshold;
+          u8 enable_dma;
+          u8 poll_mode;               /* 1 means use poll mode */
+          u8 bits_per_word;
+          int (*write)(struct driver_data *drv_data);
+          int (*read)(struct driver_data *drv_data);
+};
+
+static void flush(struct driver_data *drv_data)
+{
+          void *reg = drv_data->ioaddr;
+          u32 sssr;
+
+          /* If the transmit fifo is not empty, reset the interface. */
+          sssr = read_SSSR(reg);
+          if ((sssr & 0xf00) || (sssr & SSSR_TNF) == 0) {
+                      write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+                      return;
+          }
+
+          while (read_SSSR(reg) & SSSR_RNE)
+                      read_SSDR(reg);
+
+          write_SSSR(SSSR_ROR, reg);
+          write_SSSR(SSSR_TUR, reg);
+
+          return;
+}
+
+static int null_writer(struct driver_data *drv_data)
+{
+          void *reg = drv_data->ioaddr;
+          u8 n_bytes = drv_data->n_bytes;
+
+          if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+                      || (drv_data->tx == drv_data->tx_end))
+                      return 0;
+
+          write_SSDR(0, reg);
+          drv_data->tx += n_bytes;
+
+          return 1;
+}
+
+static int null_reader(struct driver_data *drv_data)
+{
+          void *reg = drv_data->ioaddr;
+          u8 n_bytes = drv_data->n_bytes;
+
+          while ((read_SSSR(reg) & SSSR_RNE)
+                      && (drv_data->rx < drv_data->rx_end)) {
+                      read_SSDR(reg);
+                      drv_data->rx += n_bytes;
+          }
+
+          return drv_data->rx == drv_data->rx_end;
+}
+
+static int u8_writer(struct driver_data *drv_data)
+{
+          void *reg = drv_data->ioaddr;
+          if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+                      || (drv_data->tx == drv_data->tx_end))
+                      return 0;
+
+          write_SSDR(*(u8 *)(drv_data->tx), reg);
+          ++drv_data->tx;
+
+          return 1;
+}
+
+static int u8_reader(struct driver_data *drv_data)
+{
+          void *reg = drv_data->ioaddr;
+          while ((read_SSSR(reg) & SSSR_RNE)
+                      && (drv_data->rx < drv_data->rx_end)) {
+                      *(u8 *)(drv_data->rx) = read_SSDR(reg);
+                      ++drv_data->rx;
+          }
+
+          return drv_data->rx == drv_data->rx_end;
+}
+
+static int u16_writer(struct driver_data *drv_data)
+{
+          void *reg = drv_data->ioaddr;
+          if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+                      || (drv_data->tx == drv_data->tx_end))
+                      return 0;
+
+          write_SSDR(*(u16 *)(drv_data->tx), reg);
+          drv_data->tx += 2;
+
+          return 1;
+}
+
+static int u16_reader(struct driver_data *drv_data)
+{
+          void *reg = drv_data->ioaddr;
+          while ((read_SSSR(reg) & SSSR_RNE)
+                      && (drv_data->rx < drv_data->rx_end)) {
+                      *(u16 *)(drv_data->rx) = read_SSDR(reg);
+                      drv_data->rx += 2;
+          }
+
+          return drv_data->rx == drv_data->rx_end;
+}
+
+static int u32_writer(struct driver_data *drv_data)
+{
+          void *reg = drv_data->ioaddr;
+          if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+                      || (drv_data->tx == drv_data->tx_end))
+                      return 0;
+
+          write_SSDR(*(u32 *)(drv_data->tx), reg);
+          drv_data->tx += 4;
+
+          return 1;
+}
+
+static int u32_reader(struct driver_data *drv_data)
+{
+          void *reg = drv_data->ioaddr;
+          while ((read_SSSR(reg) & SSSR_RNE)
+                      && (drv_data->rx < drv_data->rx_end)) {
+                      *(u32 *)(drv_data->rx) = read_SSDR(reg);
+                      drv_data->rx += 4;
+          }
+
+          return drv_data->rx == drv_data->rx_end;
+}
+
+
+
+/* caller already set message->status; dma and pio irqs are blocked */
+static void giveback(struct driver_data *drv_data)
+{
+          struct spi_message *msg;
+
+          msg = drv_data->cur_msg;
+          msg->state = NULL;
+          if (msg->complete)
+                      msg->complete(msg->context);
+}
+
+#ifdef CONFIG_SPI_MRST_SLAVE_DMA
+
+static bool chan_filter(struct dma_chan *chan, void *param)
+{
+          struct driver_data *drv_data = (struct driver_data *)param;
+          bool ret = false;
+
+          if (!drv_data->dmac1)
+                      return ret;
+
+          if (chan->device->dev == &drv_data->dmac1->dev)
+                      ret = true;
+
+          return ret;
+}
+
+static void int_transfer_complete(struct driver_data *drv_data);
+
+static void mrst_spi_dma_done(void *arg)
+{
+          u64 *param = arg;
+          struct driver_data *drv_data;
+       int *done;
+
+          drv_data = (struct driver_data *)(u32)(*param >> 32);
+       done = (int *)(u32)(*param & 0xffffffff);
+       *done = 1;
+
+       if (!drv_data->txdma_done || !drv_data->rxdma_done) 
+               return;
+       int_transfer_complete(drv_data);
+}
+
+static void mrst_spi_dma_init(struct driver_data *drv_data)
+{
+          struct lnw_dma_slave *rxs, *txs;
+          dma_cap_mask_t mask;
+
+       /* Use DMAC1 */
+       drv_data->dmac1 = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0814, NULL);
+       if (!drv_data->dmac1) {
+               printk(KERN_WARNING "SPI Slave:Can't find DMAC1\n");
+               return;
+       }
+
+          /* 1. init rx channel */
+          rxs = &drv_data->dmas_rx;
+
+          rxs->dirn = DMA_FROM_DEVICE;
+       rxs->hs_mode = LNW_DMA_HW_HS;
+          rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
+          rxs->src_width = LNW_DMA_WIDTH_16BIT;
+       rxs->dst_width = LNW_DMA_WIDTH_32BIT;
+       rxs->src_msize = LNW_DMA_MSIZE_8;
+       rxs->dst_msize = LNW_DMA_MSIZE_8;
+
+
+          dma_cap_zero(mask);
+          dma_cap_set(DMA_MEMCPY, mask);
+          dma_cap_set(DMA_SLAVE, mask);
+
+       drv_data->rxchan = dma_request_channel(mask, chan_filter, drv_data);
+       if (!drv_data->rxchan)
+               goto err_exit;
+
+          drv_data->rxchan->private = rxs;
+
+          /* 2. init tx channel */
+          txs = &drv_data->dmas_tx;
+
+          txs->dirn = DMA_TO_DEVICE;
+       txs->hs_mode = LNW_DMA_HW_HS;
+          txs->cfg_mode = LNW_DMA_MEM_TO_PER;
+       txs->src_width = LNW_DMA_WIDTH_32BIT;
+          txs->dst_width = LNW_DMA_WIDTH_16BIT;
+       txs->src_msize = LNW_DMA_MSIZE_8;
+       txs->dst_msize = LNW_DMA_MSIZE_8;
+
+
+          dma_cap_set(DMA_SLAVE, mask);
+          dma_cap_set(DMA_MEMCPY, mask);
+
+       drv_data->txchan = dma_request_channel(mask, chan_filter, drv_data);
+       if (!drv_data->txchan)
+               goto free_rxchan;
+       else
+
+          drv_data->txchan->private = txs;
+
+          /* set the dma done bit to 1 */
+          drv_data->txdma_done = 1;
+          drv_data->rxdma_done = 1;
+
+       drv_data->tx_param = ((u64)(u32)drv_data << 32)
+                               | (u32)(&drv_data->txdma_done);
+       drv_data->rx_param = ((u64)(u32)drv_data << 32)
+                               | (u32)(&drv_data->rxdma_done);
+          return;
+
+free_rxchan:
+       printk(KERN_ERR "SPI-Slave Error : DMA Channle Not available\n");
+          dma_release_channel(drv_data->rxchan);
+err_exit:
+       printk(KERN_ERR "SPI-Slave Error : DMA Channel Not available\n");
+       pci_dev_put(drv_data->dmac1);
+          return;
+}
+
+static void mrst_spi_dma_exit(struct driver_data *drv_data)
+{
+          dma_release_channel(drv_data->txchan);
+          dma_release_channel(drv_data->rxchan);
+       pci_dev_put(drv_data->dmac1);
+}
+
+static void dma_transfer(struct driver_data *drv_data)
+{
+       dma_addr_t ssdr_addr;
+          struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL;
+          struct dma_chan *txchan, *rxchan;
+          enum dma_ctrl_flags flag;
+
+       /* get Data Read/Write address */
+       ssdr_addr = (dma_addr_t)(u32)(drv_data->paddr + 0x10);
+
+          if (drv_data->tx_dma)
+                      drv_data->txdma_done = 0;
+
+          if (drv_data->rx_dma)
+                      drv_data->rxdma_done = 0;
+
+          /* 2. start the TX dma transfer */
+          txchan = drv_data->txchan;
+          rxchan = drv_data->rxchan;
+
+          flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+
+       if (drv_data->rx_dma) {
+               rxdesc = rxchan->device->device_prep_dma_memcpy
+                               (rxchan,                /* DMA Channel */
+                               drv_data->rx_dma,       /* DAR */
+                               ssdr_addr,              /* SAR */
+                               drv_data->len,  /* Data Length */
+                               flag);          /* Flag */
+
+               rxdesc->callback = mrst_spi_dma_done;
+               rxdesc->callback_param = &drv_data->rx_param;
+          }
+
+          /* 3. start the RX dma transfer */
+       if (drv_data->tx_dma) {
+               txdesc = txchan->device->device_prep_dma_memcpy
+                               (txchan,                /* DMA Channel */
+                               ssdr_addr,              /* DAR */
+                               drv_data->tx_dma,       /* SAR */
+                               drv_data->len,  /* Data Length */
+                               flag);          /* Flag */
+
+               txdesc->callback = mrst_spi_dma_done;
+               txdesc->callback_param = &drv_data->tx_param;
+          }
+
+          if (rxdesc)
+                      rxdesc->tx_submit(rxdesc);
+          if (txdesc)
+                      txdesc->tx_submit(txdesc);
+
+}
+
+static int map_dma_buffers(struct driver_data *drv_data)
+{
+	drv_data->rx_dma = (dma_addr_t) virt_to_phys(drv_data->rx);
+	drv_data->tx_dma = (dma_addr_t) virt_to_phys(drv_data->tx);
+	return 1;
+}
+#endif
+
+static void int_error_stop(struct driver_data *drv_data, const char* msg)
+{
+          void *reg = drv_data->ioaddr;
+
+          /* Stop and reset SSP */
+          write_SSSR(drv_data->clear_sr, reg);
+          write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
+          write_SSTO(0, reg);
+          flush(drv_data);
+
+          dev_err(&drv_data->pdev->dev, "%s\n", msg);
+
+          drv_data->cur_msg->state = ERROR_STATE;
+}
+
+static void int_transfer_complete(struct driver_data *drv_data)
+{
+          void *reg = drv_data->ioaddr;
+
+	/* Clear Status Register */
+          write_SSSR(drv_data->clear_sr, reg);
+
+#ifdef CONFIG_SPI_MRST_SLAVE_DMA
+	/* Disable Triggers to DMA */
+          write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+#else
+	/* Disable Interrupt */
+          write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
+#endif
+	/* Stop getting Time Outs */
+          write_SSTO(0, reg);
+
+          /* Update total byte transfered return count actual bytes read */
+          drv_data->cur_msg->actual_length += drv_data->len -
+                                              (drv_data->rx_end - drv_data->rx);
+
+          drv_data->cur_msg->status = 0;
+          giveback(drv_data);
+}
+
+static void transfer_complete(struct driver_data *drv_data)
+{
+          /* Update total byte transfered return count actual bytes read */
+          drv_data->cur_msg->actual_length +=
+                      drv_data->len - (drv_data->rx_end - drv_data->rx);
+
+          drv_data->cur_msg->status = 0;
+          giveback(drv_data);
+}
+
+static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
+{
+          void *reg = drv_data->ioaddr;
+          u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ?
+                                  drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
+
+          u32 irq_status = read_SSSR(reg) & irq_mask;
+          if (irq_status & SSSR_ROR) {
+                      int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
+                      return IRQ_HANDLED;
+          }
+
+          if (irq_status & SSSR_TINT) {
+                      write_SSSR(SSSR_TINT, reg);
+                      if (drv_data->read(drv_data)) {
+                                  int_transfer_complete(drv_data);
+                                  return IRQ_HANDLED;
+                      }
+          }
+
+          /* Drain rx fifo, Fill tx fifo and prevent overruns */
+          do {
+                      if (drv_data->read(drv_data)) {
+                                  int_transfer_complete(drv_data);
+                                  return IRQ_HANDLED;
+                      }
+          } while (drv_data->write(drv_data));
+
+          if (drv_data->read(drv_data)) {
+                      int_transfer_complete(drv_data);
+                      return IRQ_HANDLED;
+          }
+
+          if (drv_data->tx == drv_data->tx_end)
+                      write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
+
+          return IRQ_HANDLED;
+}
+
+static irqreturn_t ssp_int(int irq, void *dev_id)
+{
+          struct driver_data *drv_data = dev_id;
+          void *reg = drv_data->ioaddr;
+	u32 status = read_SSSR(reg);
+
+ #ifdef CONFIG_SPI_MRST_SLAVE_DMA
+ 	if (status & SSSR_ROR || status & SSSR_TUR) {
+		printk(KERN_DEBUG "--- SPI ROR or TUR Occred : SSSR=%x\n", status);
+		write_SSSR(SSSR_ROR, reg);		/* Clear ROR */
+		write_SSSR(SSSR_TUR, reg);		/* Clear TUR */
+ 	 	return IRQ_HANDLED;
+	}
+               return IRQ_NONE;
+ #endif
+          /* just return if this is not our interrupt */
+          if (!(read_SSSR(reg) & drv_data->mask_sr))
+                      return IRQ_NONE;
+
+          if (!drv_data->cur_msg) {
+                      write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+                      write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
+                      write_SSSR(drv_data->clear_sr, reg);
+
+                      /* Never fail */
+                      return IRQ_HANDLED;
+          }
+          return drv_data->transfer_handler(drv_data);
+}
+
+static void poll_transfer(unsigned long data)
+{
+          struct driver_data *drv_data = (struct driver_data *)data;
+
+          if (drv_data->tx)
+                      while (drv_data->tx != drv_data->tx_end) {
+                                  drv_data->write(drv_data);
+                                  drv_data->read(drv_data);
+          }
+
+          while (!drv_data->read(drv_data))
+                      ;
+
+          transfer_complete(drv_data);
+}
+
+static int transfer(struct spi_device *spi, struct spi_message *msg)
+{
+          struct driver_data *drv_data = \
+                                  spi_slave_get_devdata(spi->slave);
+          unsigned long flags;
+          struct chip_data *chip = NULL;
+          struct spi_transfer *transfer = NULL;
+          void *reg = drv_data->ioaddr;
+          void *i2cReg = drv_data->I2C_ioaddr;
+          u32 clk_div = 0;
+          u8 bits = 0;
+          u32 cr0;
+          u32 cr1;
+          u32 sssr;
+
+          spin_lock_irqsave(&drv_data->lock, flags);
+          msg->actual_length = 0;
+          msg->status = -EINPROGRESS;
+          drv_data->cur_msg = msg;
+          /* Initial message state*/
+          msg->state = START_STATE;
+
+          /* We handle only one transfer message since the protocol module has to
+             control the out of band signaling. */
+          transfer = list_entry(msg->transfers.next,
+                                                                      struct spi_transfer,
+                                                                      transfer_list);
+
+          chip = spi_get_ctldata(msg->spi);
+
+          drv_data->busy = 1;
+
+          /* Check transfer length */
+          if (transfer->len > 8192) {
+                      dev_warn(&drv_data->pdev->dev, "SPI-SLAVE: transfer "
+                                              "length greater than 8192\n");
+                      msg->status = -EINVAL;
+                      giveback(drv_data);
+                      spin_unlock_irqrestore(&drv_data->lock, flags);
+                      return 0;
+          }
+
+          /* Setup the transfer state based on the type of transfer */
+          flush(drv_data);
+          drv_data->n_bytes = chip->n_bytes;
+          drv_data->tx = (void *)transfer->tx_buf;
+          drv_data->tx_end = drv_data->tx + transfer->len;
+          drv_data->rx = transfer->rx_buf;
+          drv_data->rx_end = drv_data->rx + transfer->len;
+          drv_data->rx_dma = transfer->rx_dma;
+          drv_data->tx_dma = transfer->tx_dma;
+          drv_data->len = transfer->len;
+          drv_data->write = drv_data->tx ? chip->write : null_writer;
+          drv_data->read = drv_data->rx ? chip->read : null_reader;
+
+          /* Change speed and bit per word on a per transfer */
+          cr0 = chip->cr0;
+          if (transfer->bits_per_word) {
+
+                      bits = chip->bits_per_word;
+
+                      clk_div = 0x0;
+
+                      if (transfer->bits_per_word)
+                                  bits = transfer->bits_per_word;
+
+
+                      if (bits <= 8) {
+                                  drv_data->n_bytes = 1;
+                                  drv_data->read = drv_data->read != null_reader ?
+                                                                      u8_reader : null_reader;
+                                  drv_data->write = drv_data->write != null_writer ?
+                                                                      u8_writer : null_writer;
+                      } else if (bits <= 16) {
+                                  drv_data->n_bytes = 2;
+                                  drv_data->read = drv_data->read != null_reader ?
+                                                                      u16_reader : null_reader;
+                                  drv_data->write = drv_data->write != null_writer ?
+                                                                      u16_writer : null_writer;
+                      } else if (bits <= 32) {
+                                  drv_data->n_bytes = 4;
+                                  drv_data->read = drv_data->read != null_reader ?
+                                                                      u32_reader : null_reader;
+                                  drv_data->write = drv_data->write != null_writer ?
+                                                                      u32_writer : null_writer;
+                      }
+
+                      cr0 = clk_div
+                                  | SSCR0_Motorola
+                                  | SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
+                                  | SSCR0_SSE
+                                  | SSCR0_TIM
+                                  | SSCR0_RIM
+                                  | (bits > 16 ? SSCR0_EDSS : 0);
+          }
+
+
+#ifdef CONFIG_SPI_MRST_SLAVE_DMA
+	drv_data->dma_mapped = 0;
+	if (chip->enable_dma)
+		drv_data->dma_mapped = map_dma_buffers(drv_data);
+#endif
+
+          msg->state = RUNNING_STATE;
+                      /* Ensure we have the correct interrupt handler    */
+          drv_data->transfer_handler = interrupt_transfer;
+                      /* Clear status  */
+          cr1 = chip->cr1 | chip->threshold;
+          write_SSSR(drv_data->clear_sr, reg);
+
+	/* Reload the config and do bitbanging only if SSP not-enable or not-synchronized */
+	if( ( read_SSSR(reg) & SSP_NOT_SYNC )  || (!(read_SSCR0(reg) & SSCR0_SSE) ) ) {
+
+	              write_SSSR(drv_data->clear_sr, reg);	/* clear status */
+                      write_SSCR0(cr0 & ~SSCR0_SSE, reg);
+                      write_SSPSP(0x02010007, reg);
+                      write_SSTO(chip->timeout, reg);
+                      write_SSCR1(0x13001DC0, reg);		/* TBD remove hardcoded value */
+                      write_SSCR0(cr0, reg);
+
+                      /*
+                      *  This routine uses the DFx block to override the SSP inputs
+                      *  and outputs allowing us to bit bang SSPSCLK. On Langwell,
+                      *  we have to generate the clock to clear busy.
+                      */
+
+                      write_I2CDATA(0x3, i2cReg);
+                      udelay(10);
+                      write_I2CCTRL(0x01070034, i2cReg);
+                      udelay(10);
+                      write_I2CDATA(0x00000099, i2cReg);
+                      udelay(10);
+                      write_I2CCTRL(0x01070038, i2cReg);
+                      udelay(10);
+                      sssr = read_SSSR(reg);
+
+                      /* Bit bang the clock until CSS clears */
+                      while (sssr & 0x400000) {
+                                  write_I2CDATA(0x2, i2cReg);
+                                  udelay(10);
+                                  write_I2CCTRL(0x01070034, i2cReg);
+                                  udelay(10);
+                                  write_I2CDATA(0x3, i2cReg);
+                                  udelay(10);
+                                  write_I2CCTRL(0x01070034, i2cReg);
+                                  udelay(10);
+                                  sssr = read_SSSR(reg);
+                      }
+
+                      write_I2CDATA(0x0, i2cReg);
+                      udelay(10);
+                      write_I2CCTRL(0x01070038, i2cReg);
+
+          } else {
+                      write_SSTO(chip->timeout, reg);
+                      write_SSCR1(0x13001DC0, reg);	/* TBD: remove hardcoded value */
+          }
+
+          /* transfer using DMA */
+          if (drv_data->dma_mapped) {
+#ifdef CONFIG_SPI_MRST_SLAVE_DMA
+	cr1 = cr1 | drv_data->dma_cr1;
+	write_SSCR1(0x13701DC0, reg);	/* TBD: remove hardcoded value */
+	dma_transfer(drv_data);
+#endif
+          }
+
+          /* transfer using non interrupt polling */
+          else if (chip->poll_mode)
+                      tasklet_schedule(&drv_data->poll_transfer);
+
+          /* transfer using interrupt driven programmed I/O */
+          else {
+                      cr1 = cr1 | drv_data->int_cr1;
+                      write_SSCR1(cr1, reg);
+          }
+
+          spin_unlock_irqrestore(&drv_data->lock, flags);
+          return 0;
+}
+
+static int setup(struct spi_device *spi)
+{
+          struct mrst_spi_chip *chip_info = NULL;
+          struct chip_data *chip;
+
+          if (!spi->bits_per_word)
+                      spi->bits_per_word = 8;
+
+          if ((spi->bits_per_word < 4 || spi->bits_per_word > 32))
+                      return -EINVAL;
+
+          /* Only alloc on first setup */
+          chip = spi_get_ctldata(spi);
+          if (!chip) {
+                      chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+                      if (!chip) {
+                                  dev_err(&spi->dev,
+                                              "failed setup: can't allocate chip data\n");
+                                  return -ENOMEM;
+                      }
+
+			chip->enable_dma = 1;
+			chip->poll_mode = 1;
+			chip->timeout = 1000;
+			chip->threshold = SSCR1_RxTresh(1) | SSCR1_TxTresh(1);
+          }
+
+          /*
+          *  protocol drivers may change the chip settings, so...
+          * if chip_info exists, use it
+          */
+          chip_info = spi->controller_data;
+
+          /* chip_info isn't always needed */
+          chip->cr1 = 0;
+          if (chip_info) {
+
+                      chip->timeout = chip_info->timeout;
+
+                      chip->threshold = (SSCR1_RxTresh(chip_info->rx_threshold) &
+                                                                                              SSCR1_RFT) |
+                                              (SSCR1_TxTresh(chip_info->tx_threshold) &
+                                                                                              SSCR1_TFT);
+
+
+                      if (chip_info->enable_loopback)
+                                  chip->cr1 = SSCR1_LBM;
+          }
+
+          chip->cr0 =       SSCR0_Motorola
+                                  | SSCR0_DataSize(spi->bits_per_word > 16 ?
+                                              spi->bits_per_word - 16 : spi->bits_per_word)
+                                  | SSCR0_SSE
+                                  | SSCR0_TIM
+                                  | SSCR0_RIM
+                                  | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0);
+          chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH);
+          chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
+                                  | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
+          /* set slave mode */
+          chip->cr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
+          chip->cr1 |= SSCR1_SCFR;       /* slave clock is not free running */
+          dev_dbg(&spi->dev, "%d bits/word, mode %d\n",
+                                  spi->bits_per_word,
+                                  spi->mode & 0x3);
+
+          if (spi->bits_per_word <= 8) {
+                      chip->n_bytes = 1;
+                      chip->read = u8_reader;
+                      chip->write = u8_writer;
+          } else if (spi->bits_per_word <= 16) {
+                      chip->n_bytes = 2;
+                      chip->read = u16_reader;
+                      chip->write = u16_writer;
+          } else if (spi->bits_per_word <= 32) {
+                      chip->cr0 |= SSCR0_EDSS;
+                      chip->n_bytes = 4;
+                      chip->read = u32_reader;
+                      chip->write = u32_writer;
+          } else {
+                      dev_err(&spi->dev, "invalid wordsize\n");
+                      return -ENODEV;
+          }
+          chip->bits_per_word = spi->bits_per_word;
+          spi_set_ctldata(spi, chip);
+
+          return 0;
+}
+
+static void cleanup(struct spi_device *spi)
+{
+          struct chip_data *chip = spi_get_ctldata(spi);
+
+          kfree(chip);
+}
+
+static struct mrst_spi_chip spidev_chip_info = {
+          .tx_threshold = 8, /* SSP hardware FIFO threshold */
+          .rx_threshold = 8, /* SSP hardware FIFO threshold */
+          .timeout = 235, 	/* See Intel documentation */
+};
+
+/*
+ * mrst_parse_spi_dib - mrst-ssp parse the spi device info block
+ *        table
+ * @pdev: spi controller pci device structure
+ * @drv_data: spi controller driver data
+ * Context: can sleep
+ *
+ * ssp controller needs to parse the spi device info block table
+ * saved in PCI bar 1 and register them with the spi core subsystem.
+ */
+static void mrst_parse_spi_dib(struct pci_dev *pdev,
+                                                                      struct driver_data *drv_data)
+{
+          u32 dib_len;
+          void *dib_vaddr;
+          unsigned long dib_paddr;
+          struct spi_board_info info[1];
+          struct spi_dib_header *header;
+          struct spi_dib *dib;
+          int info_num, i, j, dib_bar;
+          u16  *pval;
+
+          dib_bar = 1;
+          dib_paddr = pci_resource_start(pdev, dib_bar);
+          dib_len = pci_resource_len(pdev, dib_bar);
+
+          printk(KERN_INFO "SPI-Slave: %s() - paddr = 0x%08lx, "
+                                  "iolen = 0x%x\n", __func__, dib_paddr, dib_len);
+
+          dib_vaddr = ioremap(dib_paddr, dib_len);
+          if (!dib_vaddr) {
+                      dev_err(&pdev->dev, "%s(): ioremap failed\n", __func__);
+                      goto err_ioremap;
+          }
+
+          /* bar1 contains a pointer to the SPI DIB table */
+          if (dib_len == 8) {
+                      u32 *ptemp = (u32 *)dib_vaddr;
+                      dib_len = *(ptemp + 1);
+                      dib_vaddr = ioremap(*(unsigned long *)dib_vaddr, dib_len);
+                      iounmap(ptemp);
+          }
+
+          header = (struct spi_dib_header *)dib_vaddr;
+          info_num = (header->length - sizeof(*header)) /
+                                                                                              sizeof(*dib);
+          dib = (struct spi_dib *)&header[1];
+
+          /* search for our dib entry. */
+          for (i = 0; i < info_num; i++)
+                      if (dib[i].host_num == 3)
+                                  break;
+          if (i == info_num)
+                      return;
+
+          strncpy(info[0].modalias, dib[i].name, SPI_DIB_NAME_LEN);
+          info[0].irq = dib[i].irq;
+          info[0].bus_num = dib[i].host_num;
+          info[0].chip_select = dib[i].cs;
+          info[0].mode = 0;
+          info[0].max_speed_hz = 0;
+
+          printk(KERN_INFO "SPI-Slave: name = %s, irq = 0x%x, "
+                      "bus = %d, cs = %d\n", info[0].modalias, info[0].irq,
+                      info[0].bus_num, info[0].chip_select);
+
+          pval = (u16 *)&(dib[i].dev_data[0]);
+
+          info[0].controller_data = &spidev_chip_info; /* Slave chip config */
+
+          for (j = 0; j < 5; j++) {
+                      spidev_chip_info.extra_data[j] = *pval;
+                      pval++;
+          }
+
+          spi_register_board_info(info, 1);
+
+err_ioremap:
+          pci_release_region(pdev, dib_bar);
+
+          return;
+}
+
+static int mrst_spi_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+          struct device *dev = &pdev->dev;
+          struct spi_slave *slave;
+          struct driver_data *drv_data = 0;
+          int status = 0;
+          int pci_bar = 0;
+
+          printk(KERN_INFO "SPI-Slave: found PCI SSP controller(ID: %04x:%04x)\n",
+                      pdev->vendor, pdev->device);
+
+          status = pci_enable_device(pdev);
+          if (status)
+                      return status;
+
+          /* Allocate Slave with space for drv_data and null dma buffer */
+          slave = spi_alloc_slave(dev, sizeof(struct driver_data));
+
+          if (!slave) {
+                      dev_err(&pdev->dev, "cannot alloc spi_slave\n");
+                      status = -ENOMEM;
+                      goto err_free_slave0;
+          }
+
+          drv_data = spi_slave_get_devdata(slave);
+          drv_data->slave = slave;
+
+          drv_data->pdev = pdev;
+          spin_lock_init(&drv_data->lock);
+
+          slave->bus_num = 3;
+          slave->num_chipselect = 1;
+          slave->cleanup = cleanup;
+          slave->setup = setup;
+          slave->transfer = transfer;
+
+          /* get basic io resource and map it */
+          drv_data->paddr = (void *)pci_resource_start(pdev, pci_bar);
+          drv_data->iolen = pci_resource_len(pdev, pci_bar);
+
+          status = pci_request_region(pdev, pci_bar, dev_name(&pdev->dev));
+          if (status)
+                      goto err_free_slave1;
+
+          drv_data->ioaddr =
+                      ioremap_nocache((u32)drv_data->paddr, drv_data->iolen);
+          if (!drv_data->ioaddr) {
+                      status = -ENOMEM;
+                      goto err_free_slave2;
+          }
+          printk(KERN_INFO "SPI-Slave: ioaddr = : %08x\n", (int)drv_data->ioaddr);
+          printk(KERN_INFO "SPI-Slave: attaching to IRQ: %04x\n", pdev->irq);
+
+          mrst_parse_spi_dib(pdev, drv_data);
+
+          /* get base address of IPC registers */
+          drv_data->IPC_paddr = (void *)0xffae8000;
+          drv_data->IPC_ioaddr =
+                      ioremap_nocache((unsigned long)drv_data->IPC_paddr, 0x80);
+          if (!drv_data->IPC_ioaddr) {
+                      status = -ENOMEM;
+                      goto err_free_slave3;
+          }
+          /* get base address of I2C_Serbus registers */
+          drv_data->I2C_paddr = (void *)0xff12b000;
+          drv_data->I2C_ioaddr =
+                      ioremap_nocache((unsigned long)drv_data->I2C_paddr, 0x10);
+          if (!drv_data->I2C_ioaddr) {
+                      status = -ENOMEM;
+                      goto err_free_slave4;
+          }
+
+          printk(KERN_INFO "SPI-Slave: IPC_ioaddr = : %08x\n",
+                      (int)drv_data->IPC_ioaddr);
+          printk(KERN_INFO "SPI-Slave: IPCCSR = : %08x\n",
+                      read_IPCCSR(drv_data->IPC_ioaddr));
+          write_IPCCSR(0x802, drv_data->IPC_ioaddr);
+          printk(KERN_INFO "SPI-Slave: IPCCSR = : %08x\n",
+                      read_IPCCSR(drv_data->IPC_ioaddr));
+
+          /* Attach to IRQ */
+          drv_data->irq = pdev->irq;
+          status = request_irq(drv_data->irq, ssp_int, IRQF_SHARED,
+                                  "mrst_spi3", drv_data);
+          if (status < 0) {
+                      dev_err(&pdev->dev, "can not get IRQ\n");
+                      goto err_free_slave5;
+          }
+
+          drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE;
+       	  drv_data->dma_cr1 = SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL;
+          drv_data->clear_sr = SSSR_ROR | SSSR_TINT;
+          drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
+
+          tasklet_init(&drv_data->poll_transfer,
+                                  poll_transfer,     (unsigned long)drv_data);
+
+          /* Setup DMA if requested */
+
+          /* Load default SSP configuration */
+          printk(KERN_INFO "SPI-Slave: setup default SSP configuration\n");
+          write_SSCR0(0, drv_data->ioaddr);
+          write_SSCR1(SSCR1_RxTresh(4) | SSCR1_TxTresh(12), drv_data->ioaddr);
+          write_SSCR0(SSCR0_Motorola
+                                   | SSCR0_DataSize(8),
+                                   drv_data->ioaddr);
+          write_SSTO(0, drv_data->ioaddr);
+          write_SSPSP(0x02010007, drv_data->ioaddr);
+
+          /* Register with the SPI framework */
+          printk(KERN_INFO "SPI-Slave: register with SPI framework\n");
+
+          status = spi_register_slave(slave);
+
+          if (status != 0) {
+                      dev_err(&pdev->dev, "problem registering spi slave\n");
+                      goto err_free_slave6;
+          }
+
+#ifdef CONFIG_SPI_MRST_SLAVE_DMA
+          mrst_spi_dma_init(drv_data);
+#endif
+
+          pci_set_drvdata(pdev, drv_data);
+
+          return status;
+
+err_free_slave6:
+          free_irq(drv_data->irq, drv_data);
+err_free_slave5:
+          iounmap(drv_data->I2C_ioaddr);
+err_free_slave4:
+          iounmap(drv_data->IPC_ioaddr);
+err_free_slave3:
+          iounmap(drv_data->ioaddr);
+err_free_slave2:
+          pci_release_region(pdev, pci_bar);
+err_free_slave1:
+          spi_slave_put(slave);
+err_free_slave0:
+          pci_disable_device(pdev);
+
+          return status;
+}
+
+static void __devexit mrst_spi_remove(struct pci_dev *pdev)
+{
+          struct driver_data *drv_data = pci_get_drvdata(pdev);
+
+          if (!drv_data)
+                      return;
+
+          pci_set_drvdata(pdev, NULL);
+
+#ifdef CONFIG_SPI_MRST_SLAVE_DMA
+          mrst_spi_dma_exit(drv_data);
+          pci_dev_put(drv_data->dmac1);
+#endif
+
+          /* Release IRQ */
+          free_irq(drv_data->irq, drv_data);
+
+          iounmap(drv_data->ioaddr);
+          iounmap(drv_data->I2C_ioaddr);
+          iounmap(drv_data->IPC_ioaddr);
+
+          pci_release_region(pdev, 0);
+
+          /* disconnect from the SPI framework */
+          spi_unregister_slave(drv_data->slave);
+
+          pci_disable_device(pdev);
+
+          return;
+}
+
+#ifdef CONFIG_PM
+
+static int mrst_spi_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+          struct driver_data *drv_data = pci_get_drvdata(pdev);
+          printk(KERN_ERR "spi-slave: suspend\n");
+
+          tasklet_disable(&drv_data->poll_transfer);
+
+          return 0;
+}
+
+static int mrst_spi_resume(struct pci_dev *pdev)
+{
+          struct driver_data *drv_data = pci_get_drvdata(pdev);
+          printk(KERN_ERR "spi-slave: resume\n");
+
+          tasklet_enable(&drv_data->poll_transfer);
+
+          return 0;
+}
+#else
+#define mrst_spi_suspend NULL
+#define mrst_spi_resume NULL
+#endif /* CONFIG_PM */
+
+
+static const struct pci_device_id pci_ids[] __devinitdata = {
+
+          {
+                      .vendor             = PCI_VENDOR_ID_INTEL,
+                      .device             = 0x0815,
+                      .subvendor       = PCI_ANY_ID,
+                      .subdevice        = PCI_ANY_ID,
+          },
+          {},
+};
+
+static struct pci_driver mrst_spi_slave_driver = {
+          .name =                        DRIVER_NAME,
+          .id_table =        pci_ids,
+          .probe =           mrst_spi_probe,
+          .remove =         __devexit_p(mrst_spi_remove),
+          .suspend =       mrst_spi_suspend,
+          .resume            =          mrst_spi_resume,
+};
+
+static int __init mrst_spi_init(void)
+{
+          return pci_register_driver(&mrst_spi_slave_driver);
+}
+
+late_initcall_sync(mrst_spi_init);
+
+static void __exit mrst_spi_exit(void)
+{
+          pci_unregister_driver(&mrst_spi_slave_driver);
+}
+module_exit(mrst_spi_exit);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index b76f246..f58f8c3 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -27,10 +27,16 @@
 #include <linux/spi/spi.h>
 
 
-/* SPI bustype and spi_master class are registered after board init code
- * provides the SPI device tables, ensuring that both are present by the
- * time controller driver registration causes spi_devices to "enumerate".
- */
+/* SPI bustype, spi_master and spi_slave class are registered after board
+* init code provides the SPI device tables, ensuring that both are present
+* by the time controller driver registration causes spi_devices
+* to "enumerate".
+*/
+
+/* SPI Slave Support is added for new spi slave devices: It uses common APIs,
+* apart from few new APIs and a spi_slave structure.
+*/
+
 static void spidev_release(struct device *dev)
 {
 	struct spi_device	*spi = to_spi_device(dev);
@@ -43,11 +49,22 @@ static void spidev_release(struct device *dev)
 	kfree(dev);
 }
 
+static void spidev_slave_release(struct device *dev)
+{
+	struct spi_device	*spi = to_spi_device(dev);
+
+	/* spi slave may cleanup */
+	if (spi->slave->cleanup)
+		spi->slave->cleanup(spi);
+
+	spi_slave_put(spi->slave);
+	kfree(dev);
+}
+
 static ssize_t
 modalias_show(struct device *dev, struct device_attribute *a, char *buf)
 {
 	const struct spi_device	*spi = to_spi_device(dev);
-
 	return sprintf(buf, "%s\n", spi->modalias);
 }
 
@@ -177,10 +194,13 @@ int spi_register_driver(struct spi_driver *sdrv)
 	sdrv->driver.bus = &spi_bus_type;
 	if (sdrv->probe)
 		sdrv->driver.probe = spi_drv_probe;
+
 	if (sdrv->remove)
 		sdrv->driver.remove = spi_drv_remove;
+
 	if (sdrv->shutdown)
 		sdrv->driver.shutdown = spi_drv_shutdown;
+
 	return driver_register(&sdrv->driver);
 }
 EXPORT_SYMBOL_GPL(spi_register_driver);
@@ -201,6 +221,7 @@ struct boardinfo {
 
 static LIST_HEAD(board_list);
 static DEFINE_MUTEX(board_lock);
+static DEFINE_MUTEX(slave_board_lock);
 
 /**
  * spi_alloc_device - Allocate a new SPI device
@@ -221,28 +242,70 @@ static DEFINE_MUTEX(board_lock);
  */
 struct spi_device *spi_alloc_device(struct spi_master *master)
 {
-	struct spi_device	*spi;
+	struct spi_device	*spi_m_dev;
 	struct device		*dev = master->dev.parent;
 
 	if (!spi_master_get(master))
 		return NULL;
 
-	spi = kzalloc(sizeof *spi, GFP_KERNEL);
-	if (!spi) {
+	spi_m_dev = kzalloc(sizeof *spi_m_dev, GFP_KERNEL);
+	if (!spi_m_dev) {
 		dev_err(dev, "cannot alloc spi_device\n");
 		spi_master_put(master);
 		return NULL;
 	}
 
-	spi->master = master;
-	spi->dev.parent = dev;
-	spi->dev.bus = &spi_bus_type;
-	spi->dev.release = spidev_release;
-	device_initialize(&spi->dev);
-	return spi;
+	spi_m_dev->master = master;
+	spi_m_dev->using_slave = 0;
+	spi_m_dev->dev.parent = dev;
+	spi_m_dev->dev.bus = &spi_bus_type;
+	spi_m_dev->dev.release = spidev_release;
+	device_initialize(&spi_m_dev->dev);
+	return spi_m_dev;
 }
 EXPORT_SYMBOL_GPL(spi_alloc_device);
 
+/*
+* spi_alloc_slave_device - Allocate a new SPI device
+* @slave: Controller to which device is connected
+* Context: can sleep
+*
+* Allows a driver to allocate and initialize a spi_device without
+* registering it immediately.  This allows a driver to directly
+* fill the spi_device with device parameters before calling
+* spi_add_slave_device() on it.
+*
+* Caller is responsible to call spi_add_slave_device() on the returned
+* spi_device structure to add it to the SPI slave.  If the caller
+* needs to discard the spi_device without adding it, then it should
+* call spi_dev_slave_put() on it.
+* Returns a pointer to the new device, or NULL.
+*/
+struct spi_device *spi_alloc_slave_device(struct spi_slave *slave)
+{
+	struct spi_device	*spi_s;
+	struct device		*dev = slave->dev.parent;
+
+	if (!spi_slave_get(slave))
+		return NULL;
+
+	spi_s = kzalloc(sizeof *spi_s, GFP_KERNEL);
+	if (!spi_s) {
+		dev_err(dev, "cannot alloc spi_slave_device\n");
+		spi_slave_put(slave);
+		return NULL;
+	}
+
+	spi_s->slave = slave;
+	spi_s->using_slave = 9;
+	spi_s->dev.parent = dev;
+	spi_s->dev.bus = &spi_bus_type;
+	spi_s->dev.release = spidev_slave_release;
+	device_initialize(&spi_s->dev);
+	return spi_s;
+}
+EXPORT_SYMBOL_GPL(spi_alloc_slave_device);
+
 /**
  * spi_add_device - Add spi_device allocated with spi_alloc_device
  * @spi: spi_device to register
@@ -301,6 +364,7 @@ int spi_add_device(struct spi_device *spi)
 	if (status < 0)
 		dev_err(dev, "can't %s %s, status %d\n",
 				"add", dev_name(&spi->dev), status);
+
 	else
 		dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
 
@@ -311,6 +375,74 @@ done:
 EXPORT_SYMBOL_GPL(spi_add_device);
 
 /**
+* spi_add_slave_device - Add spi_device allocated with spi_alloc_slave_device
+* @spi: spi_device to register
+*
+* Companion function to spi_alloc_slave_device.  Devices allocated with
+* spi_alloc_slave_device can be added onto the spi bus with this function.
+*
+* Returns 0 on success; negative errno on failure
+*/
+int spi_add_slave_device(struct spi_device *spi)
+{
+	static DEFINE_MUTEX(spi_slave_add_lock);
+	struct device *dev = spi->slave->dev.parent;
+	int status;
+
+	/* Chipselects are numbered 0..max; validate. */
+	if (spi->chip_select >= spi->slave->num_chipselect) {
+		dev_err(dev, "cs%d >= max %d\n",
+			spi->chip_select,
+			spi->slave->num_chipselect);
+		return -EINVAL;
+	}
+
+	/* Set the bus ID string */
+	dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->slave->dev),
+			spi->chip_select);
+
+
+	/* We need to make sure there's no other device with this
+	 * chipselect **BEFORE** we call setup(), else we'll trash
+	 * its configuration.  Lock against concurrent add() calls.
+	 */
+	mutex_lock(&spi_slave_add_lock);
+
+	if (bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev))
+			!= NULL) {
+		dev_err(dev, "chipselect %d already in use\n",
+				spi->chip_select);
+		status = -EBUSY;
+		goto done;
+	}
+
+	/* Drivers may modify this initial i/o setup, but will
+	 * normally rely on the device being setup.  Devices
+	 * using SPI_CS_HIGH can't coexist well otherwise...
+	 */
+	status = spi->slave->setup(spi);
+	if (status < 0) {
+		dev_err(dev, "can't %s %s, status %d\n",
+				"setup", dev_name(&spi->dev), status);
+		goto done;
+	}
+
+	/* Device may be bound to an active driver when this returns */
+	status = device_add(&spi->dev);
+	if (status < 0)
+		dev_err(dev, "can't %s %s, status %d\n",
+				"add", dev_name(&spi->dev), status);
+	else
+		dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
+
+done:
+	mutex_unlock(&spi_slave_add_lock);
+	return status;
+}
+EXPORT_SYMBOL_GPL(spi_add_slave_device);
+
+
+/**
  * spi_new_device - instantiate one new SPI device
  * @master: Controller to which device is connected
  * @chip: Describes the SPI device
@@ -341,6 +473,8 @@ struct spi_device *spi_new_device(struct spi_master *master,
 	if (!proxy)
 		return NULL;
 
+
+
 	WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
 
 	proxy->chip_select = chip->chip_select;
@@ -363,6 +497,54 @@ struct spi_device *spi_new_device(struct spi_master *master,
 EXPORT_SYMBOL_GPL(spi_new_device);
 
 /**
+* spi_slave_new_device - instantiate one new SPI device
+* @slave: Controller to which device is connected
+* @chip: Describes the SPI device
+* Context: can sleep
+*
+* On typical mainboards, this is purely internal; and it's not needed
+* after board init creates the hard-wired devices.  Some development
+* platforms may not be able to use spi_register_board_info though, and
+* this is exported so that for example a USB or parport based adapter
+* driver could add devices (which it would learn about out-of-band).
+*
+* Returns the new device, or NULL.
+*/
+struct spi_device *spi_slave_new_device(struct spi_slave *slave,
+				  struct spi_board_info *chip)
+{
+	struct spi_device	*proxy_slave;
+	int			status;
+
+	proxy_slave = spi_alloc_slave_device(slave);
+
+	if (!proxy_slave)
+		return NULL;
+
+	WARN_ON(strlen(chip->modalias) >= sizeof(proxy_slave->modalias));
+
+	proxy_slave->chip_select = chip->chip_select;
+	proxy_slave->max_speed_hz = chip->max_speed_hz;
+	proxy_slave->mode = chip->mode;
+	proxy_slave->irq = chip->irq;
+	strlcpy(proxy_slave->modalias, chip->modalias,
+					sizeof(proxy_slave->modalias));
+	proxy_slave->dev.platform_data = (void *) chip->platform_data;
+	proxy_slave->controller_data = chip->controller_data;
+	proxy_slave->controller_state = NULL;
+
+	status = spi_add_slave_device(proxy_slave);
+	if (status < 0) {
+		spi_dev_put(proxy_slave);
+		return NULL;
+	}
+
+	return proxy_slave;
+}
+EXPORT_SYMBOL_GPL(spi_slave_new_device);
+
+
+/**
  * spi_register_board_info - register SPI devices for a given board
  * @info: array of chip descriptors
  * @n: how many descriptors are provided
@@ -389,6 +571,7 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
 	bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
 	if (!bi)
 		return -ENOMEM;
+
 	bi->n_board_info = n;
 	memcpy(bi->board_info, info, n * sizeof *info);
 
@@ -398,6 +581,7 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
 	return 0;
 }
 
+
 /* FIXME someone should add support for a __setup("spi", ...) that
  * creates board info from kernel command lines
  */
@@ -423,6 +607,28 @@ static void scan_boardinfo(struct spi_master *master)
 	mutex_unlock(&board_lock);
 }
 
+static void spi_slave_scan_boardinfo(struct spi_slave *slave)
+{
+	struct boardinfo	*bi;
+
+	mutex_lock(&slave_board_lock);
+	list_for_each_entry(bi, &board_list, list) {
+		struct spi_board_info	*chip = bi->board_info;
+		unsigned		n;
+
+		for (n = bi->n_board_info; n > 0; n--, chip++) {
+			if (chip->bus_num != slave->bus_num)
+				continue;
+			/* NOTE: this relies on spi_new_device to
+			 * issue diagnostics when given bogus inputs
+			 */
+			(void) spi_slave_new_device(slave, chip);
+
+		}
+	}
+	mutex_unlock(&slave_board_lock);
+}
+
 /*-------------------------------------------------------------------------*/
 
 static void spi_master_release(struct device *dev)
@@ -439,6 +645,19 @@ static struct class spi_master_class = {
 	.dev_release	= spi_master_release,
 };
 
+static void spi_slave_release(struct device *dev)
+{
+	struct spi_slave *slave;
+
+	slave = container_of(dev, struct spi_slave, dev);
+	kfree(slave);
+}
+
+static struct class spi_slave_class = {
+	.name		= "spi_slave",
+	.owner		= THIS_MODULE,
+	.dev_release	= spi_slave_release,
+};
 
 /**
  * spi_alloc_master - allocate SPI master controller
@@ -480,6 +699,47 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
 EXPORT_SYMBOL_GPL(spi_alloc_master);
 
 /**
+* spi_alloc_slave - allocate SPI slave controller
+* @dev: the controller, possibly using the platform_bus
+* @size: how much zeroed driver-private data to allocate; the pointer to this
+*	memory is in the driver_data field of the returned device,
+*	accessible with spi_slave_get_devdata().
+* Context: can sleep
+*
+* This call is used only by SPI master controller drivers, which are the
+* only ones directly touching chip registers.  It's how they allocate
+* an spi_master structure, prior to calling spi_register_slave().
+*
+* This must be called from context that can sleep.  It returns the SPI
+* master structure on success, else NULL.
+*
+* The caller is responsible for assigning the bus number and initializing
+* the master's methods before calling spi_register_slave(); and (after errors
+* adding the device) calling spi_slave_put() to prevent a memory leak.
+*/
+struct spi_slave *spi_alloc_slave(struct device *dev, unsigned size)
+{
+	struct spi_slave	*slave;
+
+	if (!dev)
+		return NULL;
+
+	slave = kzalloc(size + sizeof *slave, GFP_KERNEL);
+	if (!slave)
+		return NULL;
+
+	device_initialize(&slave->dev);
+	slave->dev.class = &spi_slave_class;
+	slave->dev.parent = get_device(dev);
+	spi_slave_set_devdata(slave, &slave[1]);
+
+	return slave;
+}
+EXPORT_SYMBOL_GPL(spi_alloc_slave);
+
+
+
+/**
  * spi_register_master - register SPI master controller
  * @master: initialized master, originally from spi_alloc_master()
  * Context: can sleep
@@ -531,7 +791,8 @@ int spi_register_master(struct spi_master *master)
 	status = device_add(&master->dev);
 	if (status < 0)
 		goto done;
-	dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
+
+	dev_dbg(dev, "spi_register_master() : %s%s\n", dev_name(&master->dev),
 			dynamic ? " (dynamic)" : "");
 
 	/* populate children from any spi device tables */
@@ -542,6 +803,71 @@ done:
 }
 EXPORT_SYMBOL_GPL(spi_register_master);
 
+/**
+* spi_register_slave - register SPI slave controller
+* @master: initialized master, originally from spi_alloc_slave()
+* Context: can sleep
+*
+* SPI slave controllers connect to their drivers using some non-SPI bus,
+* such as the platform bus.  The final stage of probe() in that code
+* includes calling spi_register_slave() to hook up to this SPI bus glue.
+*
+* SPI controllers use board specific (often SOC specific) bus numbers,
+* and board-specific addressing for SPI devices combines those numbers
+* with chip select numbers.  Since SPI does not directly support dynamic
+* device identification, boards need configuration tables telling which
+* chip is at which address.
+*
+* This must be called from context that can sleep.  It returns zero on
+* success, else a negative error code (dropping the slave's refcount).
+* After a successful return, the caller is responsible for calling
+* spi_unregister_slave().
+*/
+int spi_register_slave(struct spi_slave *slave)
+{
+	static atomic_t		dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
+	struct device		*dev = slave->dev.parent;
+	int			status = -ENODEV;
+	int			dynamic = 0;
+
+	if (!dev)
+		return -ENODEV;
+
+	/* even if it's just one always-selected device, there must
+	 * be at least one chipselect
+	 */
+	if (slave->num_chipselect == 0)
+		return -EINVAL;
+
+	/* convention:  dynamically assigned bus IDs count down from the max */
+	if (slave->bus_num < 0) {
+		/* FIXME switch to an IDR based scheme, something like
+		 * I2C now uses, so we can't run out of "dynamic" IDs
+		 */
+		slave->bus_num = atomic_dec_return(&dyn_bus_id);
+		dynamic = 1;
+	}
+
+	/* register the device, then userspace will see it.
+	 * registration fails if the bus ID is in use.
+	 */
+	dev_set_name(&slave->dev, "spi%u", slave->bus_num);
+	status = device_add(&slave->dev);
+	if (status < 0)
+		goto done;
+
+	dev_dbg(dev, "registered slave %s%s\n", dev_name(&slave->dev),
+			dynamic ? " (dynamic)" : "");
+
+	/* populate children from any spi device tables */
+	spi_slave_scan_boardinfo(slave);
+	status = 0;
+done:
+	return status;
+}
+EXPORT_SYMBOL_GPL(spi_register_slave);
+
+
 
 static int __unregister(struct device *dev, void *master_dev)
 {
@@ -571,6 +897,27 @@ void spi_unregister_master(struct spi_master *master)
 }
 EXPORT_SYMBOL_GPL(spi_unregister_master);
 
+/**
+* spi_unregister_slave - unregister SPI slave controller
+* @master: the slave being unregistered
+* Context: can sleep
+*
+* This call is used only by SPI slave controller drivers, which are the
+* only ones directly touching chip registers.
+*
+* This must be called from context that can sleep.
+*/
+void spi_unregister_slave(struct spi_slave *slave)
+{
+	int dummy;
+
+	dummy = device_for_each_child(slave->dev.parent, &slave->dev,
+					__unregister);
+	device_unregister(&slave->dev);
+}
+EXPORT_SYMBOL_GPL(spi_unregister_slave);
+
+
 static int __spi_master_match(struct device *dev, void *data)
 {
 	struct spi_master *m;
@@ -718,7 +1065,12 @@ int spi_async(struct spi_device *spi, struct spi_message *message)
 
 	message->spi = spi;
 	message->status = -EINPROGRESS;
-	return master->transfer(spi, message);
+
+	/* TODO: ugly*/
+	if (spi->using_slave == 9)
+		return spi->slave->transfer(spi, message);	/* Slave */
+	else
+		return spi->master->transfer(spi, message);	/* Master */
 }
 EXPORT_SYMBOL_GPL(spi_async);
 
@@ -773,6 +1125,18 @@ int spi_sync(struct spi_device *spi, struct spi_message *message)
 }
 EXPORT_SYMBOL_GPL(spi_sync);
 
+/* spi_transfer_async - Wraper function to allow spi_async to expose to
+* user protocol drivers for modem handshaking
+*/
+
+int spi_transfer_async(struct spi_device *spi, struct spi_message *message)
+{
+	int status;
+	status = spi_async(spi, message);
+	return status;
+}
+EXPORT_SYMBOL_GPL(spi_transfer_async);
+
 /* portable code must never pass more than 32 bytes */
 #define	SPI_BUFSIZ	max(32,SMP_CACHE_BYTES)
 
@@ -871,6 +1235,12 @@ static int __init spi_init(void)
 	status = class_register(&spi_master_class);
 	if (status < 0)
 		goto err2;
+
+	status = class_register(&spi_slave_class);
+
+	if (status < 0)
+		goto err2;
+
 	return 0;
 
 err2:
@@ -890,4 +1260,3 @@ err0:
  * include needing to have boardinfo data structures be much more public.
  */
 postcore_initcall(spi_init);
-
diff --git a/include/linux/spi/mrst_spi_slave.h b/include/linux/spi/mrst_spi_slave.h
new file mode 100644
index 0000000..4d73f0e
--- /dev/null
+++ b/include/linux/spi/mrst_spi_slave.h
@@ -0,0 +1,143 @@
+/*
+ *  Copyright (C) Intel 2009
+ *  Ken Mills <ken.k.mills@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+#ifndef MRST_SSP_H_
+#define MRST_SSP_H_
+
+
+/*
+ * Langwell SSP serial port register definitions
+ */
+
+#define SSCR0_DSS   (0x0000000f)     /* Data Size Select (mask) */
+#define SSCR0_DataSize(x)  ((x) - 1)    /* Data Size Select [4..16] */
+#define SSCR0_FRF   (0x00000030)     /* FRame Format (mask) */
+#define SSCR0_Motorola        (0x0 << 4)         /* Motorola's SPI mode */
+#define SSCR0_ECS   (1 << 6) /* External clock select */
+#define SSCR0_SSE   (1 << 7) /* Synchronous Serial Port Enable */
+
+
+#define SSCR0_SCR   (0x000fff00)      /* Serial Clock Rate (mask) */
+#define SSCR0_SerClkDiv(x) (((x) - 1) << 8) /* Divisor [1..4096] */
+#define SSCR0_EDSS            (1 << 20)           /* Extended data size select */
+#define SSCR0_NCS   (1 << 21)           /* Network clock select */
+#define SSCR0_RIM    (1 << 22)           /* Receive FIFO overrrun int mask */
+#define SSCR0_TUM   (1 << 23)           /* Transmit FIFO underrun int mask */
+#define SSCR0_FRDC (0x07000000)     /* Frame rate divider control (mask) */
+#define SSCR0_SlotsPerFrm(x) (((x) - 1) << 24)            /* Time slots per frame */
+#define SSCR0_ADC   (1 << 30)           /* Audio clock select */
+#define SSCR0_MOD  (1 << 31)           /* Mode (normal or network) */
+
+
+#define SSCR1_RIE    (1 << 0) /* Receive FIFO Interrupt Enable */
+#define SSCR1_TIE     (1 << 1) /* Transmit FIFO Interrupt Enable */
+#define SSCR1_LBM   (1 << 2) /* Loop-Back Mode */
+#define SSCR1_SPO   (1 << 3) /* SSPSCLK polarity setting */
+#define SSCR1_SPH   (1 << 4) /* Motorola SPI SSPSCLK phase setting */
+#define SSCR1_MWDS           (1 << 5) /* Microwire Transmit Data Size */
+#define SSCR1_TFT    (0x000003c0)     /* Transmit FIFO Threshold (mask) */
+#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */
+#define SSCR1_RFT    (0x00003c00)     /* Receive FIFO Threshold (mask) */
+#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */
+
+#define SSSR_TNF     (1 << 2) /* Transmit FIFO Not Full */
+#define SSSR_RNE     (1 << 3) /* Receive FIFO Not Empty */
+#define SSSR_BSY     (1 << 4) /* SSP Busy */
+#define SSSR_TFS     (1 << 5) /* Transmit FIFO Service Request */
+#define SSSR_RFS     (1 << 6) /* Receive FIFO Service Request */
+#define SSSR_ROR    (1 << 7) /* Receive FIFO Overrun */
+
+#define SSCR0_TIM    (1 << 23)           /* Transmit FIFO Under Run Int Mask */
+#define SSCR0_RIM    (1 << 22)           /* Receive FIFO Over Run int Mask */
+#define SSCR0_NCS   (1 << 21)           /* Network Clock Select */
+#define SSCR0_EDSS            (1 << 20)           /* Extended Data Size Select */
+
+#define SSCR0_TISSP            (1 << 4) /* TI Sync Serial Protocol */
+#define SSCR0_PSP   (3 << 4) /* PSP - Programmable Serial Protocol */
+#define SSCR1_TTELP            (1 << 31)           /* TXD Tristate Enable Last Phase */
+#define SSCR1_TTE    (1 << 30)           /* TXD Tristate Enable */
+#define SSCR1_EBCEI            (1 << 29)           /* Enable Bit Count Error interrupt */
+#define SSCR1_SCFR (1 << 28)           /* Slave Clock free Running */
+#define SSCR1_ECRA (1 << 27)           /* Enable Clock Request A */
+#define SSCR1_ECRB (1 << 26)           /* Enable Clock request B */
+#define SSCR1_SCLKDIR        (1 << 25)           /* Serial Bit Rate Clock Direction */
+#define SSCR1_SFRMDIR       (1 << 24)           /* Frame Direction */
+#define SSCR1_RWOT            (1 << 23)           /* Receive Without Transmit */
+#define SSCR1_TRAIL (1 << 22)           /* Trailing Byte */
+#define SSCR1_TSRE (1 << 21)           /* Transmit Service Request Enable */
+#define SSCR1_RSRE (1 << 20)           /* Receive Service Request Enable */
+#define SSCR1_TINTE (1 << 19)           /* Receiver Time-out Interrupt enable */
+#define SSCR1_PINTE            (1 << 18)           /* Trailing Byte Interupt Enable */
+#define SSCR1_STRF (1 << 15)           /* Select FIFO or EFWR */
+#define SSCR1_EFWR            (1 << 14)           /* Enable FIFO Write/Read */
+
+#define SSSR_BCE     (1 << 23)           /* Bit Count Error */
+#define SSSR_CSS     (1 << 22)           /* Clock Synchronisation Status */
+#define SSSR_TUR     (1 << 21)           /* Transmit FIFO Under Run */
+#define SSSR_EOC    (1 << 20)           /* End Of Chain */
+#define SSSR_TINT     (1 << 19)           /* Receiver Time-out Interrupt */
+#define SSSR_PINT    (1 << 18)           /* Peripheral Trailing Byte Interrupt */
+
+#define SSPSP_FSRT (1 << 25)           /* Frame Sync Relative Timing */
+#define SSPSP_DMYSTOP(x) ((x) << 23)         /* Dummy Stop */
+#define SSPSP_SFRMWDTH(x) ((x) << 16)      /* Serial Frame Width */
+#define SSPSP_SFRMDLY(x) ((x) << 9)           /* Serial Frame Delay */
+#define SSPSP_DMYSTRT(x) ((x) << 7)           /* Dummy Start */
+#define SSPSP_STRTDLY(x) ((x) << 4)            /* Start Delay */
+#define SSPSP_ETDS            (1 << 3) /* End of Transfer data State */
+#define SSPSP_SFRMP          (1 << 2) /* Serial Frame Polarity */
+#define SSPSP_SCMODE(x)   ((x) << 0)           /* Serial Bit Rate Clock Mode */
+
+/* spi_board_info.controller_data for SPI slave devices,
+ * copied to spi_device.platform_data ... mostly for dma tuning
+ */
+struct mrst_spi_chip {
+          u8 tx_threshold;
+          u8 rx_threshold;
+          u8 dma_burst_size;
+          u32 timeout;
+          u8 enable_loopback;
+          u16 extra_data[5];
+};
+
+
+#define SPI_DIB_NAME_LEN  16
+#define SPI_DIB_SPEC_INFO_LEN      10
+
+struct spi_dib_header {
+          u32       signature;
+          u32       length;
+          u8         rev;
+          u8         checksum;
+          u8         dib[0];
+} __attribute__((packed));
+
+struct spi_dib {
+          u16       host_num;
+          u16       cs;
+          u16       irq;
+          char      name[SPI_DIB_NAME_LEN];
+          u8         dev_data[SPI_DIB_SPEC_INFO_LEN];
+} __attribute__((packed));
+
+#endif /*MRST_SSP_H_*/
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 97b60b3..87b4d12 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -23,15 +23,19 @@
 #include <linux/mod_devicetable.h>
 
 /*
- * INTERFACES between SPI master-side drivers and SPI infrastructure.
- * (There's no SPI slave support for Linux yet...)
+ * INTERFACES between SPI Master/Slave side drivers and
+ * SPI infrastructure.
+ * SPI Slave Support added : It uses few new APIs and
+ * a new spi_slave struct
  */
 extern struct bus_type spi_bus_type;
 
 /**
  * struct spi_device - Master side proxy for an SPI slave device
  * @dev: Driver model representation of the device.
- * @master: SPI controller used with the device.
+ * @master: SPI Master controller used with the device.
+ * @slave: SPI Slave Controller used with the device
+ * @using_slave: SPI Slave Flag used by spi_async()
  * @max_speed_hz: Maximum clock rate to be used with this chip
  *	(on this board); may be changed by the device's driver.
  *	The spi_transfer.speed_hz can override this for each transfer.
@@ -68,6 +72,8 @@ extern struct bus_type spi_bus_type;
 struct spi_device {
 	struct device		dev;
 	struct spi_master	*master;
+	struct spi_slave	*slave;
+	u8			using_slave;
 	u32			max_speed_hz;
 	u8			chip_select;
 	u8			mode;
@@ -143,7 +149,6 @@ static inline void *spi_get_drvdata(struct spi_device *spi)
 struct spi_message;
 
 
-
 /**
  * struct spi_driver - Host side "protocol" driver
  * @id_table: List of SPI devices supported by this driver
@@ -295,16 +300,56 @@ struct spi_master {
 	void			(*cleanup)(struct spi_device *spi);
 };
 
+/**
+ * struct spi_slave - interface to SPI Slave Controller
+ * @dev: device interface to this driver
+ * @bus_num: board-specific (and often SOC-specific) identifier for a
+ *	given SPI controller.
+ * @num_chipselect: chipselects are used to distinguish individual
+ *	SPI slaves, and are numbered from zero to num_chipselects.
+ *	each slave has a chipselect signal, but it's common that not
+ *	every chipselect is connected to a slave.
+ * @setup: updates the device mode and clocking records used by a
+ *	device's SPI controller; protocol code may call this.  This
+ *	must fail if an unrecognized or unsupported mode is requested.
+ *	It's always safe to call this unless transfers are pending on
+ *	the device whose settings are being modified.
+ * @transfer: adds a message to the controller's transfer queue.
+ * @cleanup: frees controller-specific state
+ */
+struct spi_slave {
+	struct device	dev;
+	s16			bus_num;
+	u16			num_chipselect;
+
+	int			(*setup)(struct spi_device *spi);
+
+	int			(*transfer)(struct spi_device *spi,
+						struct spi_message *mesg);
+
+	void			(*cleanup)(struct spi_device *spi);
+};
+
 static inline void *spi_master_get_devdata(struct spi_master *master)
 {
 	return dev_get_drvdata(&master->dev);
 }
 
+static inline void *spi_slave_get_devdata(struct spi_slave *slave)
+{
+	return dev_get_drvdata(&slave->dev);
+}
+
 static inline void spi_master_set_devdata(struct spi_master *master, void *data)
 {
 	dev_set_drvdata(&master->dev, data);
 }
 
+static inline void spi_slave_set_devdata(struct spi_slave *slave, void *data)
+{
+	dev_set_drvdata(&slave->dev, data);
+}
+
 static inline struct spi_master *spi_master_get(struct spi_master *master)
 {
 	if (!master || !get_device(&master->dev))
@@ -312,20 +357,42 @@ static inline struct spi_master *spi_master_get(struct spi_master *master)
 	return master;
 }
 
+static inline struct spi_slave *spi_slave_get(struct spi_slave *slave)
+{
+	if (!slave || !get_device(&slave->dev))
+		return NULL;
+	return slave;
+}
+
 static inline void spi_master_put(struct spi_master *master)
 {
 	if (master)
 		put_device(&master->dev);
 }
 
+static inline void spi_slave_put(struct spi_slave *slave)
+{
+	if (slave)
+		put_device(&slave->dev);
+}
+
 
 /* the spi driver core manages memory for the spi_master classdev */
 extern struct spi_master *
 spi_alloc_master(struct device *host, unsigned size);
 
+extern struct spi_slave *
+spi_alloc_slave(struct device *host, unsigned size);
+
+
 extern int spi_register_master(struct spi_master *master);
+
+extern int spi_register_slave(struct spi_slave *slave);
+
 extern void spi_unregister_master(struct spi_master *master);
 
+extern void spi_unregister_slave(struct spi_slave *slave);
+
 extern struct spi_master *spi_busnum_to_master(u16 busnum);
 
 /*---------------------------------------------------------------------------*/
@@ -551,6 +618,18 @@ extern int spi_async(struct spi_device *spi, struct spi_message *message);
 
 extern int spi_sync(struct spi_device *spi, struct spi_message *message);
 
+static inline int
+spi_slave_setup(struct spi_device *spi)
+{
+	return spi->slave->setup(spi);
+}
+
+
+/* spi_transfer_async() exposes spi_async() functionality */
+extern int spi_transfer_async(struct spi_device *spi,
+			      struct spi_message *message);
+
+
 /**
  * spi_write - SPI synchronous write
  * @spi: device to which data will be written
@@ -759,12 +838,23 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
 extern struct spi_device *
 spi_alloc_device(struct spi_master *master);
 
+extern struct spi_device *
+spi_alloc_slave_device(struct spi_slave *slave);
+
 extern int
 spi_add_device(struct spi_device *spi);
 
+extern int
+spi_add_slave_device(struct spi_device *spi);
+
+
 extern struct spi_device *
 spi_new_device(struct spi_master *, struct spi_board_info *);
 
+extern struct spi_device *
+spi_slave_new_device(struct spi_slave *, struct spi_board_info *);
+
+
 static inline void
 spi_unregister_device(struct spi_device *spi)
 {
-- 
1.6.2.5

openSUSE Build Service is sponsored by