summaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig29
-rw-r--r--drivers/spi/Makefile3
-rw-r--r--drivers/spi/amba-pl022.c1866
-rw-r--r--drivers/spi/atmel_spi.c14
-rw-r--r--drivers/spi/au1550_spi.c14
-rw-r--r--drivers/spi/mpc52xx_psc_spi.c34
-rw-r--r--drivers/spi/omap2_mcspi.c16
-rw-r--r--drivers/spi/omap_uwire.c16
-rw-r--r--drivers/spi/orion_spi.c12
-rw-r--r--drivers/spi/pxa2xx_spi.c23
-rw-r--r--drivers/spi/spi.c70
-rw-r--r--drivers/spi/spi_bfin5xx.c19
-rw-r--r--drivers/spi/spi_bitbang.c40
-rw-r--r--drivers/spi/spi_imx.c17
-rw-r--r--drivers/spi/spi_mpc8xxx.c (renamed from drivers/spi/spi_mpc83xx.c)535
-rw-r--r--drivers/spi/spi_s3c24xx.c19
-rw-r--r--drivers/spi/spi_s3c24xx_gpio.c1
-rw-r--r--drivers/spi/spi_txx9.c11
-rw-r--r--drivers/spi/spidev.c17
-rw-r--r--drivers/spi/xilinx_spi.c18
20 files changed, 2295 insertions, 479 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 83a185d5296..2c733c27db2 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -118,7 +118,7 @@ config SPI_GPIO
config SPI_IMX
tristate "Freescale iMX SPI controller"
- depends on ARCH_IMX && EXPERIMENTAL
+ depends on ARCH_MX1 && EXPERIMENTAL
help
This enables using the Freescale iMX SPI controller in master
mode.
@@ -139,17 +139,15 @@ config SPI_MPC52xx_PSC
This enables using the Freescale MPC52xx Programmable Serial
Controller in master SPI mode.
-config SPI_MPC83xx
- tristate "Freescale MPC83xx/QUICC Engine SPI controller"
- depends on (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL
+config SPI_MPC8xxx
+ tristate "Freescale MPC8xxx SPI controller"
+ depends on FSL_SOC
help
- This enables using the Freescale MPC83xx and QUICC Engine SPI
- controllers in master mode.
+ This enables using the Freescale MPC8xxx SPI controllers in master
+ mode.
- Note, this driver uniquely supports the SPI controller on the MPC83xx
- family of PowerPC processors, plus processors with QUICC Engine
- technology. This driver uses a simple set of shift registers for data
- (opposed to the CPM based descriptor model).
+ This driver uses a simple set of shift registers for data (opposed
+ to the CPM based descriptor model).
config SPI_OMAP_UWIRE
tristate "OMAP1 MicroWire"
@@ -171,6 +169,15 @@ config SPI_ORION
help
This enables using the SPI master controller on the Orion chips.
+config SPI_PL022
+ tristate "ARM AMBA PL022 SSP controller (EXPERIMENTAL)"
+ depends on ARM_AMBA && EXPERIMENTAL
+ default y if MACH_U300
+ help
+ This selects the ARM(R) AMBA(R) PrimeCell PL022 SSP
+ controller. If you have an embedded system with an AMBA(R)
+ bus and a PL022 controller, say Y or M here.
+
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
depends on ARCH_PXA && EXPERIMENTAL
@@ -212,7 +219,7 @@ config SPI_TXX9
config SPI_XILINX
tristate "Xilinx SPI controller"
- depends on XILINX_VIRTEX && EXPERIMENTAL
+ depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL
select SPI_BITBANG
help
This exposes the SPI controller IP from the Xilinx EDK.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 5d0451936d8..3de408d294b 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -23,8 +23,9 @@ obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o
obj-$(CONFIG_SPI_ORION) += orion_spi.o
+obj-$(CONFIG_SPI_PL022) += amba-pl022.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o
-obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o
+obj-$(CONFIG_SPI_MPC8xxx) += spi_mpc8xxx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
new file mode 100644
index 00000000000..da76797ce8b
--- /dev/null
+++ b/drivers/spi/amba-pl022.c
@@ -0,0 +1,1866 @@
+/*
+ * drivers/spi/amba-pl022.c
+ *
+ * A driver for the ARM PL022 PrimeCell SSP/SPI bus master.
+ *
+ * Copyright (C) 2008-2009 ST-Ericsson AB
+ * Copyright (C) 2006 STMicroelectronics Pvt. Ltd.
+ *
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ *
+ * Initial version inspired by:
+ * linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c
+ * Initial adoption to PL022 by:
+ * Sachin Verma <sachin.verma@st.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.
+ */
+
+/*
+ * TODO:
+ * - add timeout on polled transfers
+ * - add generic DMA framework support
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/pl022.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+/*
+ * This macro is used to define some register default values.
+ * reg is masked with mask, the OR:ed with an (again masked)
+ * val shifted sb steps to the left.
+ */
+#define SSP_WRITE_BITS(reg, val, mask, sb) \
+ ((reg) = (((reg) & ~(mask)) | (((val)<<(sb)) & (mask))))
+
+/*
+ * This macro is also used to define some default values.
+ * It will just shift val by sb steps to the left and mask
+ * the result with mask.
+ */
+#define GEN_MASK_BITS(val, mask, sb) \
+ (((val)<<(sb)) & (mask))
+
+#define DRIVE_TX 0
+#define DO_NOT_DRIVE_TX 1
+
+#define DO_NOT_QUEUE_DMA 0
+#define QUEUE_DMA 1
+
+#define RX_TRANSFER 1
+#define TX_TRANSFER 2
+
+/*
+ * Macros to access SSP Registers with their offsets
+ */
+#define SSP_CR0(r) (r + 0x000)
+#define SSP_CR1(r) (r + 0x004)
+#define SSP_DR(r) (r + 0x008)
+#define SSP_SR(r) (r + 0x00C)
+#define SSP_CPSR(r) (r + 0x010)
+#define SSP_IMSC(r) (r + 0x014)
+#define SSP_RIS(r) (r + 0x018)
+#define SSP_MIS(r) (r + 0x01C)
+#define SSP_ICR(r) (r + 0x020)
+#define SSP_DMACR(r) (r + 0x024)
+#define SSP_ITCR(r) (r + 0x080)
+#define SSP_ITIP(r) (r + 0x084)
+#define SSP_ITOP(r) (r + 0x088)
+#define SSP_TDR(r) (r + 0x08C)
+
+#define SSP_PID0(r) (r + 0xFE0)
+#define SSP_PID1(r) (r + 0xFE4)
+#define SSP_PID2(r) (r + 0xFE8)
+#define SSP_PID3(r) (r + 0xFEC)
+
+#define SSP_CID0(r) (r + 0xFF0)
+#define SSP_CID1(r) (r + 0xFF4)
+#define SSP_CID2(r) (r + 0xFF8)
+#define SSP_CID3(r) (r + 0xFFC)
+
+/*
+ * SSP Control Register 0 - SSP_CR0
+ */
+#define SSP_CR0_MASK_DSS (0x1FUL << 0)
+#define SSP_CR0_MASK_HALFDUP (0x1UL << 5)
+#define SSP_CR0_MASK_SPO (0x1UL << 6)
+#define SSP_CR0_MASK_SPH (0x1UL << 7)
+#define SSP_CR0_MASK_SCR (0xFFUL << 8)
+#define SSP_CR0_MASK_CSS (0x1FUL << 16)
+#define SSP_CR0_MASK_FRF (0x3UL << 21)
+
+/*
+ * SSP Control Register 0 - SSP_CR1
+ */
+#define SSP_CR1_MASK_LBM (0x1UL << 0)
+#define SSP_CR1_MASK_SSE (0x1UL << 1)
+#define SSP_CR1_MASK_MS (0x1UL << 2)
+#define SSP_CR1_MASK_SOD (0x1UL << 3)
+#define SSP_CR1_MASK_RENDN (0x1UL << 4)
+#define SSP_CR1_MASK_TENDN (0x1UL << 5)
+#define SSP_CR1_MASK_MWAIT (0x1UL << 6)
+#define SSP_CR1_MASK_RXIFLSEL (0x7UL << 7)
+#define SSP_CR1_MASK_TXIFLSEL (0x7UL << 10)
+
+/*
+ * SSP Data Register - SSP_DR
+ */
+#define SSP_DR_MASK_DATA 0xFFFFFFFF
+
+/*
+ * SSP Status Register - SSP_SR
+ */
+#define SSP_SR_MASK_TFE (0x1UL << 0) /* Transmit FIFO empty */
+#define SSP_SR_MASK_TNF (0x1UL << 1) /* Transmit FIFO not full */
+#define SSP_SR_MASK_RNE (0x1UL << 2) /* Receive FIFO not empty */
+#define SSP_SR_MASK_RFF (0x1UL << 3) /* Receive FIFO full */
+#define SSP_SR_MASK_BSY (0x1UL << 4) /* Busy Flag */
+
+/*
+ * SSP Clock Prescale Register - SSP_CPSR
+ */
+#define SSP_CPSR_MASK_CPSDVSR (0xFFUL << 0)
+
+/*
+ * SSP Interrupt Mask Set/Clear Register - SSP_IMSC
+ */
+#define SSP_IMSC_MASK_RORIM (0x1UL << 0) /* Receive Overrun Interrupt mask */
+#define SSP_IMSC_MASK_RTIM (0x1UL << 1) /* Receive timeout Interrupt mask */
+#define SSP_IMSC_MASK_RXIM (0x1UL << 2) /* Receive FIFO Interrupt mask */
+#define SSP_IMSC_MASK_TXIM (0x1UL << 3) /* Transmit FIFO Interrupt mask */
+
+/*
+ * SSP Raw Interrupt Status Register - SSP_RIS
+ */
+/* Receive Overrun Raw Interrupt status */
+#define SSP_RIS_MASK_RORRIS (0x1UL << 0)
+/* Receive Timeout Raw Interrupt status */
+#define SSP_RIS_MASK_RTRIS (0x1UL << 1)
+/* Receive FIFO Raw Interrupt status */
+#define SSP_RIS_MASK_RXRIS (0x1UL << 2)
+/* Transmit FIFO Raw Interrupt status */
+#define SSP_RIS_MASK_TXRIS (0x1UL << 3)
+
+/*
+ * SSP Masked Interrupt Status Register - SSP_MIS
+ */
+/* Receive Overrun Masked Interrupt status */
+#define SSP_MIS_MASK_RORMIS (0x1UL << 0)
+/* Receive Timeout Masked Interrupt status */
+#define SSP_MIS_MASK_RTMIS (0x1UL << 1)
+/* Receive FIFO Masked Interrupt status */
+#define SSP_MIS_MASK_RXMIS (0x1UL << 2)
+/* Transmit FIFO Masked Interrupt status */
+#define SSP_MIS_MASK_TXMIS (0x1UL << 3)
+
+/*
+ * SSP Interrupt Clear Register - SSP_ICR
+ */
+/* Receive Overrun Raw Clear Interrupt bit */
+#define SSP_ICR_MASK_RORIC (0x1UL << 0)
+/* Receive Timeout Clear Interrupt bit */
+#define SSP_ICR_MASK_RTIC (0x1UL << 1)
+
+/*
+ * SSP DMA Control Register - SSP_DMACR
+ */
+/* Receive DMA Enable bit */
+#define SSP_DMACR_MASK_RXDMAE (0x1UL << 0)
+/* Transmit DMA Enable bit */
+#define SSP_DMACR_MASK_TXDMAE (0x1UL << 1)
+
+/*
+ * SSP Integration Test control Register - SSP_ITCR
+ */
+#define SSP_ITCR_MASK_ITEN (0x1UL << 0)
+#define SSP_ITCR_MASK_TESTFIFO (0x1UL << 1)
+
+/*
+ * SSP Integration Test Input Register - SSP_ITIP
+ */
+#define ITIP_MASK_SSPRXD (0x1UL << 0)
+#define ITIP_MASK_SSPFSSIN (0x1UL << 1)
+#define ITIP_MASK_SSPCLKIN (0x1UL << 2)
+#define ITIP_MASK_RXDMAC (0x1UL << 3)
+#define ITIP_MASK_TXDMAC (0x1UL << 4)
+#define ITIP_MASK_SSPTXDIN (0x1UL << 5)
+
+/*
+ * SSP Integration Test output Register - SSP_ITOP
+ */
+#define ITOP_MASK_SSPTXD (0x1UL << 0)
+#define ITOP_MASK_SSPFSSOUT (0x1UL << 1)
+#define ITOP_MASK_SSPCLKOUT (0x1UL << 2)
+#define ITOP_MASK_SSPOEn (0x1UL << 3)
+#define ITOP_MASK_SSPCTLOEn (0x1UL << 4)
+#define ITOP_MASK_RORINTR (0x1UL << 5)
+#define ITOP_MASK_RTINTR (0x1UL << 6)
+#define ITOP_MASK_RXINTR (0x1UL << 7)
+#define ITOP_MASK_TXINTR (0x1UL << 8)
+#define ITOP_MASK_INTR (0x1UL << 9)
+#define ITOP_MASK_RXDMABREQ (0x1UL << 10)
+#define ITOP_MASK_RXDMASREQ (0x1UL << 11)
+#define ITOP_MASK_TXDMABREQ (0x1UL << 12)
+#define ITOP_MASK_TXDMASREQ (0x1UL << 13)
+
+/*
+ * SSP Test Data Register - SSP_TDR
+ */
+#define TDR_MASK_TESTDATA (0xFFFFFFFF)
+
+/*
+ * Message State
+ * we use the spi_message.state (void *) pointer to
+ * hold a single state value, that's why all this
+ * (void *) casting is done here.
+ */
+#define STATE_START ((void *) 0)
+#define STATE_RUNNING ((void *) 1)
+#define STATE_DONE ((void *) 2)
+#define STATE_ERROR ((void *) -1)
+
+/*
+ * Queue State
+ */
+#define QUEUE_RUNNING (0)
+#define QUEUE_STOPPED (1)
+/*
+ * SSP State - Whether Enabled or Disabled
+ */
+#define SSP_DISABLED (0)
+#define SSP_ENABLED (1)
+
+/*
+ * SSP DMA State - Whether DMA Enabled or Disabled
+ */
+#define SSP_DMA_DISABLED (0)
+#define SSP_DMA_ENABLED (1)
+
+/*
+ * SSP Clock Defaults
+ */
+#define NMDK_SSP_DEFAULT_CLKRATE 0x2
+#define NMDK_SSP_DEFAULT_PRESCALE 0x40
+
+/*
+ * SSP Clock Parameter ranges
+ */
+#define CPSDVR_MIN 0x02
+#define CPSDVR_MAX 0xFE
+#define SCR_MIN 0x00
+#define SCR_MAX 0xFF
+
+/*
+ * SSP Interrupt related Macros
+ */
+#define DEFAULT_SSP_REG_IMSC 0x0UL
+#define DISABLE_ALL_INTERRUPTS DEFAULT_SSP_REG_IMSC
+#define ENABLE_ALL_INTERRUPTS (~DEFAULT_SSP_REG_IMSC)
+
+#define CLEAR_ALL_INTERRUPTS 0x3
+
+
+/*
+ * The type of reading going on on this chip
+ */
+enum ssp_reading {
+ READING_NULL,
+ READING_U8,
+ READING_U16,
+ READING_U32
+};
+
+/**
+ * The type of writing going on on this chip
+ */
+enum ssp_writing {
+ WRITING_NULL,
+ WRITING_U8,
+ WRITING_U16,
+ WRITING_U32
+};
+
+/**
+ * struct vendor_data - vendor-specific config parameters
+ * for PL022 derivates
+ * @fifodepth: depth of FIFOs (both)
+ * @max_bpw: maximum number of bits per word
+ * @unidir: supports unidirection transfers
+ */
+struct vendor_data {
+ int fifodepth;
+ int max_bpw;
+ bool unidir;
+};
+
+/**
+ * struct pl022 - This is the private SSP driver data structure
+ * @adev: AMBA device model hookup
+ * @phybase: The physical memory where the SSP device resides
+ * @virtbase: The virtual memory where the SSP is mapped
+ * @master: SPI framework hookup
+ * @master_info: controller-specific data from machine setup
+ * @regs: SSP controller register's virtual address
+ * @pump_messages: Work struct for scheduling work to the workqueue
+ * @lock: spinlock to syncronise access to driver data
+ * @workqueue: a workqueue on which any spi_message request is queued
+ * @busy: workqueue is busy
+ * @run: workqueue is running
+ * @pump_transfers: Tasklet used in Interrupt Transfer mode
+ * @cur_msg: Pointer to current spi_message being processed
+ * @cur_transfer: Pointer to current spi_transfer
+ * @cur_chip: pointer to current clients chip(assigned from controller_state)
+ * @tx: current position in TX buffer to be read
+ * @tx_end: end position in TX buffer to be read
+ * @rx: current position in RX buffer to be written
+ * @rx_end: end position in RX buffer to be written
+ * @readingtype: the type of read currently going on
+ * @writingtype: the type or write currently going on
+ */
+struct pl022 {
+ struct amba_device *adev;
+ struct vendor_data *vendor;
+ resource_size_t phybase;
+ void __iomem *virtbase;
+ struct clk *clk;
+ struct spi_master *master;
+ struct pl022_ssp_controller *master_info;
+ /* Driver message queue */
+ struct workqueue_struct *workqueue;
+ struct work_struct pump_messages;
+ spinlock_t queue_lock;
+ struct list_head queue;
+ int busy;
+ int run;
+ /* Message transfer pump */
+ struct tasklet_struct pump_transfers;
+ struct spi_message *cur_msg;
+ struct spi_transfer *cur_transfer;
+ struct chip_data *cur_chip;
+ void *tx;
+ void *tx_end;
+ void *rx;
+ void *rx_end;
+ enum ssp_reading read;
+ enum ssp_writing write;
+};
+
+/**
+ * struct chip_data - To maintain runtime state of SSP for each client chip
+ * @cr0: Value of control register CR0 of SSP
+ * @cr1: Value of control register CR1 of SSP
+ * @dmacr: Value of DMA control Register of SSP
+ * @cpsr: Value of Clock prescale register
+ * @n_bytes: how many bytes(power of 2) reqd for a given data width of client
+ * @enable_dma: Whether to enable DMA or not
+ * @write: function ptr to be used to write when doing xfer for this chip
+ * @read: function ptr to be used to read when doing xfer for this chip
+ * @cs_control: chip select callback provided by chip
+ * @xfer_type: polling/interrupt/DMA
+ *
+ * Runtime state of the SSP controller, maintained per chip,
+ * This would be set according to the current message that would be served
+ */
+struct chip_data {
+ u16 cr0;
+ u16 cr1;
+ u16 dmacr;
+ u16 cpsr;
+ u8 n_bytes;
+ u8 enable_dma:1;
+ enum ssp_reading read;
+ enum ssp_writing write;
+ void (*cs_control) (u32 command);
+ int xfer_type;
+};
+
+/**
+ * null_cs_control - Dummy chip select function
+ * @command: select/delect the chip
+ *
+ * If no chip select function is provided by client this is used as dummy
+ * chip select
+ */
+static void null_cs_control(u32 command)
+{
+ pr_debug("pl022: dummy chip select control, CS=0x%x\n", command);
+}
+
+/**
+ * giveback - current spi_message is over, schedule next message and call
+ * callback of this message. Assumes that caller already
+ * set message->status; dma and pio irqs are blocked
+ * @pl022: SSP driver private data structure
+ */
+static void giveback(struct pl022 *pl022)
+{
+ struct spi_transfer *last_transfer;
+ unsigned long flags;
+ struct spi_message *msg;
+ void (*curr_cs_control) (u32 command);
+
+ /*
+ * This local reference to the chip select function
+ * is needed because we set curr_chip to NULL
+ * as a step toward termininating the message.
+ */
+ curr_cs_control = pl022->cur_chip->cs_control;
+ spin_lock_irqsave(&pl022->queue_lock, flags);
+ msg = pl022->cur_msg;
+ pl022->cur_msg = NULL;
+ pl022->cur_transfer = NULL;
+ pl022->cur_chip = NULL;
+ queue_work(pl022->workqueue, &pl022->pump_messages);
+ spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+ last_transfer = list_entry(msg->transfers.prev,
+ struct spi_transfer,
+ transfer_list);
+
+ /* Delay if requested before any change in chip select */
+ if (last_transfer->delay_usecs)
+ /*
+ * FIXME: This runs in interrupt context.
+ * Is this really smart?
+ */
+ udelay(last_transfer->delay_usecs);
+
+ /*
+ * Drop chip select UNLESS cs_change is true or we are returning
+ * a message with an error, or next message is for another chip
+ */
+ if (!last_transfer->cs_change)
+ curr_cs_control(SSP_CHIP_DESELECT);
+ else {
+ struct spi_message *next_msg;
+
+ /* Holding of cs was hinted, but we need to make sure
+ * the next message is for the same chip. Don't waste
+ * time with the following tests unless this was hinted.
+ *
+ * We cannot postpone this until pump_messages, because
+ * after calling msg->complete (below) the driver that
+ * sent the current message could be unloaded, which
+ * could invalidate the cs_control() callback...
+ */
+
+ /* get a pointer to the next message, if any */
+ spin_lock_irqsave(&pl022->queue_lock, flags);
+ if (list_empty(&pl022->queue))
+ next_msg = NULL;
+ else
+ next_msg = list_entry(pl022->queue.next,
+ struct spi_message, queue);
+ spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+ /* see if the next and current messages point
+ * to the same chip
+ */
+ if (next_msg && next_msg->spi != msg->spi)
+ next_msg = NULL;
+ if (!next_msg || msg->state == STATE_ERROR)
+ curr_cs_control(SSP_CHIP_DESELECT);
+ }
+ msg->state = NULL;
+ if (msg->complete)
+ msg->complete(msg->context);
+ /* This message is completed, so let's turn off the clock! */
+ clk_disable(pl022->clk);
+}
+
+/**
+ * flush - flush the FIFO to reach a clean state
+ * @pl022: SSP driver private data structure
+ */
+static int flush(struct pl022 *pl022)
+{
+ unsigned long limit = loops_per_jiffy << 1;
+
+ dev_dbg(&pl022->adev->dev, "flush\n");
+ do {
+ while (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
+ readw(SSP_DR(pl022->virtbase));
+ } while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_BSY) && limit--);
+ return limit;
+}
+
+/**
+ * restore_state - Load configuration of current chip
+ * @pl022: SSP driver private data structure
+ */
+static void restore_state(struct pl022 *pl022)
+{
+ struct chip_data *chip = pl022->cur_chip;
+
+ writew(chip->cr0, SSP_CR0(pl022->virtbase));
+ writew(chip->cr1, SSP_CR1(pl022->virtbase));
+ writew(chip->dmacr, SSP_DMACR(pl022->virtbase));
+ writew(chip->cpsr, SSP_CPSR(pl022->virtbase));
+ writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+ writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
+}
+
+/**
+ * load_ssp_default_config - Load default configuration for SSP
+ * @pl022: SSP driver private data structure
+ */
+
+/*
+ * Default SSP Register Values
+ */
+#define DEFAULT_SSP_REG_CR0 ( \
+ GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS, 0) | \
+ GEN_MASK_BITS(SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, SSP_CR0_MASK_HALFDUP, 5) | \
+ GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
+ GEN_MASK_BITS(SSP_CLK_FALLING_EDGE, SSP_CR0_MASK_SPH, 7) | \
+ GEN_MASK_BITS(NMDK_SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) | \
+ GEN_MASK_BITS(SSP_BITS_8, SSP_CR0_MASK_CSS, 16) | \
+ GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF, 21) \
+)
+
+#define DEFAULT_SSP_REG_CR1 ( \
+ GEN_MASK_BITS(LOOPBACK_DISABLED, SSP_CR1_MASK_LBM, 0) | \
+ GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \
+ GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \
+ GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) | \
+ GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN, 4) | \
+ GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN, 5) | \
+ GEN_MASK_BITS(SSP_MWIRE_WAIT_ZERO, SSP_CR1_MASK_MWAIT, 6) |\
+ GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL, 7) | \
+ GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL, 10) \
+)
+
+#define DEFAULT_SSP_REG_CPSR ( \
+ GEN_MASK_BITS(NMDK_SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \
+)
+
+#define DEFAULT_SSP_REG_DMACR (\
+ GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_RXDMAE, 0) | \
+ GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_TXDMAE, 1) \
+)
+
+
+static void load_ssp_default_config(struct pl022 *pl022)
+{
+ writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase));
+ writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase));
+ writew(DEFAULT_SSP_REG_DMACR, SSP_DMACR(pl022->virtbase));
+ writew(DEFAULT_SSP_REG_CPSR, SSP_CPSR(pl022->virtbase));
+ writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+ writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
+}
+
+/**
+ * This will write to TX and read from RX according to the parameters
+ * set in pl022.
+ */
+static void readwriter(struct pl022 *pl022)
+{
+
+ /*
+ * The FIFO depth is different inbetween primecell variants.
+ * I believe filling in too much in the FIFO might cause
+ * errons in 8bit wide transfers on ARM variants (just 8 words
+ * FIFO, means only 8x8 = 64 bits in FIFO) at least.
+ *
+ * FIXME: currently we have no logic to account for this.
+ * perhaps there is even something broken in HW regarding
+ * 8bit transfers (it doesn't fail on 16bit) so this needs
+ * more investigation...
+ */
+ dev_dbg(&pl022->adev->dev,
+ "%s, rx: %p, rxend: %p, tx: %p, txend: %p\n",
+ __func__, pl022->rx, pl022->rx_end, pl022->tx, pl022->tx_end);
+
+ /* Read as much as you can */
+ while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
+ && (pl022->rx < pl022->rx_end)) {
+ switch (pl022->read) {
+ case READING_NULL:
+ readw(SSP_DR(pl022->virtbase));
+ break;
+ case READING_U8:
+ *(u8 *) (pl022->rx) =
+ readw(SSP_DR(pl022->virtbase)) & 0xFFU;
+ break;
+ case READING_U16:
+ *(u16 *) (pl022->rx) =
+ (u16) readw(SSP_DR(pl022->virtbase));
+ break;
+ case READING_U32:
+ *(u32 *) (pl022->rx) =
+ readl(SSP_DR(pl022->virtbase));
+ break;
+ }
+ pl022->rx += (pl022->cur_chip->n_bytes);
+ }
+ /*
+ * Write as much as you can, while keeping an eye on the RX FIFO!
+ */
+ while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
+ && (pl022->tx < pl022->tx_end)) {
+ switch (pl022->write) {
+ case WRITING_NULL:
+ writew(0x0, SSP_DR(pl022->virtbase));
+ break;
+ case WRITING_U8:
+ writew(*(u8 *) (pl022->tx), SSP_DR(pl022->virtbase));
+ break;
+ case WRITING_U16:
+ writew((*(u16 *) (pl022->tx)), SSP_DR(pl022->virtbase));
+ break;
+ case WRITING_U32:
+ writel(*(u32 *) (pl022->tx), SSP_DR(pl022->virtbase));
+ break;
+ }
+ pl022->tx += (pl022->cur_chip->n_bytes);
+ /*
+ * This inner reader takes care of things appearing in the RX
+ * FIFO as we're transmitting. This will happen a lot since the
+ * clock starts running when you put things into the TX FIFO,
+ * and then things are continously clocked into the RX FIFO.
+ */
+ while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
+ && (pl022->rx < pl022->rx_end)) {
+ switch (pl022->read) {
+ case READING_NULL:
+ readw(SSP_DR(pl022->virtbase));
+ break;
+ case READING_U8:
+ *(u8 *) (pl022->rx) =
+ readw(SSP_DR(pl022->virtbase)) & 0xFFU;
+ break;
+ case READING_U16:
+ *(u16 *) (pl022->rx) =
+ (u16) readw(SSP_DR(pl022->virtbase));
+ break;
+ case READING_U32:
+ *(u32 *) (pl022->rx) =
+ readl(SSP_DR(pl022->virtbase));
+ break;
+ }
+ pl022->rx += (pl022->cur_chip->n_bytes);
+ }
+ }
+ /*
+ * When we exit here the TX FIFO should be full and the RX FIFO
+ * should be empty
+ */
+}
+
+
+/**
+ * next_transfer - Move to the Next transfer in the current spi message
+ * @pl022: SSP driver private data structure
+ *
+ * This function moves though the linked list of spi transfers in the
+ * current spi message and returns with the state of current spi
+ * message i.e whether its last transfer is done(STATE_DONE) or
+ * Next transfer is ready(STATE_RUNNING)
+ */
+static void *next_transfer(struct pl022 *pl022)
+{
+ struct spi_message *msg = pl022->cur_msg;
+ struct spi_transfer *trans = pl022->cur_transfer;
+
+ /* Move to next transfer */
+ if (trans->transfer_list.next != &msg->transfers) {
+ pl022->cur_transfer =
+ list_entry(trans->transfer_list.next,
+ struct spi_transfer, transfer_list);
+ return STATE_RUNNING;
+ }
+ return STATE_DONE;
+}
+/**
+ * pl022_interrupt_handler - Interrupt handler for SSP controller
+ *
+ * This function handles interrupts generated for an interrupt based transfer.
+ * If a receive overrun (ROR) interrupt is there then we disable SSP, flag the
+ * current message's state as STATE_ERROR and schedule the tasklet
+ * pump_transfers which will do the postprocessing of the current message by
+ * calling giveback(). Otherwise it reads data from RX FIFO till there is no
+ * more data, and writes data in TX FIFO till it is not full. If we complete
+ * the transfer we move to the next transfer and schedule the tasklet.
+ */
+static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
+{
+ struct pl022 *pl022 = dev_id;
+ struct spi_message *msg = pl022->cur_msg;
+ u16 irq_status = 0;
+ u16 flag = 0;
+
+ if (unlikely(!msg)) {
+ dev_err(&pl022->adev->dev,
+ "bad message state in interrupt handler");
+ /* Never fail */
+ return IRQ_HANDLED;
+ }
+
+ /* Read the Interrupt Status Register */
+ irq_status = readw(SSP_MIS(pl022->virtbase));
+
+ if (unlikely(!irq_status))
+ return IRQ_NONE;
+
+ /* This handles the error code interrupts */
+ if (unlikely(irq_status & SSP_MIS_MASK_RORMIS)) {
+ /*
+ * Overrun interrupt - bail out since our Data has been
+ * corrupted
+ */
+ dev_err(&pl022->adev->dev,
+ "FIFO overrun\n");
+ if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF)
+ dev_err(&pl022->adev->dev,
+ "RXFIFO is full\n");
+ if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
+ dev_err(&pl022->adev->dev,
+ "TXFIFO is full\n");
+
+ /*
+ * Disable and clear interrupts, disable SSP,
+ * mark message with bad status so it can be
+ * retried.
+ */
+ writew(DISABLE_ALL_INTERRUPTS,
+ SSP_IMSC(pl022->virtbase));
+ writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
+ writew((readw(SSP_CR1(pl022->virtbase)) &
+ (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
+ msg->state = STATE_ERROR;
+
+ /* Schedule message queue handler */
+ tasklet_schedule(&pl022->pump_transfers);
+ return IRQ_HANDLED;
+ }
+
+ readwriter(pl022);
+
+ if ((pl022->tx == pl022->tx_end) && (flag == 0)) {
+ flag = 1;
+ /* Disable Transmit interrupt */
+ writew(readw(SSP_IMSC(pl022->virtbase)) &
+ (~SSP_IMSC_MASK_TXIM),
+ SSP_IMSC(pl022->virtbase));
+ }
+
+ /*
+ * Since all transactions must write as much as shall be read,
+ * we can conclude the entire transaction once RX is complete.
+ * At this point, all TX will always be finished.
+ */
+ if (pl022->rx >= pl022->rx_end) {
+ writew(DISABLE_ALL_INTERRUPTS,
+ SSP_IMSC(pl022->virtbase));
+ writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
+ if (unlikely(pl022->rx > pl022->rx_end)) {
+ dev_warn(&pl022->adev->dev, "read %u surplus "
+ "bytes (did you request an odd "
+ "number of bytes on a 16bit bus?)\n",
+ (u32) (pl022->rx - pl022->rx_end));
+ }
+ /* Update total bytes transfered */
+ msg->actual_length += pl022->cur_transfer->len;
+ if (pl022->cur_transfer->cs_change)
+ pl022->cur_chip->
+ cs_control(SSP_CHIP_DESELECT);
+ /* Move to next transfer */
+ msg->state = next_transfer(pl022);
+ tasklet_schedule(&pl022->pump_transfers);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * This sets up the pointers to memory for the next message to
+ * send out on the SPI bus.
+ */
+static int set_up_next_transfer(struct pl022 *pl022,
+ struct spi_transfer *transfer)
+{
+ int residue;
+
+ /* Sanity check the message for this bus width */
+ residue = pl022->cur_transfer->len % pl022->cur_chip->n_bytes;
+ if (unlikely(residue != 0)) {
+ dev_err(&pl022->adev->dev,
+ "message of %u bytes to transmit but the current "
+ "chip bus has a data width of %u bytes!\n",
+ pl022->cur_transfer->len,
+ pl022->cur_chip->n_bytes);
+ dev_err(&pl022->adev->dev, "skipping this message\n");
+ return -EIO;
+ }
+ pl022->tx = (void *)transfer->tx_buf;
+ pl022->tx_end = pl022->tx + pl022->cur_transfer->len;
+ pl022->rx = (void *)transfer->rx_buf;
+ pl022->rx_end = pl022->rx + pl022->cur_transfer->len;
+ pl022->write =
+ pl022->tx ? pl022->cur_chip->write : WRITING_NULL;
+ pl022->read = pl022->rx ? pl022->cur_chip->read : READING_NULL;
+ return 0;
+}
+
+/**
+ * pump_transfers - Tasklet function which schedules next interrupt transfer
+ * when running in interrupt transfer mode.
+ * @data: SSP driver private data structure
+ *
+ */
+static void pump_transfers(unsigned long data)
+{
+ struct pl022 *pl022 = (struct pl022 *) data;
+ struct spi_message *message = NULL;
+ struct spi_transfer *transfer = NULL;
+ struct spi_transfer *previous = NULL;
+
+ /* Get current state information */
+ message = pl022->cur_msg;
+ transfer = pl022->cur_transfer;
+
+ /* Handle for abort */
+ if (message->state == STATE_ERROR) {
+ message->status = -EIO;
+ giveback(pl022);
+ return;
+ }
+
+ /* Handle end of message */
+ if (message->state == STATE_DONE) {
+ message->status = 0;
+ giveback(pl022);
+ return;
+ }
+
+ /* Delay if requested at end of transfer before CS change */
+ if (message->state == STATE_RUNNING) {
+ previous = list_entry(transfer->transfer_list.prev,
+ struct spi_transfer,
+ transfer_list);
+ if (previous->delay_usecs)
+ /*
+ * FIXME: This runs in interrupt context.
+ * Is this really smart?
+ */
+ udelay(previous->delay_usecs);
+
+ /* Drop chip select only if cs_change is requested */
+ if (previous->cs_change)
+ pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+ } else {
+ /* STATE_START */
+ message->state = STATE_RUNNING;
+ }
+
+ if (set_up_next_transfer(pl022, transfer)) {
+ message->state = STATE_ERROR;
+ message->status = -EIO;
+ giveback(pl022);
+ return;
+ }
+ /* Flush the FIFOs and let's go! */
+ flush(pl022);
+ writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+}
+
+/**
+ * NOT IMPLEMENTED
+ * configure_dma - It configures the DMA pipes for DMA transfers
+ * @data: SSP driver's private data structure
+ *
+ */
+static int configure_dma(void *data)
+{
+ struct pl022 *pl022 = data;
+ dev_dbg(&pl022->adev->dev, "configure DMA\n");
+ return -ENOTSUPP;
+}
+
+/**
+ * do_dma_transfer - It handles transfers of the current message
+ * if it is DMA xfer.
+ * NOT FULLY IMPLEMENTED
+ * @data: SSP driver's private data structure
+ */
+static void do_dma_transfer(void *data)
+{
+ struct pl022 *pl022 = data;
+
+ if (configure_dma(data)) {
+ dev_dbg(&pl022->adev->dev, "configuration of DMA Failed!\n");
+ goto err_config_dma;
+ }
+
+ /* TODO: Implememt DMA setup of pipes here */
+
+ /* Enable target chip, set up transfer */
+ pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+ if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
+ /* Error path */
+ pl022->cur_msg->state = STATE_ERROR;
+ pl022->cur_msg->status = -EIO;
+ giveback(pl022);
+ return;
+ }
+ /* Enable SSP */
+ writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
+ SSP_CR1(pl022->virtbase));
+
+ /* TODO: Enable the DMA transfer here */
+ return;
+
+ err_config_dma:
+ pl022->cur_msg->state = STATE_ERROR;
+ pl022->cur_msg->status = -EIO;
+ giveback(pl022);
+ return;
+}
+
+static void do_interrupt_transfer(void *data)
+{
+ struct pl022 *pl022 = data;
+
+ /* Enable target chip */
+ pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+ if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
+ /* Error path */
+ pl022->cur_msg->state = STATE_ERROR;
+ pl022->cur_msg->status = -EIO;
+ giveback(pl022);
+ return;
+ }
+ /* Enable SSP, turn on interrupts */
+ writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
+ SSP_CR1(pl022->virtbase));
+ writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+}
+
+static void do_polling_transfer(void *data)
+{
+ struct pl022 *pl022 = data;
+ struct spi_message *message = NULL;
+ struct spi_transfer *transfer = NULL;
+ struct spi_transfer *previous = NULL;
+ struct chip_data *chip;
+
+ chip = pl022->cur_chip;
+ message = pl022->cur_msg;
+
+ while (message->state != STATE_DONE) {
+ /* Handle for abort */
+ if (message->state == STATE_ERROR)
+ break;
+ transfer = pl022->cur_transfer;
+
+ /* Delay if requested at end of transfer */
+ if (message->state == STATE_RUNNING) {
+ previous =
+ list_entry(transfer->transfer_list.prev,
+ struct spi_transfer, transfer_list);
+ if (previous->delay_usecs)
+ udelay(previous->delay_usecs);
+ if (previous->cs_change)
+ pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+ } else {
+ /* STATE_START */
+ message->state = STATE_RUNNING;
+ pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+ }
+
+ /* Configuration Changing Per Transfer */
+ if (set_up_next_transfer(pl022, transfer)) {
+ /* Error path */
+ message->state = STATE_ERROR;
+ break;
+ }
+ /* Flush FIFOs and enable SSP */
+ flush(pl022);
+ writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
+ SSP_CR1(pl022->virtbase));
+
+ dev_dbg(&pl022->adev->dev, "POLLING TRANSFER ONGOING ... \n");
+ /* FIXME: insert a timeout so we don't hang here indefinately */
+ while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end)
+ readwriter(pl022);
+
+ /* Update total byte transfered */
+ message->actual_length += pl022->cur_transfer->len;
+ if (pl022->cur_transfer->cs_change)
+ pl022->cur_chip->cs_control(SSP_CHIP_DESELECT);
+ /* Move to next transfer */
+ message->state = next_transfer(pl022);
+ }
+
+ /* Handle end of message */
+ if (message->state == STATE_DONE)
+ message->status = 0;
+ else
+ message->status = -EIO;
+
+ giveback(pl022);
+ return;
+}
+
+/**
+ * pump_messages - Workqueue function which processes spi message queue
+ * @data: pointer to private data of SSP driver
+ *
+ * This function checks if there is any spi message in the queue that
+ * needs processing and delegate control to appropriate function
+ * do_polling_transfer()/do_interrupt_transfer()/do_dma_transfer()
+ * based on the kind of the transfer
+ *
+ */
+static void pump_messages(struct work_struct *work)
+{
+ struct pl022 *pl022 =
+ container_of(work, struct pl022, pump_messages);
+ unsigned long flags;
+
+ /* Lock queue and check for queue work */
+ spin_lock_irqsave(&pl022->queue_lock, flags);
+ if (list_empty(&pl022->queue) || pl022->run == QUEUE_STOPPED) {
+ pl022->busy = 0;
+ spin_unlock_irqrestore(&pl022->queue_lock, flags);
+ return;
+ }
+ /* Make sure we are not already running a message */
+ if (pl022->cur_msg) {
+ spin_unlock_irqrestore(&pl022->queue_lock, flags);
+ return;
+ }
+ /* Extract head of queue */
+ pl022->cur_msg =
+ list_entry(pl022->queue.next, struct spi_message, queue);
+
+ list_del_init(&pl022->cur_msg->queue);
+ pl022->busy = 1;
+ spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+ /* Initial message state */
+ pl022->cur_msg->state = STATE_START;
+ pl022->cur_transfer = list_entry(pl022->cur_msg->transfers.next,
+ struct spi_transfer,
+ transfer_list);
+
+ /* Setup the SPI using the per chip configuration */
+ pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi);
+ /*
+ * We enable the clock here, then the clock will be disabled when
+ * giveback() is called in each method (poll/interrupt/DMA)
+ */
+ clk_enable(pl022->clk);
+ restore_state(pl022);
+ flush(pl022);
+
+ if (pl022->cur_chip->xfer_type == POLLING_TRANSFER)
+ do_polling_transfer(pl022);
+ else if (pl022->cur_chip->xfer_type == INTERRUPT_TRANSFER)
+ do_interrupt_transfer(pl022);
+ else
+ do_dma_transfer(pl022);
+}
+
+
+static int __init init_queue(struct pl022 *pl022)
+{
+ INIT_LIST_HEAD(&pl022->queue);
+ spin_lock_init(&pl022->queue_lock);
+
+ pl022->run = QUEUE_STOPPED;
+ pl022->busy = 0;
+
+ tasklet_init(&pl022->pump_transfers,
+ pump_transfers, (unsigned long)pl022);
+
+ INIT_WORK(&pl022->pump_messages, pump_messages);
+ pl022->workqueue = create_singlethread_workqueue(
+ dev_name(pl022->master->dev.parent));
+ if (pl022->workqueue == NULL)
+ return -EBUSY;
+
+ return 0;
+}
+
+
+static int start_queue(struct pl022 *pl022)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pl022->queue_lock, flags);
+
+ if (pl022->run == QUEUE_RUNNING || pl022->busy) {
+ spin_unlock_irqrestore(&pl022->queue_lock, flags);
+ return -EBUSY;
+ }
+
+ pl022->run = QUEUE_RUNNING;
+ pl022->cur_msg = NULL;
+ pl022->cur_transfer = NULL;
+ pl022->cur_chip = NULL;
+ spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+ queue_work(pl022->workqueue, &pl022->pump_messages);
+
+ return 0;
+}
+
+
+static int stop_queue(struct pl022 *pl022)
+{
+ unsigned long flags;
+ unsigned limit = 500;
+ int status = 0;
+
+ spin_lock_irqsave(&pl022->queue_lock, flags);
+
+ /* This is a bit lame, but is optimized for the common execution path.
+ * A wait_queue on the pl022->busy could be used, but then the common
+ * execution path (pump_messages) would be required to call wake_up or
+ * friends on every SPI message. Do this instead */
+ pl022->run = QUEUE_STOPPED;
+ while (!list_empty(&pl022->queue) && pl022->busy && limit--) {
+ spin_unlock_irqrestore(&pl022->queue_lock, flags);
+ msleep(10);
+ spin_lock_irqsave(&pl022->queue_lock, flags);
+ }
+
+ if (!list_empty(&pl022->queue) || pl022->busy)
+ status = -EBUSY;
+
+ spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+ return status;
+}
+
+static int destroy_queue(struct pl022 *pl022)
+{
+ int status;
+
+ status = stop_queue(pl022);
+ /* we are unloading the module or failing to load (only two calls
+ * to this routine), and neither call can handle a return value.
+ * However, destroy_workqueue calls flush_workqueue, and that will
+ * block until all work is done. If the reason that stop_queue
+ * timed out is that the work will never finish, then it does no
+ * good to call destroy_workqueue, so return anyway. */
+ if (status != 0)
+ return status;
+
+ destroy_workqueue(pl022->workqueue);
+
+ return 0;
+}
+
+static int verify_controller_parameters(struct pl022 *pl022,
+ struct pl022_config_chip *chip_info)
+{
+ if ((chip_info->lbm != LOOPBACK_ENABLED)
+ && (chip_info->lbm != LOOPBACK_DISABLED)) {
+ dev_err(chip_info->dev,
+ "loopback Mode is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if ((chip_info->iface < SSP_INTERFACE_MOTOROLA_SPI)
+ || (chip_info->iface > SSP_INTERFACE_UNIDIRECTIONAL)) {
+ dev_err(chip_info->dev,
+ "interface is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if ((chip_info->iface == SSP_INTERFACE_UNIDIRECTIONAL) &&
+ (!pl022->vendor->unidir)) {
+ dev_err(chip_info->dev,
+ "unidirectional mode not supported in this "
+ "hardware version\n");
+ return -EINVAL;
+ }
+ if ((chip_info->hierarchy != SSP_MASTER)
+ && (chip_info->hierarchy != SSP_SLAVE)) {
+ dev_err(chip_info->dev,
+ "hierarchy is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if (((chip_info->clk_freq).cpsdvsr < CPSDVR_MIN)
+ || ((chip_info->clk_freq).cpsdvsr > CPSDVR_MAX)) {
+ dev_err(chip_info->dev,
+ "cpsdvsr is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if ((chip_info->endian_rx != SSP_RX_MSB)
+ && (chip_info->endian_rx != SSP_RX_LSB)) {
+ dev_err(chip_info->dev,
+ "RX FIFO endianess is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if ((chip_info->endian_tx != SSP_TX_MSB)
+ && (chip_info->endian_tx != SSP_TX_LSB)) {
+ dev_err(chip_info->dev,
+ "TX FIFO endianess is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if ((chip_info->data_size < SSP_DATA_BITS_4)
+ || (chip_info->data_size > SSP_DATA_BITS_32)) {
+ dev_err(chip_info->dev,
+ "DATA Size is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if ((chip_info->com_mode != INTERRUPT_TRANSFER)
+ && (chip_info->com_mode != DMA_TRANSFER)
+ && (chip_info->com_mode != POLLING_TRANSFER)) {
+ dev_err(chip_info->dev,
+ "Communication mode is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if ((chip_info->rx_lev_trig < SSP_RX_1_OR_MORE_ELEM)
+ || (chip_info->rx_lev_trig > SSP_RX_32_OR_MORE_ELEM)) {
+ dev_err(chip_info->dev,
+ "RX FIFO Trigger Level is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if ((chip_info->tx_lev_trig < SSP_TX_1_OR_MORE_EMPTY_LOC)
+ || (chip_info->tx_lev_trig > SSP_TX_32_OR_MORE_EMPTY_LOC)) {
+ dev_err(chip_info->dev,
+ "TX FIFO Trigger Level is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if (chip_info->iface == SSP_INTERFACE_MOTOROLA_SPI) {
+ if ((chip_info->clk_phase != SSP_CLK_RISING_EDGE)
+ && (chip_info->clk_phase != SSP_CLK_FALLING_EDGE)) {
+ dev_err(chip_info->dev,
+ "Clock Phase is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if ((chip_info->clk_pol != SSP_CLK_POL_IDLE_LOW)
+ && (chip_info->clk_pol != SSP_CLK_POL_IDLE_HIGH)) {
+ dev_err(chip_info->dev,
+ "Clock Polarity is configured incorrectly\n");
+ return -EINVAL;
+ }
+ }
+ if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) {
+ if ((chip_info->ctrl_len < SSP_BITS_4)
+ || (chip_info->ctrl_len > SSP_BITS_32)) {
+ dev_err(chip_info->dev,
+ "CTRL LEN is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if ((chip_info->wait_state != SSP_MWIRE_WAIT_ZERO)
+ && (chip_info->wait_state != SSP_MWIRE_WAIT_ONE)) {
+ dev_err(chip_info->dev,
+ "Wait State is configured incorrectly\n");
+ return -EINVAL;
+ }
+ if ((chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
+ && (chip_info->duplex !=
+ SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) {
+ dev_err(chip_info->dev,
+ "DUPLEX is configured incorrectly\n");
+ return -EINVAL;
+ }
+ }
+ if (chip_info->cs_control == NULL) {
+ dev_warn(chip_info->dev,
+ "Chip Select Function is NULL for this chip\n");
+ chip_info->cs_control = null_cs_control;
+ }
+ return 0;
+}
+
+/**
+ * pl022_transfer - transfer function registered to SPI master framework
+ * @spi: spi device which is requesting transfer
+ * @msg: spi message which is to handled is queued to driver queue
+ *
+ * This function is registered to the SPI framework for this SPI master
+ * controller. It will queue the spi_message in the queue of driver if
+ * the queue is not stopped and return.
+ */
+static int pl022_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct pl022 *pl022 = spi_master_get_devdata(spi->master);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pl022->queue_lock, flags);
+
+ if (pl022->run == QUEUE_STOPPED) {
+ spin_unlock_irqrestore(&pl022->queue_lock, flags);
+ return -ESHUTDOWN;
+ }
+ msg->actual_length = 0;
+ msg->status = -EINPROGRESS;
+ msg->state = STATE_START;
+
+ list_add_tail(&msg->queue, &pl022->queue);
+ if (pl022->run == QUEUE_RUNNING && !pl022->busy)
+ queue_work(pl022->workqueue, &pl022->pump_messages);
+
+ spin_unlock_irqrestore(&pl022->queue_lock, flags);
+ return 0;
+}
+
+static int calculate_effective_freq(struct pl022 *pl022,
+ int freq,
+ struct ssp_clock_params *clk_freq)
+{
+ /* Lets calculate the frequency parameters */
+ u16 cpsdvsr = 2;
+ u16 scr = 0;
+ bool freq_found = false;
+ u32 rate;
+ u32 max_tclk;
+ u32 min_tclk;
+
+ rate = clk_get_rate(pl022->clk);
+ /* cpsdvscr = 2 & scr 0 */
+ max_tclk = (rate / (CPSDVR_MIN * (1 + SCR_MIN)));
+ /* cpsdvsr = 254 & scr = 255 */
+ min_tclk = (rate / (CPSDVR_MAX * (1 + SCR_MAX)));
+
+ if ((freq <= max_tclk) && (freq >= min_tclk)) {
+ while (cpsdvsr <= CPSDVR_MAX && !freq_found) {
+ while (scr <= SCR_MAX && !freq_found) {
+ if ((rate /
+ (cpsdvsr * (1 + scr))) > freq)
+ scr += 1;
+ else {
+ /*
+ * This bool is made true when
+ * effective frequency >=
+ * target frequency is found
+ */
+ freq_found = true;
+ if ((rate /
+ (cpsdvsr * (1 + scr))) != freq) {
+ if (scr == SCR_MIN) {
+ cpsdvsr -= 2;
+ scr = SCR_MAX;
+ } else
+ scr -= 1;
+ }
+ }
+ }
+ if (!freq_found) {
+ cpsdvsr += 2;
+ scr = SCR_MIN;
+ }
+ }
+ if (cpsdvsr != 0) {
+ dev_dbg(&pl022->adev->dev,
+ "SSP Effective Frequency is %u\n",
+ (rate / (cpsdvsr * (1 + scr))));
+ clk_freq->cpsdvsr = (u8) (cpsdvsr & 0xFF);
+ clk_freq->scr = (u8) (scr & 0xFF);
+ dev_dbg(&pl022->adev->dev,
+ "SSP cpsdvsr = %d, scr = %d\n",
+ clk_freq->cpsdvsr, clk_freq->scr);
+ }
+ } else {
+ dev_err(&pl022->adev->dev,
+ "controller data is incorrect: out of range frequency");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * NOT IMPLEMENTED
+ * process_dma_info - Processes the DMA info provided by client drivers
+ * @chip_info: chip info provided by client device
+ * @chip: Runtime state maintained by the SSP controller for each spi device
+ *
+ * This function processes and stores DMA config provided by client driver
+ * into the runtime state maintained by the SSP controller driver
+ */
+static int process_dma_info(struct pl022_config_chip *chip_info,
+ struct chip_data *chip)
+{
+ dev_err(chip_info->dev,
+ "cannot process DMA info, DMA not implemented!\n");
+ return -ENOTSUPP;
+}
+
+/**
+ * pl022_setup - setup function registered to SPI master framework
+ * @spi: spi device which is requesting setup
+ *
+ * This function is registered to the SPI framework for this SPI master
+ * controller. If it is the first time when setup is called by this device,
+ * this function will initialize the runtime state for this chip and save
+ * the same in the device structure. Else it will update the runtime info
+ * with the updated chip info. Nothing is really being written to the
+ * controller hardware here, that is not done until the actual transfer
+ * commence.
+ */
+
+/* FIXME: JUST GUESSING the spi->mode bits understood by this driver */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
+ | SPI_LSB_FIRST | SPI_LOOP)
+
+static int pl022_setup(struct spi_device *spi)
+{
+ struct pl022_config_chip *chip_info;
+ struct chip_data *chip;
+ int status = 0;
+ struct pl022 *pl022 = spi_master_get_devdata(spi->master);
+
+ if (spi->mode & ~MODEBITS) {
+ dev_dbg(&spi->dev, "unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
+ if (!spi->max_speed_hz)
+ return -EINVAL;
+
+ /* Get controller_state if one is supplied */
+ chip = spi_get_ctldata(spi);
+
+ if (chip == NULL) {
+ chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+ if (!chip) {
+ dev_err(&spi->dev,
+ "cannot allocate controller state\n");
+ return -ENOMEM;
+ }
+ dev_dbg(&spi->dev,
+ "allocated memory for controller's runtime state\n");
+ }
+
+ /* Get controller data if one is supplied */
+ chip_info = spi->controller_data;
+
+ if (chip_info == NULL) {
+ /* spi_board_info.controller_data not is supplied */
+ dev_dbg(&spi->dev,
+ "using default controller_data settings\n");
+
+ chip_info =
+ kzalloc(sizeof(struct pl022_config_chip), GFP_KERNEL);
+
+ if (!chip_info) {
+ dev_err(&spi->dev,
+ "cannot allocate controller data\n");
+ status = -ENOMEM;
+ goto err_first_setup;
+ }
+
+ dev_dbg(&spi->dev, "allocated memory for controller data\n");
+
+ /* Pointer back to the SPI device */
+ chip_info->dev = &spi->dev;
+ /*
+ * Set controller data default values:
+ * Polling is supported by default
+ */
+ chip_info->lbm = LOOPBACK_DISABLED;
+ chip_info->com_mode = POLLING_TRANSFER;
+ chip_info->iface = SSP_INTERFACE_MOTOROLA_SPI;
+ chip_info->hierarchy = SSP_SLAVE;
+ chip_info->slave_tx_disable = DO_NOT_DRIVE_TX;
+ chip_info->endian_tx = SSP_TX_LSB;
+ chip_info->endian_rx = SSP_RX_LSB;
+ chip_info->data_size = SSP_DATA_BITS_12;
+ chip_info->rx_lev_trig = SSP_RX_1_OR_MORE_ELEM;
+ chip_info->tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC;
+ chip_info->clk_phase = SSP_CLK_FALLING_EDGE;
+ chip_info->clk_pol = SSP_CLK_POL_IDLE_LOW;
+ chip_info->ctrl_len = SSP_BITS_8;
+ chip_info->wait_state = SSP_MWIRE_WAIT_ZERO;
+ chip_info->duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX;
+ chip_info->cs_control = null_cs_control;
+ } else {
+ dev_dbg(&spi->dev,
+ "using user supplied controller_data settings\n");
+ }
+
+ /*
+ * We can override with custom divisors, else we use the board
+ * frequency setting
+ */
+ if ((0 == chip_info->clk_freq.cpsdvsr)
+ && (0 == chip_info->clk_freq.scr)) {
+ status = calculate_effective_freq(pl022,
+ spi->max_speed_hz,
+ &chip_info->clk_freq);
+ if (status < 0)
+ goto err_config_params;
+ } else {
+ if ((chip_info->clk_freq.cpsdvsr % 2) != 0)
+ chip_info->clk_freq.cpsdvsr =
+ chip_info->clk_freq.cpsdvsr - 1;
+ }
+ status = verify_controller_parameters(pl022, chip_info);
+ if (status) {
+ dev_err(&spi->dev, "controller data is incorrect");
+ goto err_config_params;
+ }
+ /* Now set controller state based on controller data */
+ chip->xfer_type = chip_info->com_mode;
+ chip->cs_control = chip_info->cs_control;
+
+ if (chip_info->data_size <= 8) {
+ dev_dbg(&spi->dev, "1 <= n <=8 bits per word\n");
+ chip->n_bytes = 1;
+ chip->read = READING_U8;
+ chip->write = WRITING_U8;
+ } else if (chip_info->data_size <= 16) {
+ dev_dbg(&spi->dev, "9 <= n <= 16 bits per word\n");
+ chip->n_bytes = 2;
+ chip->read = READING_U16;
+ chip->write = WRITING_U16;
+ } else {
+ if (pl022->vendor->max_bpw >= 32) {
+ dev_dbg(&spi->dev, "17 <= n <= 32 bits per word\n");
+ chip->n_bytes = 4;
+ chip->read = READING_U32;
+ chip->write = WRITING_U32;
+ } else {
+ dev_err(&spi->dev,
+ "illegal data size for this controller!\n");
+ dev_err(&spi->dev,
+ "a standard pl022 can only handle "
+ "1 <= n <= 16 bit words\n");
+ goto err_config_params;
+ }
+ }
+
+ /* Now Initialize all register settings required for this chip */
+ chip->cr0 = 0;
+ chip->cr1 = 0;
+ chip->dmacr = 0;
+ chip->cpsr = 0;
+ if ((chip_info->com_mode == DMA_TRANSFER)
+ && ((pl022->master_info)->enable_dma)) {
+ chip->enable_dma = 1;
+ dev_dbg(&spi->dev, "DMA mode set in controller state\n");
+ status = process_dma_info(chip_info, chip);
+ if (status < 0)
+ goto err_config_params;
+ SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
+ SSP_DMACR_MASK_RXDMAE, 0);
+ SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
+ SSP_DMACR_MASK_TXDMAE, 1);
+ } else {
+ chip->enable_dma = 0;
+ dev_dbg(&spi->dev, "DMA mode NOT set in controller state\n");
+ SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED,
+ SSP_DMACR_MASK_RXDMAE, 0);
+ SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED,
+ SSP_DMACR_MASK_TXDMAE, 1);
+ }
+
+ chip->cpsr = chip_info->clk_freq.cpsdvsr;
+
+ SSP_WRITE_BITS(chip->cr0, chip_info->data_size, SSP_CR0_MASK_DSS, 0);
+ SSP_WRITE_BITS(chip->cr0, chip_info->duplex, SSP_CR0_MASK_HALFDUP, 5);
+ SSP_WRITE_BITS(chip->cr0, chip_info->clk_pol, SSP_CR0_MASK_SPO, 6);
+ SSP_WRITE_BITS(chip->cr0, chip_info->clk_phase, SSP_CR0_MASK_SPH, 7);
+ SSP_WRITE_BITS(chip->cr0, chip_info->clk_freq.scr, SSP_CR0_MASK_SCR, 8);
+ SSP_WRITE_BITS(chip->cr0, chip_info->ctrl_len, SSP_CR0_MASK_CSS, 16);
+ SSP_WRITE_BITS(chip->cr0, chip_info->iface, SSP_CR0_MASK_FRF, 21);
+ SSP_WRITE_BITS(chip->cr1, chip_info->lbm, SSP_CR1_MASK_LBM, 0);
+ SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1);
+ SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2);
+ SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3);
+ SSP_WRITE_BITS(chip->cr1, chip_info->endian_rx, SSP_CR1_MASK_RENDN, 4);
+ SSP_WRITE_BITS(chip->cr1, chip_info->endian_tx, SSP_CR1_MASK_TENDN, 5);
+ SSP_WRITE_BITS(chip->cr1, chip_info->wait_state, SSP_CR1_MASK_MWAIT, 6);
+ SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig, SSP_CR1_MASK_RXIFLSEL, 7);
+ SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig, SSP_CR1_MASK_TXIFLSEL, 10);
+
+ /* Save controller_state */
+ spi_set_ctldata(spi, chip);
+ return status;
+ err_config_params:
+ err_first_setup:
+ kfree(chip);
+ return status;
+}
+
+/**
+ * pl022_cleanup - cleanup function registered to SPI master framework
+ * @spi: spi device which is requesting cleanup
+ *
+ * This function is registered to the SPI framework for this SPI master
+ * controller. It will free the runtime state of chip.
+ */
+static void pl022_cleanup(struct spi_device *spi)
+{
+ struct chip_data *chip = spi_get_ctldata(spi);
+
+ spi_set_ctldata(spi, NULL);
+ kfree(chip);
+}
+
+
+static int __init
+pl022_probe(struct amba_device *adev, struct amba_id *id)
+{
+ struct device *dev = &adev->dev;
+ struct pl022_ssp_controller *platform_info = adev->dev.platform_data;
+ struct spi_master *master;
+ struct pl022 *pl022 = NULL; /*Data for this driver */
+ int status = 0;
+
+ dev_info(&adev->dev,
+ "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid);
+ if (platform_info == NULL) {
+ dev_err(&adev->dev, "probe - no platform data supplied\n");
+ status = -ENODEV;
+ goto err_no_pdata;
+ }
+
+ /* Allocate master with space for data */
+ master = spi_alloc_master(dev, sizeof(struct pl022));
+ if (master == NULL) {
+ dev_err(&adev->dev, "probe - cannot alloc SPI master\n");
+ status = -ENOMEM;
+ goto err_no_master;
+ }
+
+ pl022 = spi_master_get_devdata(master);
+ pl022->master = master;
+ pl022->master_info = platform_info;
+ pl022->adev = adev;
+ pl022->vendor = id->data;
+
+ /*
+ * Bus Number Which has been Assigned to this SSP controller
+ * on this board
+ */
+ master->bus_num = platform_info->bus_id;
+ master->num_chipselect = platform_info->num_chipselect;
+ master->cleanup = pl022_cleanup;
+ master->setup = pl022_setup;
+ master->transfer = pl022_transfer;
+
+ dev_dbg(&adev->dev, "BUSNO: %d\n", master->bus_num);
+
+ status = amba_request_regions(adev, NULL);
+ if (status)
+ goto err_no_ioregion;
+
+ pl022->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
+ if (pl022->virtbase == NULL) {
+ status = -ENOMEM;
+ goto err_no_ioremap;
+ }
+ printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n",
+ adev->res.start, pl022->virtbase);
+
+ pl022->clk = clk_get(&adev->dev, NULL);
+ if (IS_ERR(pl022->clk)) {
+ status = PTR_ERR(pl022->clk);
+ dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n");
+ goto err_no_clk;
+ }
+
+ /* Disable SSP */
+ clk_enable(pl022->clk);
+ writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
+ SSP_CR1(pl022->virtbase));
+ load_ssp_default_config(pl022);
+ clk_disable(pl022->clk);
+
+ status = request_irq(adev->irq[0], pl022_interrupt_handler, 0, "pl022",
+ pl022);
+ if (status < 0) {
+ dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status);
+ goto err_no_irq;
+ }
+ /* Initialize and start queue */
+ status = init_queue(pl022);
+ if (status != 0) {
+ dev_err(&adev->dev, "probe - problem initializing queue\n");
+ goto err_init_queue;
+ }
+ status = start_queue(pl022);
+ if (status != 0) {
+ dev_err(&adev->dev, "probe - problem starting queue\n");
+ goto err_start_queue;
+ }
+ /* Register with the SPI framework */
+ amba_set_drvdata(adev, pl022);
+ status = spi_register_master(master);
+ if (status != 0) {
+ dev_err(&adev->dev,
+ "probe - problem registering spi master\n");
+ goto err_spi_register;
+ }
+ dev_dbg(dev, "probe succeded\n");
+ return 0;
+
+ err_spi_register:
+ err_start_queue:
+ err_init_queue:
+ destroy_queue(pl022);
+ free_irq(adev->irq[0], pl022);
+ err_no_irq:
+ clk_put(pl022->clk);
+ err_no_clk:
+ iounmap(pl022->virtbase);
+ err_no_ioremap:
+ amba_release_regions(adev);
+ err_no_ioregion:
+ spi_master_put(master);
+ err_no_master:
+ err_no_pdata:
+ return status;
+}
+
+static int __exit
+pl022_remove(struct amba_device *adev)
+{
+ struct pl022 *pl022 = amba_get_drvdata(adev);
+ int status = 0;
+ if (!pl022)
+ return 0;
+
+ /* Remove the queue */
+ status = destroy_queue(pl022);
+ if (status != 0) {
+ dev_err(&adev->dev,
+ "queue remove failed (%d)\n", status);
+ return status;
+ }
+ load_ssp_default_config(pl022);
+ free_irq(adev->irq[0], pl022);
+ clk_disable(pl022->clk);
+ clk_put(pl022->clk);
+ iounmap(pl022->virtbase);
+ amba_release_regions(adev);
+ tasklet_disable(&pl022->pump_transfers);
+ spi_unregister_master(pl022->master);
+ spi_master_put(pl022->master);
+ amba_set_drvdata(adev, NULL);
+ dev_dbg(&adev->dev, "remove succeded\n");
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int pl022_suspend(struct amba_device *adev, pm_message_t state)
+{
+ struct pl022 *pl022 = amba_get_drvdata(adev);
+ int status = 0;
+
+ status = stop_queue(pl022);
+ if (status) {
+ dev_warn(&adev->dev, "suspend cannot stop queue\n");
+ return status;
+ }
+
+ clk_enable(pl022->clk);
+ load_ssp_default_config(pl022);
+ clk_disable(pl022->clk);
+ dev_dbg(&adev->dev, "suspended\n");
+ return 0;
+}
+
+static int pl022_resume(struct amba_device *adev)
+{
+ struct pl022 *pl022 = amba_get_drvdata(adev);
+ int status = 0;
+
+ /* Start the queue running */
+ status = start_queue(pl022);
+ if (status)
+ dev_err(&adev->dev, "problem starting queue (%d)\n", status);
+ else
+ dev_dbg(&adev->dev, "resumed\n");
+
+ return status;
+}
+#else
+#define pl022_suspend NULL
+#define pl022_resume NULL
+#endif /* CONFIG_PM */
+
+static struct vendor_data vendor_arm = {
+ .fifodepth = 8,
+ .max_bpw = 16,
+ .unidir = false,
+};
+
+
+static struct vendor_data vendor_st = {
+ .fifodepth = 32,
+ .max_bpw = 32,
+ .unidir = false,
+};
+
+static struct amba_id pl022_ids[] = {
+ {
+ /*
+ * ARM PL022 variant, this has a 16bit wide
+ * and 8 locations deep TX/RX FIFO
+ */
+ .id = 0x00041022,
+ .mask = 0x000fffff,
+ .data = &vendor_arm,
+ },
+ {
+ /*
+ * ST Micro derivative, this has 32bit wide
+ * and 32 locations deep TX/RX FIFO
+ */
+ .id = 0x00108022,
+ .mask = 0xffffffff,
+ .data = &vendor_st,
+ },
+ { 0, 0 },
+};
+
+static struct amba_driver pl022_driver = {
+ .drv = {
+ .name = "ssp-pl022",
+ },
+ .id_table = pl022_ids,
+ .probe = pl022_probe,
+ .remove = __exit_p(pl022_remove),
+ .suspend = pl022_suspend,
+ .resume = pl022_resume,
+};
+
+
+static int __init pl022_init(void)
+{
+ return amba_driver_register(&pl022_driver);
+}
+
+module_init(pl022_init);
+
+static void __exit pl022_exit(void)
+{
+ amba_driver_unregister(&pl022_driver);
+}
+
+module_exit(pl022_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
+MODULE_DESCRIPTION("PL022 SSP Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 12e443cc4ac..f5b3fdbb1e2 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -530,9 +530,6 @@ atmel_spi_interrupt(int irq, void *dev_id)
return ret;
}
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
-
static int atmel_spi_setup(struct spi_device *spi)
{
struct atmel_spi *as;
@@ -555,8 +552,6 @@ static int atmel_spi_setup(struct spi_device *spi)
return -EINVAL;
}
- if (bits == 0)
- bits = 8;
if (bits < 8 || bits > 16) {
dev_dbg(&spi->dev,
"setup: invalid bits_per_word %u (8 to 16)\n",
@@ -564,12 +559,6 @@ static int atmel_spi_setup(struct spi_device *spi)
return -EINVAL;
}
- if (spi->mode & ~MODEBITS) {
- dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
- spi->mode & ~MODEBITS);
- return -EINVAL;
- }
-
/* see notes above re chipselect */
if (!atmel_spi_is_v2()
&& spi->chip_select == 0
@@ -775,6 +764,9 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
if (!master)
goto out_free;
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
master->bus_num = pdev->id;
master->num_chipselect = 4;
master->setup = atmel_spi_setup;
diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c
index b02f25c702f..76cbc1a6659 100644
--- a/drivers/spi/au1550_spi.c
+++ b/drivers/spi/au1550_spi.c
@@ -284,27 +284,16 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
return 0;
}
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST)
-
static int au1550_spi_setup(struct spi_device *spi)
{
struct au1550_spi *hw = spi_master_get_devdata(spi->master);
- if (spi->bits_per_word == 0)
- spi->bits_per_word = 8;
if (spi->bits_per_word < 4 || spi->bits_per_word > 24) {
dev_err(&spi->dev, "setup: invalid bits_per_word=%d\n",
spi->bits_per_word);
return -EINVAL;
}
- if (spi->mode & ~MODEBITS) {
- dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
- spi->mode & ~MODEBITS);
- return -EINVAL;
- }
-
if (spi->max_speed_hz == 0)
spi->max_speed_hz = hw->freq_max;
if (spi->max_speed_hz > hw->freq_max
@@ -781,6 +770,9 @@ static int __init au1550_spi_probe(struct platform_device *pdev)
goto err_nomem;
}
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+
hw = spi_master_get_devdata(master);
hw->master = spi_master_get(master);
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
index 68c77a91159..1b74d5ca03f 100644
--- a/drivers/spi/mpc52xx_psc_spi.c
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/types.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/of_platform.h>
@@ -30,8 +31,7 @@
struct mpc52xx_psc_spi {
/* fsl_spi_platform data */
- void (*activate_cs)(u8, u8);
- void (*deactivate_cs)(u8, u8);
+ void (*cs_control)(struct spi_device *spi, bool on);
u32 sysclk;
/* driver internal data */
@@ -111,18 +111,16 @@ static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi)
out_be16((u16 __iomem *)&psc->ccr, ccr);
mps->bits_per_word = cs->bits_per_word;
- if (mps->activate_cs)
- mps->activate_cs(spi->chip_select,
- (spi->mode & SPI_CS_HIGH) ? 1 : 0);
+ if (mps->cs_control)
+ mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0);
}
static void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi)
{
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
- if (mps->deactivate_cs)
- mps->deactivate_cs(spi->chip_select,
- (spi->mode & SPI_CS_HIGH) ? 1 : 0);
+ if (mps->cs_control)
+ mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1);
}
#define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1)
@@ -261,9 +259,6 @@ static void mpc52xx_psc_spi_work(struct work_struct *work)
spin_unlock_irq(&mps->lock);
}
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST)
-
static int mpc52xx_psc_spi_setup(struct spi_device *spi)
{
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
@@ -273,12 +268,6 @@ static int mpc52xx_psc_spi_setup(struct spi_device *spi)
if (spi->bits_per_word%8)
return -EINVAL;
- if (spi->mode & ~MODEBITS) {
- dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
- spi->mode & ~MODEBITS);
- return -EINVAL;
- }
-
if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs)
@@ -385,18 +374,19 @@ static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
dev_set_drvdata(dev, master);
mps = spi_master_get_devdata(master);
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+
mps->irq = irq;
if (pdata == NULL) {
dev_warn(dev, "probe called without platform data, no "
- "(de)activate_cs function will be called\n");
- mps->activate_cs = NULL;
- mps->deactivate_cs = NULL;
+ "cs_control function will be called\n");
+ mps->cs_control = NULL;
mps->sysclk = 0;
master->bus_num = bus_num;
master->num_chipselect = 255;
} else {
- mps->activate_cs = pdata->activate_cs;
- mps->deactivate_cs = pdata->deactivate_cs;
+ mps->cs_control = pdata->cs_control;
mps->sysclk = pdata->sysclk;
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->max_chipselect;
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index d6d0c5d241c..eee4b6e0af2 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -603,9 +603,6 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
return 0;
}
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
-
static int omap2_mcspi_setup(struct spi_device *spi)
{
int ret;
@@ -613,15 +610,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
struct omap2_mcspi_dma *mcspi_dma;
struct omap2_mcspi_cs *cs = spi->controller_state;
- if (spi->mode & ~MODEBITS) {
- dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
- spi->mode & ~MODEBITS);
- return -EINVAL;
- }
-
- if (spi->bits_per_word == 0)
- spi->bits_per_word = 8;
- else if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
+ if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
dev_dbg(&spi->dev, "setup: unsupported %d bit words\n",
spi->bits_per_word);
return -EINVAL;
@@ -984,6 +973,9 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
if (pdev->id != -1)
master->bus_num = pdev->id;
diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c
index fe8b9ac0cce..8980a5640bd 100644
--- a/drivers/spi/omap_uwire.c
+++ b/drivers/spi/omap_uwire.c
@@ -339,8 +339,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
bits = spi->bits_per_word;
if (t != NULL && t->bits_per_word)
bits = t->bits_per_word;
- if (!bits)
- bits = 8;
if (bits > 16) {
pr_debug("%s: wordsize %d?\n", dev_name(&spi->dev), bits);
@@ -449,19 +447,10 @@ done:
return status;
}
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
-
static int uwire_setup(struct spi_device *spi)
{
struct uwire_state *ust = spi->controller_state;
- if (spi->mode & ~MODEBITS) {
- dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
- spi->mode & ~MODEBITS);
- return -EINVAL;
- }
-
if (ust == NULL) {
ust = kzalloc(sizeof(*ust), GFP_KERNEL);
if (ust == NULL)
@@ -522,6 +511,11 @@ static int __init uwire_probe(struct platform_device *pdev)
uwire_write_reg(UWIRE_SR3, 1);
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
+ master->flags = SPI_MASTER_HALF_DUPLEX;
+
master->bus_num = 2; /* "official" */
master->num_chipselect = 4;
master->setup = uwire_setup;
diff --git a/drivers/spi/orion_spi.c b/drivers/spi/orion_spi.c
index c8b0babdc2a..3aea50da7b2 100644
--- a/drivers/spi/orion_spi.c
+++ b/drivers/spi/orion_spi.c
@@ -358,20 +358,11 @@ static int orion_spi_setup(struct spi_device *spi)
orion_spi = spi_master_get_devdata(spi->master);
- if (spi->mode) {
- dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
- spi->mode);
- return -EINVAL;
- }
-
/* Fix ac timing if required. */
if (orion_spi->spi_info->enable_clock_fix)
orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
(1 << 14));
- if (spi->bits_per_word == 0)
- spi->bits_per_word = 8;
-
if ((spi->max_speed_hz == 0)
|| (spi->max_speed_hz > orion_spi->max_speed))
spi->max_speed_hz = orion_spi->max_speed;
@@ -476,6 +467,9 @@ static int __init orion_spi_probe(struct platform_device *pdev)
if (pdev->id != -1)
master->bus_num = pdev->id;
+ /* we support only mode 0, and no options */
+ master->mode_bits = 0;
+
master->setup = orion_spi_setup;
master->transfer = orion_spi_transfer;
master->num_chipselect = ORION_NUM_CHIPSELECTS;
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 3f3c08c6ba4..d949dbf1141 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -1185,9 +1185,6 @@ static int transfer(struct spi_device *spi, struct spi_message *msg)
return 0;
}
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA)
-
static int setup_cs(struct spi_device *spi, struct chip_data *chip,
struct pxa2xx_spi_chip *chip_info)
{
@@ -1236,9 +1233,6 @@ static int setup(struct spi_device *spi)
uint tx_thres = TX_THRESH_DFLT;
uint rx_thres = RX_THRESH_DFLT;
- if (!spi->bits_per_word)
- spi->bits_per_word = 8;
-
if (drv_data->ssp_type != PXA25x_SSP
&& (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
@@ -1255,12 +1249,6 @@ static int setup(struct spi_device *spi)
return -EINVAL;
}
- if (spi->mode & ~MODEBITS) {
- dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
- spi->mode & ~MODEBITS);
- return -EINVAL;
- }
-
/* Only alloc on first setup */
chip = spi_get_ctldata(spi);
if (!chip) {
@@ -1328,18 +1316,14 @@ static int setup(struct spi_device *spi)
/* NOTE: PXA25x_SSP _could_ use external clocking ... */
if (drv_data->ssp_type != PXA25x_SSP)
- dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d, %s\n",
- spi->bits_per_word,
+ dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
clk_get_rate(ssp->clk)
/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
- spi->mode & 0x3,
chip->enable_dma ? "DMA" : "PIO");
else
- dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d, %s\n",
- spi->bits_per_word,
+ dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
clk_get_rate(ssp->clk) / 2
/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
- spi->mode & 0x3,
chip->enable_dma ? "DMA" : "PIO");
if (spi->bits_per_word <= 8) {
@@ -1500,6 +1484,9 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->pdev = pdev;
drv_data->ssp = ssp;
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
master->bus_num = pdev->id;
master->num_chipselect = platform_info->num_chipselect;
master->dma_alignment = DMA_ALIGNMENT;
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 8eba98c8ed1..70845ccd85c 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -265,7 +265,7 @@ int spi_add_device(struct spi_device *spi)
* normally rely on the device being setup. Devices
* using SPI_CS_HIGH can't coexist well otherwise...
*/
- status = spi->master->setup(spi);
+ status = spi_setup(spi);
if (status < 0) {
dev_err(dev, "can't %s %s, status %d\n",
"setup", dev_name(&spi->dev), status);
@@ -583,6 +583,70 @@ EXPORT_SYMBOL_GPL(spi_busnum_to_master);
/*-------------------------------------------------------------------------*/
+/* Core methods for SPI master protocol drivers. Some of the
+ * other core methods are currently defined as inline functions.
+ */
+
+/**
+ * spi_setup - setup SPI mode and clock rate
+ * @spi: the device whose settings are being modified
+ * Context: can sleep, and no requests are queued to the device
+ *
+ * SPI protocol drivers may need to update the transfer mode if the
+ * device doesn't work with its default. They may likewise need
+ * to update clock rates or word sizes from initial values. This function
+ * changes those settings, and must be called from a context that can sleep.
+ * Except for SPI_CS_HIGH, which takes effect immediately, the changes take
+ * effect the next time the device is selected and data is transferred to
+ * or from it. When this function returns, the spi device is deselected.
+ *
+ * Note that this call will fail if the protocol driver specifies an option
+ * that the underlying controller or its driver does not support. For
+ * example, not all hardware supports wire transfers using nine bit words,
+ * LSB-first wire encoding, or active-high chipselects.
+ */
+int spi_setup(struct spi_device *spi)
+{
+ unsigned bad_bits;
+ int status;
+
+ /* help drivers fail *cleanly* when they need options
+ * that aren't supported with their current master
+ */
+ bad_bits = spi->mode & ~spi->master->mode_bits;
+ if (bad_bits) {
+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ bad_bits);
+ return -EINVAL;
+ }
+
+ if (!spi->bits_per_word)
+ spi->bits_per_word = 8;
+
+ status = spi->master->setup(spi);
+
+ dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s"
+ "%u bits/w, %u Hz max --> %d\n",
+ (int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
+ (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
+ (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
+ (spi->mode & SPI_3WIRE) ? "3wire, " : "",
+ (spi->mode & SPI_LOOP) ? "loopback, " : "",
+ spi->bits_per_word, spi->max_speed_hz,
+ status);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(spi_setup);
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Utility methods for SPI master protocol drivers, layered on
+ * top of the core. Some other utility methods are defined as
+ * inline functions.
+ */
+
static void spi_complete(void *arg)
{
complete(arg);
@@ -636,8 +700,8 @@ static u8 *buf;
* @spi: device with which data will be exchanged
* @txbuf: data to be written (need not be dma-safe)
* @n_tx: size of txbuf, in bytes
- * @rxbuf: buffer into which data will be read
- * @n_rx: size of rxbuf, in bytes (need not be dma-safe)
+ * @rxbuf: buffer into which data will be read (need not be dma-safe)
+ * @n_rx: size of rxbuf, in bytes
* Context: can sleep
*
* This performs a half duplex MicroWire style transaction with the
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index f014cc21e81..73e24ef5a2f 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -169,7 +169,7 @@ static int bfin_spi_flush(struct driver_data *drv_data)
unsigned long limit = loops_per_jiffy << 1;
/* wait for stop and clear stat */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF) && limit--)
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF) && --limit)
cpu_relax();
write_STAT(drv_data, BIT_STAT_CLR);
@@ -803,7 +803,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
drv_data->rx, drv_data->len_in_bytes);
/* invalidate caches, if needed */
- if (bfin_addr_dcachable((unsigned long) drv_data->rx))
+ if (bfin_addr_dcacheable((unsigned long) drv_data->rx))
invalidate_dcache_range((unsigned long) drv_data->rx,
(unsigned long) (drv_data->rx +
drv_data->len_in_bytes));
@@ -816,7 +816,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
/* flush caches, if needed */
- if (bfin_addr_dcachable((unsigned long) drv_data->tx))
+ if (bfin_addr_dcacheable((unsigned long) drv_data->tx))
flush_dcache_range((unsigned long) drv_data->tx,
(unsigned long) (drv_data->tx +
drv_data->len_in_bytes));
@@ -1010,16 +1010,6 @@ static int bfin_spi_setup(struct spi_device *spi)
struct driver_data *drv_data = spi_master_get_devdata(spi->master);
int ret;
- /* Abort device setup if requested features are not supported */
- if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
- dev_err(&spi->dev, "requested mode not fully supported\n");
- return -EINVAL;
- }
-
- /* Zero (the default) here means 8 bits */
- if (!spi->bits_per_word)
- spi->bits_per_word = 8;
-
if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
return -EINVAL;
@@ -1287,6 +1277,9 @@ static int __init bfin_spi_probe(struct platform_device *pdev)
drv_data->pdev = pdev;
drv_data->pin_req = platform_info->pin_req;
+ /* the spi->mode bits supported by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+
master->bus_num = pdev->id;
master->num_chipselect = platform_info->num_chipselect;
master->cleanup = bfin_spi_cleanup;
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
index 85e61f45121..f1db395dd88 100644
--- a/drivers/spi/spi_bitbang.c
+++ b/drivers/spi/spi_bitbang.c
@@ -188,12 +188,6 @@ int spi_bitbang_setup(struct spi_device *spi)
bitbang = spi_master_get_devdata(spi->master);
- /* Bitbangers can support SPI_CS_HIGH, SPI_3WIRE, and so on;
- * add those to master->flags, and provide the other support.
- */
- if ((spi->mode & ~(SPI_CPOL|SPI_CPHA|bitbang->flags)) != 0)
- return -EINVAL;
-
if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs)
@@ -201,9 +195,6 @@ int spi_bitbang_setup(struct spi_device *spi)
spi->controller_state = cs;
}
- if (!spi->bits_per_word)
- spi->bits_per_word = 8;
-
/* per-word shift register access, in hardware or bitbanging */
cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
if (!cs->txrx_word)
@@ -213,9 +204,7 @@ int spi_bitbang_setup(struct spi_device *spi)
if (retval < 0)
return retval;
- dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
- __func__, spi->mode & (SPI_CPOL | SPI_CPHA),
- spi->bits_per_word, 2 * cs->nsecs);
+ dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs);
/* NOTE we _need_ to call chipselect() early, ideally with adapter
* setup, unless the hardware defaults cooperate to avoid confusion
@@ -269,6 +258,11 @@ static void bitbang_work(struct work_struct *work)
struct spi_bitbang *bitbang =
container_of(work, struct spi_bitbang, work);
unsigned long flags;
+ int do_setup = -1;
+ int (*setup_transfer)(struct spi_device *,
+ struct spi_transfer *);
+
+ setup_transfer = bitbang->setup_transfer;
spin_lock_irqsave(&bitbang->lock, flags);
bitbang->busy = 1;
@@ -280,8 +274,6 @@ static void bitbang_work(struct work_struct *work)
unsigned tmp;
unsigned cs_change;
int status;
- int (*setup_transfer)(struct spi_device *,
- struct spi_transfer *);
m = container_of(bitbang->queue.next, struct spi_message,
queue);
@@ -298,19 +290,19 @@ static void bitbang_work(struct work_struct *work)
tmp = 0;
cs_change = 1;
status = 0;
- setup_transfer = NULL;
list_for_each_entry (t, &m->transfers, transfer_list) {
- /* override or restore speed and wordsize */
- if (t->speed_hz || t->bits_per_word) {
- setup_transfer = bitbang->setup_transfer;
+ /* override speed or wordsize? */
+ if (t->speed_hz || t->bits_per_word)
+ do_setup = 1;
+
+ /* init (-1) or override (1) transfer params */
+ if (do_setup != 0) {
if (!setup_transfer) {
status = -ENOPROTOOPT;
break;
}
- }
- if (setup_transfer) {
status = setup_transfer(spi, t);
if (status < 0)
break;
@@ -374,9 +366,10 @@ static void bitbang_work(struct work_struct *work)
m->status = status;
m->complete(m->context);
- /* restore speed and wordsize */
- if (setup_transfer)
+ /* restore speed and wordsize if it was overridden */
+ if (do_setup == 1)
setup_transfer(spi, NULL);
+ do_setup = 0;
/* normally deactivate chipselect ... unless no error and
* cs_change has hinted that the next message will probably
@@ -457,6 +450,9 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
spin_lock_init(&bitbang->lock);
INIT_LIST_HEAD(&bitbang->queue);
+ if (!bitbang->master->mode_bits)
+ bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
+
if (!bitbang->master->transfer)
bitbang->master->transfer = spi_bitbang_transfer;
if (!bitbang->txrx_bufs) {
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index 0671aeef579..c195e45f7f3 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -1171,9 +1171,6 @@ msg_rejected:
return -EINVAL;
}
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
-
/* On first setup bad values must free chip_data memory since will cause
spi_new_device to fail. Bad value setup from protocol driver are simply not
applied and notified to the calling driver. */
@@ -1186,12 +1183,6 @@ static int setup(struct spi_device *spi)
u32 tmp;
int status = 0;
- if (spi->mode & ~MODEBITS) {
- dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
- spi->mode & ~MODEBITS);
- return -EINVAL;
- }
-
/* Get controller data */
chip_info = spi->controller_data;
@@ -1286,10 +1277,7 @@ static int setup(struct spi_device *spi)
/* SPI word width */
tmp = spi->bits_per_word;
- if (tmp == 0) {
- tmp = 8;
- spi->bits_per_word = 8;
- } else if (tmp > 16) {
+ if (tmp > 16) {
status = -EINVAL;
dev_err(&spi->dev,
"setup - "
@@ -1481,6 +1469,9 @@ static int __init spi_imx_probe(struct platform_device *pdev)
drv_data->master_info = platform_info;
drv_data->pdev = pdev;
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
master->bus_num = pdev->id;
master->num_chipselect = platform_info->num_chipselect;
master->dma_alignment = DMA_ALIGNMENT;
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc8xxx.c
index f4573a96af2..0fd0ec4d3a7 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc8xxx.c
@@ -1,5 +1,5 @@
/*
- * MPC83xx SPI controller driver.
+ * MPC8xxx SPI controller driver.
*
* Maintainer: Kumar Gala
*
@@ -14,8 +14,10 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/kernel.h>
+#include <linux/bug.h>
#include <linux/errno.h>
#include <linux/err.h>
+#include <linux/io.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -33,10 +35,9 @@
#include <sysdev/fsl_soc.h>
#include <asm/irq.h>
-#include <asm/io.h>
/* SPI Controller registers */
-struct mpc83xx_spi_reg {
+struct mpc8xxx_spi_reg {
u8 res1[0x20];
__be32 mode;
__be32 event;
@@ -75,16 +76,16 @@ struct mpc83xx_spi_reg {
#define SPIM_NF 0x00000100 /* Not full */
/* SPI Controller driver's private data. */
-struct mpc83xx_spi {
- struct mpc83xx_spi_reg __iomem *base;
+struct mpc8xxx_spi {
+ struct mpc8xxx_spi_reg __iomem *base;
/* rx & tx bufs from the spi_transfer */
const void *tx;
void *rx;
/* functions to deal with different sized buffers */
- void (*get_rx) (u32 rx_data, struct mpc83xx_spi *);
- u32(*get_tx) (struct mpc83xx_spi *);
+ void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
+ u32(*get_tx) (struct mpc8xxx_spi *);
unsigned int count;
unsigned int irq;
@@ -97,8 +98,6 @@ struct mpc83xx_spi {
bool qe_mode;
- u8 busy;
-
struct workqueue_struct *workqueue;
struct work_struct work;
@@ -108,44 +107,44 @@ struct mpc83xx_spi {
struct completion done;
};
-struct spi_mpc83xx_cs {
+struct spi_mpc8xxx_cs {
/* functions to deal with different sized buffers */
- void (*get_rx) (u32 rx_data, struct mpc83xx_spi *);
- u32 (*get_tx) (struct mpc83xx_spi *);
+ void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
+ u32 (*get_tx) (struct mpc8xxx_spi *);
u32 rx_shift; /* RX data reg shift when in qe mode */
u32 tx_shift; /* TX data reg shift when in qe mode */
u32 hw_mode; /* Holds HW mode register settings */
};
-static inline void mpc83xx_spi_write_reg(__be32 __iomem * reg, u32 val)
+static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
{
out_be32(reg, val);
}
-static inline u32 mpc83xx_spi_read_reg(__be32 __iomem * reg)
+static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
{
return in_be32(reg);
}
#define MPC83XX_SPI_RX_BUF(type) \
static \
-void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \
+void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
{ \
- type * rx = mpc83xx_spi->rx; \
- *rx++ = (type)(data >> mpc83xx_spi->rx_shift); \
- mpc83xx_spi->rx = rx; \
+ type *rx = mpc8xxx_spi->rx; \
+ *rx++ = (type)(data >> mpc8xxx_spi->rx_shift); \
+ mpc8xxx_spi->rx = rx; \
}
#define MPC83XX_SPI_TX_BUF(type) \
static \
-u32 mpc83xx_spi_tx_buf_##type(struct mpc83xx_spi *mpc83xx_spi) \
+u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \
{ \
u32 data; \
- const type * tx = mpc83xx_spi->tx; \
+ const type *tx = mpc8xxx_spi->tx; \
if (!tx) \
return 0; \
- data = *tx++ << mpc83xx_spi->tx_shift; \
- mpc83xx_spi->tx = tx; \
+ data = *tx++ << mpc8xxx_spi->tx_shift; \
+ mpc8xxx_spi->tx = tx; \
return data; \
}
@@ -156,12 +155,12 @@ MPC83XX_SPI_TX_BUF(u8)
MPC83XX_SPI_TX_BUF(u16)
MPC83XX_SPI_TX_BUF(u32)
-static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
+static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
{
- struct mpc83xx_spi *mpc83xx_spi = spi_master_get_devdata(spi->master);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
bool pol = spi->mode & SPI_CS_HIGH;
- struct spi_mpc83xx_cs *cs = spi->controller_state;
+ struct spi_mpc8xxx_cs *cs = spi->controller_state;
if (value == BITBANG_CS_INACTIVE) {
if (pdata->cs_control)
@@ -169,16 +168,16 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
}
if (value == BITBANG_CS_ACTIVE) {
- u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
+ u32 regval = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
- mpc83xx_spi->rx_shift = cs->rx_shift;
- mpc83xx_spi->tx_shift = cs->tx_shift;
- mpc83xx_spi->get_rx = cs->get_rx;
- mpc83xx_spi->get_tx = cs->get_tx;
+ mpc8xxx_spi->rx_shift = cs->rx_shift;
+ mpc8xxx_spi->tx_shift = cs->tx_shift;
+ mpc8xxx_spi->get_rx = cs->get_rx;
+ mpc8xxx_spi->get_tx = cs->get_tx;
if (cs->hw_mode != regval) {
unsigned long flags;
- __be32 __iomem *mode = &mpc83xx_spi->base->mode;
+ __be32 __iomem *mode = &mpc8xxx_spi->base->mode;
regval = cs->hw_mode;
/* Turn off IRQs locally to minimize time that
@@ -186,8 +185,8 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
*/
local_irq_save(flags);
/* Turn off SPI unit prior changing mode */
- mpc83xx_spi_write_reg(mode, regval & ~SPMODE_ENABLE);
- mpc83xx_spi_write_reg(mode, regval);
+ mpc8xxx_spi_write_reg(mode, regval & ~SPMODE_ENABLE);
+ mpc8xxx_spi_write_reg(mode, regval);
local_irq_restore(flags);
}
if (pdata->cs_control)
@@ -196,15 +195,15 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
}
static
-int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
{
- struct mpc83xx_spi *mpc83xx_spi;
+ struct mpc8xxx_spi *mpc8xxx_spi;
u32 regval;
u8 bits_per_word, pm;
u32 hz;
- struct spi_mpc83xx_cs *cs = spi->controller_state;
+ struct spi_mpc8xxx_cs *cs = spi->controller_state;
- mpc83xx_spi = spi_master_get_devdata(spi->master);
+ mpc8xxx_spi = spi_master_get_devdata(spi->master);
if (t) {
bits_per_word = t->bits_per_word;
@@ -229,26 +228,26 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
cs->rx_shift = 0;
cs->tx_shift = 0;
if (bits_per_word <= 8) {
- cs->get_rx = mpc83xx_spi_rx_buf_u8;
- cs->get_tx = mpc83xx_spi_tx_buf_u8;
- if (mpc83xx_spi->qe_mode) {
+ cs->get_rx = mpc8xxx_spi_rx_buf_u8;
+ cs->get_tx = mpc8xxx_spi_tx_buf_u8;
+ if (mpc8xxx_spi->qe_mode) {
cs->rx_shift = 16;
cs->tx_shift = 24;
}
} else if (bits_per_word <= 16) {
- cs->get_rx = mpc83xx_spi_rx_buf_u16;
- cs->get_tx = mpc83xx_spi_tx_buf_u16;
- if (mpc83xx_spi->qe_mode) {
+ cs->get_rx = mpc8xxx_spi_rx_buf_u16;
+ cs->get_tx = mpc8xxx_spi_tx_buf_u16;
+ if (mpc8xxx_spi->qe_mode) {
cs->rx_shift = 16;
cs->tx_shift = 16;
}
} else if (bits_per_word <= 32) {
- cs->get_rx = mpc83xx_spi_rx_buf_u32;
- cs->get_tx = mpc83xx_spi_tx_buf_u32;
+ cs->get_rx = mpc8xxx_spi_rx_buf_u32;
+ cs->get_tx = mpc8xxx_spi_tx_buf_u32;
} else
return -EINVAL;
- if (mpc83xx_spi->qe_mode && spi->mode & SPI_LSB_FIRST) {
+ if (mpc8xxx_spi->qe_mode && spi->mode & SPI_LSB_FIRST) {
cs->tx_shift = 0;
if (bits_per_word <= 8)
cs->rx_shift = 8;
@@ -256,10 +255,10 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
cs->rx_shift = 0;
}
- mpc83xx_spi->rx_shift = cs->rx_shift;
- mpc83xx_spi->tx_shift = cs->tx_shift;
- mpc83xx_spi->get_rx = cs->get_rx;
- mpc83xx_spi->get_tx = cs->get_tx;
+ mpc8xxx_spi->rx_shift = cs->rx_shift;
+ mpc8xxx_spi->tx_shift = cs->tx_shift;
+ mpc8xxx_spi->get_rx = cs->get_rx;
+ mpc8xxx_spi->get_tx = cs->get_tx;
if (bits_per_word == 32)
bits_per_word = 0;
@@ -272,25 +271,25 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
cs->hw_mode |= SPMODE_LEN(bits_per_word);
- if ((mpc83xx_spi->spibrg / hz) > 64) {
+ if ((mpc8xxx_spi->spibrg / hz) > 64) {
cs->hw_mode |= SPMODE_DIV16;
- pm = mpc83xx_spi->spibrg / (hz * 64);
- if (pm > 16) {
- dev_err(&spi->dev, "Requested speed is too "
- "low: %d Hz. Will use %d Hz instead.\n",
- hz, mpc83xx_spi->spibrg / 1024);
+ pm = mpc8xxx_spi->spibrg / (hz * 64);
+
+ WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
+ "Will use %d Hz instead.\n", dev_name(&spi->dev),
+ hz, mpc8xxx_spi->spibrg / 1024);
+ if (pm > 16)
pm = 16;
- }
} else
- pm = mpc83xx_spi->spibrg / (hz * 4);
+ pm = mpc8xxx_spi->spibrg / (hz * 4);
if (pm)
pm--;
cs->hw_mode |= SPMODE_PM(pm);
- regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
+ regval = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
if (cs->hw_mode != regval) {
unsigned long flags;
- __be32 __iomem *mode = &mpc83xx_spi->base->mode;
+ __be32 __iomem *mode = &mpc8xxx_spi->base->mode;
regval = cs->hw_mode;
/* Turn off IRQs locally to minimize time
@@ -298,22 +297,22 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
*/
local_irq_save(flags);
/* Turn off SPI unit prior changing mode */
- mpc83xx_spi_write_reg(mode, regval & ~SPMODE_ENABLE);
- mpc83xx_spi_write_reg(mode, regval);
+ mpc8xxx_spi_write_reg(mode, regval & ~SPMODE_ENABLE);
+ mpc8xxx_spi_write_reg(mode, regval);
local_irq_restore(flags);
}
return 0;
}
-static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
+static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
- struct mpc83xx_spi *mpc83xx_spi;
+ struct mpc8xxx_spi *mpc8xxx_spi;
u32 word, len, bits_per_word;
- mpc83xx_spi = spi_master_get_devdata(spi->master);
+ mpc8xxx_spi = spi_master_get_devdata(spi->master);
- mpc83xx_spi->tx = t->tx_buf;
- mpc83xx_spi->rx = t->rx_buf;
+ mpc8xxx_spi->tx = t->tx_buf;
+ mpc8xxx_spi->rx = t->rx_buf;
bits_per_word = spi->bits_per_word;
if (t->bits_per_word)
bits_per_word = t->bits_per_word;
@@ -330,111 +329,106 @@ static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
return -EINVAL;
len /= 2;
}
- mpc83xx_spi->count = len;
+ mpc8xxx_spi->count = len;
- INIT_COMPLETION(mpc83xx_spi->done);
+ INIT_COMPLETION(mpc8xxx_spi->done);
/* enable rx ints */
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, SPIM_NE);
+ mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, SPIM_NE);
/* transmit word */
- word = mpc83xx_spi->get_tx(mpc83xx_spi);
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word);
+ word = mpc8xxx_spi->get_tx(mpc8xxx_spi);
+ mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->transmit, word);
- wait_for_completion(&mpc83xx_spi->done);
+ wait_for_completion(&mpc8xxx_spi->done);
/* disable rx ints */
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
+ mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
- return mpc83xx_spi->count;
+ return mpc8xxx_spi->count;
}
-static void mpc83xx_spi_work(struct work_struct *work)
+static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
{
- struct mpc83xx_spi *mpc83xx_spi =
- container_of(work, struct mpc83xx_spi, work);
-
- spin_lock_irq(&mpc83xx_spi->lock);
- mpc83xx_spi->busy = 1;
- while (!list_empty(&mpc83xx_spi->queue)) {
- struct spi_message *m;
- struct spi_device *spi;
- struct spi_transfer *t = NULL;
- unsigned cs_change;
- int status, nsecs = 50;
-
- m = container_of(mpc83xx_spi->queue.next,
- struct spi_message, queue);
- list_del_init(&m->queue);
- spin_unlock_irq(&mpc83xx_spi->lock);
-
- spi = m->spi;
- cs_change = 1;
- status = 0;
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (t->bits_per_word || t->speed_hz) {
- /* Don't allow changes if CS is active */
- status = -EINVAL;
-
- if (cs_change)
- status = mpc83xx_spi_setup_transfer(spi, t);
- if (status < 0)
- break;
- }
+ struct spi_device *spi = m->spi;
+ struct spi_transfer *t;
+ unsigned int cs_change;
+ const int nsecs = 50;
+ int status;
+
+ cs_change = 1;
+ status = 0;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->bits_per_word || t->speed_hz) {
+ /* Don't allow changes if CS is active */
+ status = -EINVAL;
if (cs_change)
- mpc83xx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
- cs_change = t->cs_change;
- if (t->len)
- status = mpc83xx_spi_bufs(spi, t);
- if (status) {
- status = -EMSGSIZE;
+ status = mpc8xxx_spi_setup_transfer(spi, t);
+ if (status < 0)
break;
- }
- m->actual_length += t->len;
-
- if (t->delay_usecs)
- udelay(t->delay_usecs);
+ }
- if (cs_change) {
- ndelay(nsecs);
- mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
- ndelay(nsecs);
- }
+ if (cs_change) {
+ mpc8xxx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
+ ndelay(nsecs);
+ }
+ cs_change = t->cs_change;
+ if (t->len)
+ status = mpc8xxx_spi_bufs(spi, t);
+ if (status) {
+ status = -EMSGSIZE;
+ break;
}
+ m->actual_length += t->len;
- m->status = status;
- m->complete(m->context);
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
- if (status || !cs_change) {
+ if (cs_change) {
+ ndelay(nsecs);
+ mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
ndelay(nsecs);
- mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
}
+ }
- mpc83xx_spi_setup_transfer(spi, NULL);
+ m->status = status;
+ m->complete(m->context);
- spin_lock_irq(&mpc83xx_spi->lock);
+ if (status || !cs_change) {
+ ndelay(nsecs);
+ mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
}
- mpc83xx_spi->busy = 0;
- spin_unlock_irq(&mpc83xx_spi->lock);
+
+ mpc8xxx_spi_setup_transfer(spi, NULL);
}
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
- | SPI_LSB_FIRST | SPI_LOOP)
+static void mpc8xxx_spi_work(struct work_struct *work)
+{
+ struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
+ work);
+
+ spin_lock_irq(&mpc8xxx_spi->lock);
+ while (!list_empty(&mpc8xxx_spi->queue)) {
+ struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
+ struct spi_message, queue);
+
+ list_del_init(&m->queue);
+ spin_unlock_irq(&mpc8xxx_spi->lock);
+
+ mpc8xxx_spi_do_one_msg(m);
+
+ spin_lock_irq(&mpc8xxx_spi->lock);
+ }
+ spin_unlock_irq(&mpc8xxx_spi->lock);
+}
-static int mpc83xx_spi_setup(struct spi_device *spi)
+static int mpc8xxx_spi_setup(struct spi_device *spi)
{
- struct mpc83xx_spi *mpc83xx_spi;
+ struct mpc8xxx_spi *mpc8xxx_spi;
int retval;
u32 hw_mode;
- struct spi_mpc83xx_cs *cs = spi->controller_state;
-
- if (spi->mode & ~MODEBITS) {
- dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
- spi->mode & ~MODEBITS);
- return -EINVAL;
- }
+ struct spi_mpc8xxx_cs *cs = spi->controller_state;
if (!spi->max_speed_hz)
return -EINVAL;
@@ -445,13 +439,10 @@ static int mpc83xx_spi_setup(struct spi_device *spi)
return -ENOMEM;
spi->controller_state = cs;
}
- mpc83xx_spi = spi_master_get_devdata(spi->master);
-
- if (!spi->bits_per_word)
- spi->bits_per_word = 8;
+ mpc8xxx_spi = spi_master_get_devdata(spi->master);
hw_mode = cs->hw_mode; /* Save orginal settings */
- cs->hw_mode = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
+ cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
/* mask out bits we are going to set */
cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
| SPMODE_REV | SPMODE_LOOP);
@@ -465,45 +456,29 @@ static int mpc83xx_spi_setup(struct spi_device *spi)
if (spi->mode & SPI_LOOP)
cs->hw_mode |= SPMODE_LOOP;
- retval = mpc83xx_spi_setup_transfer(spi, NULL);
+ retval = mpc8xxx_spi_setup_transfer(spi, NULL);
if (retval < 0) {
cs->hw_mode = hw_mode; /* Restore settings */
return retval;
}
-
- dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u Hz\n",
- __func__, spi->mode & (SPI_CPOL | SPI_CPHA),
- spi->bits_per_word, spi->max_speed_hz);
-#if 0 /* Don't think this is needed */
- /* NOTE we _need_ to call chipselect() early, ideally with adapter
- * setup, unless the hardware defaults cooperate to avoid confusion
- * between normal (active low) and inverted chipselects.
- */
-
- /* deselect chip (low or high) */
- spin_lock(&mpc83xx_spi->lock);
- if (!mpc83xx_spi->busy)
- mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
- spin_unlock(&mpc83xx_spi->lock);
-#endif
return 0;
}
-static irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
+static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
{
- struct mpc83xx_spi *mpc83xx_spi = context_data;
+ struct mpc8xxx_spi *mpc8xxx_spi = context_data;
u32 event;
irqreturn_t ret = IRQ_NONE;
/* Get interrupt events(tx/rx) */
- event = mpc83xx_spi_read_reg(&mpc83xx_spi->base->event);
+ event = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->event);
/* We need handle RX first */
if (event & SPIE_NE) {
- u32 rx_data = mpc83xx_spi_read_reg(&mpc83xx_spi->base->receive);
+ u32 rx_data = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->receive);
- if (mpc83xx_spi->rx)
- mpc83xx_spi->get_rx(rx_data, mpc83xx_spi);
+ if (mpc8xxx_spi->rx)
+ mpc8xxx_spi->get_rx(rx_data, mpc8xxx_spi);
ret = IRQ_HANDLED;
}
@@ -511,56 +486,56 @@ static irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
if ((event & SPIE_NF) == 0)
/* spin until TX is done */
while (((event =
- mpc83xx_spi_read_reg(&mpc83xx_spi->base->event)) &
+ mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->event)) &
SPIE_NF) == 0)
- cpu_relax();
+ cpu_relax();
- mpc83xx_spi->count -= 1;
- if (mpc83xx_spi->count) {
- u32 word = mpc83xx_spi->get_tx(mpc83xx_spi);
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word);
+ mpc8xxx_spi->count -= 1;
+ if (mpc8xxx_spi->count) {
+ u32 word = mpc8xxx_spi->get_tx(mpc8xxx_spi);
+ mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->transmit, word);
} else {
- complete(&mpc83xx_spi->done);
+ complete(&mpc8xxx_spi->done);
}
/* Clear the events */
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, event);
+ mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, event);
return ret;
}
-static int mpc83xx_spi_transfer(struct spi_device *spi,
+static int mpc8xxx_spi_transfer(struct spi_device *spi,
struct spi_message *m)
{
- struct mpc83xx_spi *mpc83xx_spi = spi_master_get_devdata(spi->master);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
unsigned long flags;
m->actual_length = 0;
m->status = -EINPROGRESS;
- spin_lock_irqsave(&mpc83xx_spi->lock, flags);
- list_add_tail(&m->queue, &mpc83xx_spi->queue);
- queue_work(mpc83xx_spi->workqueue, &mpc83xx_spi->work);
- spin_unlock_irqrestore(&mpc83xx_spi->lock, flags);
+ spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
+ list_add_tail(&m->queue, &mpc8xxx_spi->queue);
+ queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
+ spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
return 0;
}
-static void mpc83xx_spi_cleanup(struct spi_device *spi)
+static void mpc8xxx_spi_cleanup(struct spi_device *spi)
{
kfree(spi->controller_state);
}
static struct spi_master * __devinit
-mpc83xx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
+mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev->platform_data;
struct spi_master *master;
- struct mpc83xx_spi *mpc83xx_spi;
+ struct mpc8xxx_spi *mpc8xxx_spi;
u32 regval;
int ret = 0;
- master = spi_alloc_master(dev, sizeof(struct mpc83xx_spi));
+ master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
if (master == NULL) {
ret = -ENOMEM;
goto err;
@@ -568,36 +543,40 @@ mpc83xx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
dev_set_drvdata(dev, master);
- master->setup = mpc83xx_spi_setup;
- master->transfer = mpc83xx_spi_transfer;
- master->cleanup = mpc83xx_spi_cleanup;
-
- mpc83xx_spi = spi_master_get_devdata(master);
- mpc83xx_spi->qe_mode = pdata->qe_mode;
- mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
- mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
- mpc83xx_spi->spibrg = pdata->sysclk;
-
- mpc83xx_spi->rx_shift = 0;
- mpc83xx_spi->tx_shift = 0;
- if (mpc83xx_spi->qe_mode) {
- mpc83xx_spi->rx_shift = 16;
- mpc83xx_spi->tx_shift = 24;
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
+ | SPI_LSB_FIRST | SPI_LOOP;
+
+ master->setup = mpc8xxx_spi_setup;
+ master->transfer = mpc8xxx_spi_transfer;
+ master->cleanup = mpc8xxx_spi_cleanup;
+
+ mpc8xxx_spi = spi_master_get_devdata(master);
+ mpc8xxx_spi->qe_mode = pdata->qe_mode;
+ mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
+ mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
+ mpc8xxx_spi->spibrg = pdata->sysclk;
+
+ mpc8xxx_spi->rx_shift = 0;
+ mpc8xxx_spi->tx_shift = 0;
+ if (mpc8xxx_spi->qe_mode) {
+ mpc8xxx_spi->rx_shift = 16;
+ mpc8xxx_spi->tx_shift = 24;
}
- init_completion(&mpc83xx_spi->done);
+ init_completion(&mpc8xxx_spi->done);
- mpc83xx_spi->base = ioremap(mem->start, mem->end - mem->start + 1);
- if (mpc83xx_spi->base == NULL) {
+ mpc8xxx_spi->base = ioremap(mem->start, mem->end - mem->start + 1);
+ if (mpc8xxx_spi->base == NULL) {
ret = -ENOMEM;
goto put_master;
}
- mpc83xx_spi->irq = irq;
+ mpc8xxx_spi->irq = irq;
/* Register for SPI Interrupt */
- ret = request_irq(mpc83xx_spi->irq, mpc83xx_spi_irq,
- 0, "mpc83xx_spi", mpc83xx_spi);
+ ret = request_irq(mpc8xxx_spi->irq, mpc8xxx_spi_irq,
+ 0, "mpc8xxx_spi", mpc8xxx_spi);
if (ret != 0)
goto unmap_io;
@@ -606,25 +585,25 @@ mpc83xx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
master->num_chipselect = pdata->max_chipselect;
/* SPI controller initializations */
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->command, 0);
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, 0xffffffff);
+ mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0);
+ mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
+ mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0);
+ mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff);
/* Enable SPI interface */
regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
if (pdata->qe_mode)
regval |= SPMODE_OP;
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
- spin_lock_init(&mpc83xx_spi->lock);
- init_completion(&mpc83xx_spi->done);
- INIT_WORK(&mpc83xx_spi->work, mpc83xx_spi_work);
- INIT_LIST_HEAD(&mpc83xx_spi->queue);
+ mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
+ spin_lock_init(&mpc8xxx_spi->lock);
+ init_completion(&mpc8xxx_spi->done);
+ INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
+ INIT_LIST_HEAD(&mpc8xxx_spi->queue);
- mpc83xx_spi->workqueue = create_singlethread_workqueue(
+ mpc8xxx_spi->workqueue = create_singlethread_workqueue(
dev_name(master->dev.parent));
- if (mpc83xx_spi->workqueue == NULL) {
+ if (mpc8xxx_spi->workqueue == NULL) {
ret = -EBUSY;
goto free_irq;
}
@@ -634,57 +613,57 @@ mpc83xx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
goto unreg_master;
printk(KERN_INFO
- "%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n",
- dev_name(dev), mpc83xx_spi->base, mpc83xx_spi->irq);
+ "%s: MPC8xxx SPI Controller driver at 0x%p (irq = %d)\n",
+ dev_name(dev), mpc8xxx_spi->base, mpc8xxx_spi->irq);
return master;
unreg_master:
- destroy_workqueue(mpc83xx_spi->workqueue);
+ destroy_workqueue(mpc8xxx_spi->workqueue);
free_irq:
- free_irq(mpc83xx_spi->irq, mpc83xx_spi);
+ free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
unmap_io:
- iounmap(mpc83xx_spi->base);
+ iounmap(mpc8xxx_spi->base);
put_master:
spi_master_put(master);
err:
return ERR_PTR(ret);
}
-static int __devexit mpc83xx_spi_remove(struct device *dev)
+static int __devexit mpc8xxx_spi_remove(struct device *dev)
{
- struct mpc83xx_spi *mpc83xx_spi;
+ struct mpc8xxx_spi *mpc8xxx_spi;
struct spi_master *master;
master = dev_get_drvdata(dev);
- mpc83xx_spi = spi_master_get_devdata(master);
+ mpc8xxx_spi = spi_master_get_devdata(master);
- flush_workqueue(mpc83xx_spi->workqueue);
- destroy_workqueue(mpc83xx_spi->workqueue);
+ flush_workqueue(mpc8xxx_spi->workqueue);
+ destroy_workqueue(mpc8xxx_spi->workqueue);
spi_unregister_master(master);
- free_irq(mpc83xx_spi->irq, mpc83xx_spi);
- iounmap(mpc83xx_spi->base);
+ free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
+ iounmap(mpc8xxx_spi->base);
return 0;
}
-struct mpc83xx_spi_probe_info {
+struct mpc8xxx_spi_probe_info {
struct fsl_spi_platform_data pdata;
int *gpios;
bool *alow_flags;
};
-static struct mpc83xx_spi_probe_info *
+static struct mpc8xxx_spi_probe_info *
to_of_pinfo(struct fsl_spi_platform_data *pdata)
{
- return container_of(pdata, struct mpc83xx_spi_probe_info, pdata);
+ return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
}
-static void mpc83xx_spi_cs_control(struct spi_device *spi, bool on)
+static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
{
struct device *dev = spi->dev.parent;
- struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
+ struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
u16 cs = spi->chip_select;
int gpio = pinfo->gpios[cs];
bool alow = pinfo->alow_flags[cs];
@@ -692,11 +671,11 @@ static void mpc83xx_spi_cs_control(struct spi_device *spi, bool on)
gpio_set_value(gpio, on ^ alow);
}
-static int of_mpc83xx_spi_get_chipselects(struct device *dev)
+static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
{
struct device_node *np = dev_archdata_get_node(&dev->archdata);
struct fsl_spi_platform_data *pdata = dev->platform_data;
- struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+ struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
unsigned int ngpios;
int i = 0;
int ret;
@@ -711,12 +690,12 @@ static int of_mpc83xx_spi_get_chipselects(struct device *dev)
return 0;
}
- pinfo->gpios = kmalloc(ngpios * sizeof(pinfo->gpios), GFP_KERNEL);
+ pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
if (!pinfo->gpios)
return -ENOMEM;
- memset(pinfo->gpios, -1, ngpios * sizeof(pinfo->gpios));
+ memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
- pinfo->alow_flags = kzalloc(ngpios * sizeof(pinfo->alow_flags),
+ pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
GFP_KERNEL);
if (!pinfo->alow_flags) {
ret = -ENOMEM;
@@ -752,7 +731,7 @@ static int of_mpc83xx_spi_get_chipselects(struct device *dev)
}
pdata->max_chipselect = ngpios;
- pdata->cs_control = mpc83xx_spi_cs_control;
+ pdata->cs_control = mpc8xxx_spi_cs_control;
return 0;
@@ -771,10 +750,10 @@ err_alloc_flags:
return ret;
}
-static int of_mpc83xx_spi_free_chipselects(struct device *dev)
+static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
{
struct fsl_spi_platform_data *pdata = dev->platform_data;
- struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+ struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
int i;
if (!pinfo->gpios)
@@ -790,12 +769,12 @@ static int of_mpc83xx_spi_free_chipselects(struct device *dev)
return 0;
}
-static int __devinit of_mpc83xx_spi_probe(struct of_device *ofdev,
+static int __devinit of_mpc8xxx_spi_probe(struct of_device *ofdev,
const struct of_device_id *ofid)
{
struct device *dev = &ofdev->dev;
struct device_node *np = ofdev->node;
- struct mpc83xx_spi_probe_info *pinfo;
+ struct mpc8xxx_spi_probe_info *pinfo;
struct fsl_spi_platform_data *pdata;
struct spi_master *master;
struct resource mem;
@@ -827,7 +806,7 @@ static int __devinit of_mpc83xx_spi_probe(struct of_device *ofdev,
if (prop && !strcmp(prop, "cpu-qe"))
pdata->qe_mode = 1;
- ret = of_mpc83xx_spi_get_chipselects(dev);
+ ret = of_mpc8xxx_spi_get_chipselects(dev);
if (ret)
goto err;
@@ -841,7 +820,7 @@ static int __devinit of_mpc83xx_spi_probe(struct of_device *ofdev,
goto err;
}
- master = mpc83xx_spi_probe(dev, &mem, irq.start);
+ master = mpc8xxx_spi_probe(dev, &mem, irq.start);
if (IS_ERR(master)) {
ret = PTR_ERR(master);
goto err;
@@ -852,34 +831,34 @@ static int __devinit of_mpc83xx_spi_probe(struct of_device *ofdev,
return 0;
err:
- of_mpc83xx_spi_free_chipselects(dev);
+ of_mpc8xxx_spi_free_chipselects(dev);
err_clk:
kfree(pinfo);
return ret;
}
-static int __devexit of_mpc83xx_spi_remove(struct of_device *ofdev)
+static int __devexit of_mpc8xxx_spi_remove(struct of_device *ofdev)
{
int ret;
- ret = mpc83xx_spi_remove(&ofdev->dev);
+ ret = mpc8xxx_spi_remove(&ofdev->dev);
if (ret)
return ret;
- of_mpc83xx_spi_free_chipselects(&ofdev->dev);
+ of_mpc8xxx_spi_free_chipselects(&ofdev->dev);
return 0;
}
-static const struct of_device_id of_mpc83xx_spi_match[] = {
+static const struct of_device_id of_mpc8xxx_spi_match[] = {
{ .compatible = "fsl,spi" },
{},
};
-MODULE_DEVICE_TABLE(of, of_mpc83xx_spi_match);
+MODULE_DEVICE_TABLE(of, of_mpc8xxx_spi_match);
-static struct of_platform_driver of_mpc83xx_spi_driver = {
- .name = "mpc83xx_spi",
- .match_table = of_mpc83xx_spi_match,
- .probe = of_mpc83xx_spi_probe,
- .remove = __devexit_p(of_mpc83xx_spi_remove),
+static struct of_platform_driver of_mpc8xxx_spi_driver = {
+ .name = "mpc8xxx_spi",
+ .match_table = of_mpc8xxx_spi_match,
+ .probe = of_mpc8xxx_spi_probe,
+ .remove = __devexit_p(of_mpc8xxx_spi_remove),
};
#ifdef CONFIG_MPC832x_RDB
@@ -890,7 +869,7 @@ static struct of_platform_driver of_mpc83xx_spi_driver = {
* tree can work with OpenFirmware driver. But for now we support old trees
* as well.
*/
-static int __devinit plat_mpc83xx_spi_probe(struct platform_device *pdev)
+static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
{
struct resource *mem;
unsigned int irq;
@@ -907,23 +886,23 @@ static int __devinit plat_mpc83xx_spi_probe(struct platform_device *pdev)
if (!irq)
return -EINVAL;
- master = mpc83xx_spi_probe(&pdev->dev, mem, irq);
+ master = mpc8xxx_spi_probe(&pdev->dev, mem, irq);
if (IS_ERR(master))
return PTR_ERR(master);
return 0;
}
-static int __devexit plat_mpc83xx_spi_remove(struct platform_device *pdev)
+static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
{
- return mpc83xx_spi_remove(&pdev->dev);
+ return mpc8xxx_spi_remove(&pdev->dev);
}
-MODULE_ALIAS("platform:mpc83xx_spi");
-static struct platform_driver mpc83xx_spi_driver = {
- .probe = plat_mpc83xx_spi_probe,
- .remove = __exit_p(plat_mpc83xx_spi_remove),
+MODULE_ALIAS("platform:mpc8xxx_spi");
+static struct platform_driver mpc8xxx_spi_driver = {
+ .probe = plat_mpc8xxx_spi_probe,
+ .remove = __exit_p(plat_mpc8xxx_spi_remove),
.driver = {
- .name = "mpc83xx_spi",
+ .name = "mpc8xxx_spi",
.owner = THIS_MODULE,
},
};
@@ -932,35 +911,35 @@ static bool legacy_driver_failed;
static void __init legacy_driver_register(void)
{
- legacy_driver_failed = platform_driver_register(&mpc83xx_spi_driver);
+ legacy_driver_failed = platform_driver_register(&mpc8xxx_spi_driver);
}
static void __exit legacy_driver_unregister(void)
{
if (legacy_driver_failed)
return;
- platform_driver_unregister(&mpc83xx_spi_driver);
+ platform_driver_unregister(&mpc8xxx_spi_driver);
}
#else
static void __init legacy_driver_register(void) {}
static void __exit legacy_driver_unregister(void) {}
#endif /* CONFIG_MPC832x_RDB */
-static int __init mpc83xx_spi_init(void)
+static int __init mpc8xxx_spi_init(void)
{
legacy_driver_register();
- return of_register_platform_driver(&of_mpc83xx_spi_driver);
+ return of_register_platform_driver(&of_mpc8xxx_spi_driver);
}
-static void __exit mpc83xx_spi_exit(void)
+static void __exit mpc8xxx_spi_exit(void)
{
- of_unregister_platform_driver(&of_mpc83xx_spi_driver);
+ of_unregister_platform_driver(&of_mpc8xxx_spi_driver);
legacy_driver_unregister();
}
-module_init(mpc83xx_spi_init);
-module_exit(mpc83xx_spi_exit);
+module_init(mpc8xxx_spi_init);
+module_exit(mpc8xxx_spi_exit);
MODULE_AUTHOR("Kumar Gala");
-MODULE_DESCRIPTION("Simple MPC83xx SPI Driver");
+MODULE_DESCRIPTION("Simple MPC8xxx SPI Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index b3ebc1d0f85..e0d44af4745 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -146,32 +146,16 @@ static int s3c24xx_spi_setupxfer(struct spi_device *spi,
return 0;
}
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
-
static int s3c24xx_spi_setup(struct spi_device *spi)
{
int ret;
- if (!spi->bits_per_word)
- spi->bits_per_word = 8;
-
- if (spi->mode & ~MODEBITS) {
- dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
- spi->mode & ~MODEBITS);
- return -EINVAL;
- }
-
ret = s3c24xx_spi_setupxfer(spi, NULL);
if (ret < 0) {
dev_err(&spi->dev, "setupxfer returned %d\n", ret);
return ret;
}
- dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n",
- __func__, spi->mode, spi->bits_per_word,
- spi->max_speed_hz);
-
return 0;
}
@@ -290,6 +274,9 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev)
/* setup the master state. */
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
master->num_chipselect = hw->pdata->num_cs;
master->bus_num = pdata->bus_num;
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index f2447a5476b..bbf9371cd28 100644
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -17,6 +17,7 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
+#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
diff --git a/drivers/spi/spi_txx9.c b/drivers/spi/spi_txx9.c
index 29cbb065618..96057de133a 100644
--- a/drivers/spi/spi_txx9.c
+++ b/drivers/spi/spi_txx9.c
@@ -110,23 +110,17 @@ static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c,
ndelay(cs_delay); /* CS Setup Time / CS Recovery Time */
}
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CS_HIGH|SPI_CPOL|SPI_CPHA)
-
static int txx9spi_setup(struct spi_device *spi)
{
struct txx9spi *c = spi_master_get_devdata(spi->master);
u8 bits_per_word;
- if (spi->mode & ~MODEBITS)
- return -EINVAL;
-
if (!spi->max_speed_hz
|| spi->max_speed_hz > c->max_speed_hz
|| spi->max_speed_hz < c->min_speed_hz)
return -EINVAL;
- bits_per_word = spi->bits_per_word ? : 8;
+ bits_per_word = spi->bits_per_word;
if (bits_per_word != 8 && bits_per_word != 16)
return -EINVAL;
@@ -414,6 +408,9 @@ static int __init txx9spi_probe(struct platform_device *dev)
(unsigned long long)res->start, irq,
(c->baseclk + 500000) / 1000000);
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
+
master->bus_num = dev->id;
master->setup = txx9spi_setup;
master->transfer = txx9spi_transfer;
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 5d869c4d3eb..606e7a40a8d 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -58,15 +58,20 @@ static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG];
/* Bit masks for spi_device.mode management. Note that incorrect
- * settings for CS_HIGH and 3WIRE can cause *lots* of trouble for other
- * devices on a shared bus: CS_HIGH, because this device will be
- * active when it shouldn't be; 3WIRE, because when active it won't
- * behave as it should.
+ * settings for some settings can cause *lots* of trouble for other
+ * devices on a shared bus:
*
- * REVISIT should changing those two modes be privileged?
+ * - CS_HIGH ... this device will be active when it shouldn't be
+ * - 3WIRE ... when active, it won't behave as it should
+ * - NO_CS ... there will be no explicit message boundaries; this
+ * is completely incompatible with the shared bus model
+ * - READY ... transfers may proceed when they shouldn't.
+ *
+ * REVISIT should changing those flags be privileged?
*/
#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
- | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP)
+ | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
+ | SPI_NO_CS | SPI_READY)
struct spidev_data {
dev_t devt;
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 494d3f756e2..46b8c5c2f45 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -158,9 +158,6 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi,
return 0;
}
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA)
-
static int xilinx_spi_setup(struct spi_device *spi)
{
struct spi_bitbang *bitbang;
@@ -170,22 +167,10 @@ static int xilinx_spi_setup(struct spi_device *spi)
xspi = spi_master_get_devdata(spi->master);
bitbang = &xspi->bitbang;
- if (!spi->bits_per_word)
- spi->bits_per_word = 8;
-
- if (spi->mode & ~MODEBITS) {
- dev_err(&spi->dev, "%s, unsupported mode bits %x\n",
- __func__, spi->mode & ~MODEBITS);
- return -EINVAL;
- }
-
retval = xilinx_spi_setup_transfer(spi, NULL);
if (retval < 0)
return retval;
- dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
- __func__, spi->mode & MODEBITS, spi->bits_per_word, 0);
-
return 0;
}
@@ -333,6 +318,9 @@ static int __init xilinx_spi_of_probe(struct of_device *ofdev,
goto put_master;
}
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA;
+
xspi = spi_master_get_devdata(master);
xspi->bitbang.master = spi_master_get(master);
xspi->bitbang.chipselect = xilinx_spi_chipselect;