diff options
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-spi-slave-controller-driver-1.1.patch')
-rw-r--r-- | meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-spi-slave-controller-driver-1.1.patch | 2230 |
1 files changed, 0 insertions, 2230 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-spi-slave-controller-driver-1.1.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-spi-slave-controller-driver-1.1.patch deleted file mode 100644 index 2328f9a30..000000000 --- a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-spi-slave-controller-driver-1.1.patch +++ /dev/null @@ -1,2230 +0,0 @@ -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 - |