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