spi/ep93xx: implemented driver for Cirrus EP93xx SPI controller
Mika Westerberg [Thu, 6 May 2010 04:47:04 +0000 (04:47 +0000)]
This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
in EP93xx chips.

Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>

Documentation/spi/ep93xx_spi [new file with mode: 0644]
arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h [new file with mode: 0644]
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/ep93xx_spi.c [new file with mode: 0644]

diff --git a/Documentation/spi/ep93xx_spi b/Documentation/spi/ep93xx_spi
new file mode 100644 (file)
index 0000000..6325f5b
--- /dev/null
@@ -0,0 +1,95 @@
+Cirrus EP93xx SPI controller driver HOWTO
+=========================================
+
+ep93xx_spi driver brings SPI master support for EP93xx SPI controller.  Chip
+selects are implemented with GPIO lines.
+
+NOTE: If possible, don't use SFRMOUT (SFRM1) signal as a chip select. It will
+not work correctly (it cannot be controlled by software). Use GPIO lines
+instead.
+
+Sample configuration
+====================
+
+Typically driver configuration is done in platform board files (the files under
+arch/arm/mach-ep93xx/*.c). In this example we configure MMC over SPI through
+this driver on TS-7260 board. You can adapt the code to suit your needs.
+
+This example uses EGPIO9 as SD/MMC card chip select (this is wired in DIO1
+header on the board).
+
+You need to select CONFIG_MMC_SPI to use mmc_spi driver.
+
+arch/arm/mach-ep93xx/ts72xx.c:
+
+...
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+
+#include <mach/ep93xx_spi.h>
+
+/* this is our GPIO line used for chip select */
+#define MMC_CHIP_SELECT_GPIO EP93XX_GPIO_LINE_EGPIO9
+
+static int ts72xx_mmc_spi_setup(struct spi_device *spi)
+{
+       int err;
+
+       err = gpio_request(MMC_CHIP_SELECT_GPIO, spi->modalias);
+       if (err)
+               return err;
+
+       gpio_direction_output(MMC_CHIP_SELECT_GPIO, 1);
+
+       return 0;
+}
+
+static void ts72xx_mmc_spi_cleanup(struct spi_device *spi)
+{
+       gpio_set_value(MMC_CHIP_SELECT_GPIO, 1);
+       gpio_direction_input(MMC_CHIP_SELECT_GPIO);
+       gpio_free(MMC_CHIP_SELECT_GPIO);
+}
+
+static void ts72xx_mmc_spi_cs_control(struct spi_device *spi, int value)
+{
+       gpio_set_value(MMC_CHIP_SELECT_GPIO, value);
+}
+
+static struct ep93xx_spi_chip_ops ts72xx_mmc_spi_ops = {
+       .setup          = ts72xx_mmc_spi_setup,
+       .cleanup        = ts72xx_mmc_spi_cleanup,
+       .cs_control     = ts72xx_mmc_spi_cs_control,
+};
+
+static struct spi_board_info ts72xx_spi_devices[] __initdata = {
+       {
+               .modalias               = "mmc_spi",
+               .controller_data        = &ts72xx_mmc_spi_ops,
+               /*
+                * We use 10 MHz even though the maximum is 7.4 MHz. The driver
+                * will limit it automatically to max. frequency.
+                */
+               .max_speed_hz           = 10 * 1000 * 1000,
+               .bus_num                = 0,
+               .chip_select            = 0,
+               .mode                   = SPI_MODE_0,
+       },
+};
+
+static struct ep93xx_spi_info ts72xx_spi_info = {
+       .num_chipselect = ARRAY_SIZE(ts72xx_spi_devices),
+};
+
+static void __init ts72xx_init_machine(void)
+{
+       ...
+       ep93xx_register_spi(&ts72xx_spi_info, ts72xx_spi_devices,
+                           ARRAY_SIZE(ts72xx_spi_devices));
+}
+
+Thanks to
+=========
+Martin Guy, H. Hartley Sweeten and others who helped me during development of
+the driver. Simplemachines.it donated me a Sim.One board which I used testing
+the driver on EP9307.
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
new file mode 100644 (file)
index 0000000..0a37961
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __ASM_MACH_EP93XX_SPI_H
+#define __ASM_MACH_EP93XX_SPI_H
+
+struct spi_device;
+
+/**
+ * struct ep93xx_spi_info - EP93xx specific SPI descriptor
+ * @num_chipselect: number of chip selects on this board, must be
+ *                  at least one
+ */
+struct ep93xx_spi_info {
+       int     num_chipselect;
+};
+
+/**
+ * struct ep93xx_spi_chip_ops - operation callbacks for SPI slave device
+ * @setup: setup the chip select mechanism
+ * @cleanup: cleanup the chip select mechanism
+ * @cs_control: control the device chip select
+ */
+struct ep93xx_spi_chip_ops {
+       int     (*setup)(struct spi_device *spi);
+       void    (*cleanup)(struct spi_device *spi);
+       void    (*cs_control)(struct spi_device *spi, int value);
+};
+
+#endif /* __ASM_MACH_EP93XX_SPI_H */
index a191fa2..2b2f4c3 100644 (file)
@@ -117,6 +117,16 @@ config SPI_DAVINCI
        help
          SPI master controller for DaVinci and DA8xx SPI modules.
 
+config SPI_EP93XX
+       tristate "Cirrus Logic EP93xx SPI controller"
+       depends on ARCH_EP93XX
+       help
+         This enables using the Cirrus EP93xx SPI controller in master
+         mode.
+
+         To compile this driver as a module, choose M here. The module will be
+         called ep93xx_spi.
+
 config SPI_GPIO
        tristate "GPIO-based bitbanging SPI Master"
        depends on GENERIC_GPIO
index d7d0f89..377f845 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_SPI_DAVINCI)             += davinci_spi.o
 obj-$(CONFIG_SPI_DESIGNWARE)           += dw_spi.o
 obj-$(CONFIG_SPI_DW_PCI)               += dw_spi_pci.o
 obj-$(CONFIG_SPI_DW_MMIO)              += dw_spi_mmio.o
+obj-$(CONFIG_SPI_EP93XX)               += ep93xx_spi.o
 obj-$(CONFIG_SPI_GPIO)                 += spi_gpio.o
 obj-$(CONFIG_SPI_IMX)                  += spi_imx.o
 obj-$(CONFIG_SPI_LM70_LLP)             += spi_lm70llp.o
diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c
new file mode 100644 (file)
index 0000000..0ba35df
--- /dev/null
@@ -0,0 +1,938 @@
+/*
+ * Driver for Cirrus Logic EP93xx SPI controller.
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Explicit FIFO handling code was inspired by amba-pl022 driver.
+ *
+ * Chip select support using other than built-in GPIOs by H. Hartley Sweeten.
+ *
+ * For more information about the SPI controller see documentation on Cirrus
+ * Logic web site:
+ *     http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/spi/spi.h>
+
+#include <mach/ep93xx_spi.h>
+
+#define SSPCR0                 0x0000
+#define SSPCR0_MODE_SHIFT      6
+#define SSPCR0_SCR_SHIFT       8
+
+#define SSPCR1                 0x0004
+#define SSPCR1_RIE             BIT(0)
+#define SSPCR1_TIE             BIT(1)
+#define SSPCR1_RORIE           BIT(2)
+#define SSPCR1_LBM             BIT(3)
+#define SSPCR1_SSE             BIT(4)
+#define SSPCR1_MS              BIT(5)
+#define SSPCR1_SOD             BIT(6)
+
+#define SSPDR                  0x0008
+
+#define SSPSR                  0x000c
+#define SSPSR_TFE              BIT(0)
+#define SSPSR_TNF              BIT(1)
+#define SSPSR_RNE              BIT(2)
+#define SSPSR_RFF              BIT(3)
+#define SSPSR_BSY              BIT(4)
+#define SSPCPSR                        0x0010
+
+#define SSPIIR                 0x0014
+#define SSPIIR_RIS             BIT(0)
+#define SSPIIR_TIS             BIT(1)
+#define SSPIIR_RORIS           BIT(2)
+#define SSPICR                 SSPIIR
+
+/* timeout in milliseconds */
+#define SPI_TIMEOUT            5
+/* maximum depth of RX/TX FIFO */
+#define SPI_FIFO_SIZE          8
+
+/**
+ * struct ep93xx_spi - EP93xx SPI controller structure
+ * @lock: spinlock that protects concurrent accesses to fields @running,
+ *        @current_msg and @msg_queue
+ * @pdev: pointer to platform device
+ * @clk: clock for the controller
+ * @regs_base: pointer to ioremap()'d registers
+ * @irq: IRQ number used by the driver
+ * @min_rate: minimum clock rate (in Hz) supported by the controller
+ * @max_rate: maximum clock rate (in Hz) supported by the controller
+ * @running: is the queue running
+ * @wq: workqueue used by the driver
+ * @msg_work: work that is queued for the driver
+ * @wait: wait here until given transfer is completed
+ * @msg_queue: queue for the messages
+ * @current_msg: message that is currently processed (or %NULL if none)
+ * @tx: current byte in transfer to transmit
+ * @rx: current byte in transfer to receive
+ * @fifo_level: how full is FIFO (%0..%SPI_FIFO_SIZE - %1). Receiving one
+ *              frame decreases this level and sending one frame increases it.
+ *
+ * This structure holds EP93xx SPI controller specific information. When
+ * @running is %true, driver accepts transfer requests from protocol drivers.
+ * @current_msg is used to hold pointer to the message that is currently
+ * processed. If @current_msg is %NULL, it means that no processing is going
+ * on.
+ *
+ * Most of the fields are only written once and they can be accessed without
+ * taking the @lock. Fields that are accessed concurrently are: @current_msg,
+ * @running, and @msg_queue.
+ */
+struct ep93xx_spi {
+       spinlock_t                      lock;
+       const struct platform_device    *pdev;
+       struct clk                      *clk;
+       void __iomem                    *regs_base;
+       int                             irq;
+       unsigned long                   min_rate;
+       unsigned long                   max_rate;
+       bool                            running;
+       struct workqueue_struct         *wq;
+       struct work_struct              msg_work;
+       struct completion               wait;
+       struct list_head                msg_queue;
+       struct spi_message              *current_msg;
+       size_t                          tx;
+       size_t                          rx;
+       size_t                          fifo_level;
+};
+
+/**
+ * struct ep93xx_spi_chip - SPI device hardware settings
+ * @spi: back pointer to the SPI device
+ * @rate: max rate in hz this chip supports
+ * @div_cpsr: cpsr (pre-scaler) divider
+ * @div_scr: scr divider
+ * @dss: bits per word (4 - 16 bits)
+ * @ops: private chip operations
+ *
+ * This structure is used to store hardware register specific settings for each
+ * SPI device. Settings are written to hardware by function
+ * ep93xx_spi_chip_setup().
+ */
+struct ep93xx_spi_chip {
+       const struct spi_device         *spi;
+       unsigned long                   rate;
+       u8                              div_cpsr;
+       u8                              div_scr;
+       u8                              dss;
+       struct ep93xx_spi_chip_ops      *ops;
+};
+
+/* converts bits per word to CR0.DSS value */
+#define bits_per_word_to_dss(bpw)      ((bpw) - 1)
+
+static inline void
+ep93xx_spi_write_u8(const struct ep93xx_spi *espi, u16 reg, u8 value)
+{
+       __raw_writeb(value, espi->regs_base + reg);
+}
+
+static inline u8
+ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg)
+{
+       return __raw_readb(spi->regs_base + reg);
+}
+
+static inline void
+ep93xx_spi_write_u16(const struct ep93xx_spi *espi, u16 reg, u16 value)
+{
+       __raw_writew(value, espi->regs_base + reg);
+}
+
+static inline u16
+ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg)
+{
+       return __raw_readw(spi->regs_base + reg);
+}
+
+static int ep93xx_spi_enable(const struct ep93xx_spi *espi)
+{
+       u8 regval;
+       int err;
+
+       err = clk_enable(espi->clk);
+       if (err)
+               return err;
+
+       regval = ep93xx_spi_read_u8(espi, SSPCR1);
+       regval |= SSPCR1_SSE;
+       ep93xx_spi_write_u8(espi, SSPCR1, regval);
+
+       return 0;
+}
+
+static void ep93xx_spi_disable(const struct ep93xx_spi *espi)
+{
+       u8 regval;
+
+       regval = ep93xx_spi_read_u8(espi, SSPCR1);
+       regval &= ~SSPCR1_SSE;
+       ep93xx_spi_write_u8(espi, SSPCR1, regval);
+
+       clk_disable(espi->clk);
+}
+
+static void ep93xx_spi_enable_interrupts(const struct ep93xx_spi *espi)
+{
+       u8 regval;
+
+       regval = ep93xx_spi_read_u8(espi, SSPCR1);
+       regval |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
+       ep93xx_spi_write_u8(espi, SSPCR1, regval);
+}
+
+static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
+{
+       u8 regval;
+
+       regval = ep93xx_spi_read_u8(espi, SSPCR1);
+       regval &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
+       ep93xx_spi_write_u8(espi, SSPCR1, regval);
+}
+
+/**
+ * ep93xx_spi_calc_divisors() - calculates SPI clock divisors
+ * @espi: ep93xx SPI controller struct
+ * @chip: divisors are calculated for this chip
+ * @rate: desired SPI output clock rate
+ *
+ * Function calculates cpsr (clock pre-scaler) and scr divisors based on
+ * given @rate and places them to @chip->div_cpsr and @chip->div_scr. If,
+ * for some reason, divisors cannot be calculated nothing is stored and
+ * %-EINVAL is returned.
+ */
+static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
+                                   struct ep93xx_spi_chip *chip,
+                                   unsigned long rate)
+{
+       unsigned long spi_clk_rate = clk_get_rate(espi->clk);
+       int cpsr, scr;
+
+       /*
+        * Make sure that max value is between values supported by the
+        * controller. Note that minimum value is already checked in
+        * ep93xx_spi_transfer().
+        */
+       rate = clamp(rate, espi->min_rate, espi->max_rate);
+
+       /*
+        * Calculate divisors so that we can get speed according the
+        * following formula:
+        *      rate = spi_clock_rate / (cpsr * (1 + scr))
+        *
+        * cpsr must be even number and starts from 2, scr can be any number
+        * between 0 and 255.
+        */
+       for (cpsr = 2; cpsr <= 254; cpsr += 2) {
+               for (scr = 0; scr <= 255; scr++) {
+                       if ((spi_clk_rate / (cpsr * (scr + 1))) <= rate) {
+                               chip->div_scr = (u8)scr;
+                               chip->div_cpsr = (u8)cpsr;
+                               return 0;
+                       }
+               }
+       }
+
+       return -EINVAL;
+}
+
+static void ep93xx_spi_cs_control(struct spi_device *spi, bool control)
+{
+       struct ep93xx_spi_chip *chip = spi_get_ctldata(spi);
+       int value = (spi->mode & SPI_CS_HIGH) ? control : !control;
+
+       if (chip->ops && chip->ops->cs_control)
+               chip->ops->cs_control(spi, value);
+}
+
+/**
+ * ep93xx_spi_setup() - setup an SPI device
+ * @spi: SPI device to setup
+ *
+ * This function sets up SPI device mode, speed etc. Can be called multiple
+ * times for a single device. Returns %0 in case of success, negative error in
+ * case of failure. When this function returns success, the device is
+ * deselected.
+ */
+static int ep93xx_spi_setup(struct spi_device *spi)
+{
+       struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
+       struct ep93xx_spi_chip *chip;
+
+       if (spi->bits_per_word < 4 || spi->bits_per_word > 16) {
+               dev_err(&espi->pdev->dev, "invalid bits per word %d\n",
+                       spi->bits_per_word);
+               return -EINVAL;
+       }
+
+       chip = spi_get_ctldata(spi);
+       if (!chip) {
+               dev_dbg(&espi->pdev->dev, "initial setup for %s\n",
+                       spi->modalias);
+
+               chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+               if (!chip)
+                       return -ENOMEM;
+
+               chip->spi = spi;
+               chip->ops = spi->controller_data;
+
+               if (chip->ops && chip->ops->setup) {
+                       int ret = chip->ops->setup(spi);
+                       if (ret) {
+                               kfree(chip);
+                               return ret;
+                       }
+               }
+
+               spi_set_ctldata(spi, chip);
+       }
+
+       if (spi->max_speed_hz != chip->rate) {
+               int err;
+
+               err = ep93xx_spi_calc_divisors(espi, chip, spi->max_speed_hz);
+               if (err != 0) {
+                       spi_set_ctldata(spi, NULL);
+                       kfree(chip);
+                       return err;
+               }
+               chip->rate = spi->max_speed_hz;
+       }
+
+       chip->dss = bits_per_word_to_dss(spi->bits_per_word);
+
+       ep93xx_spi_cs_control(spi, false);
+       return 0;
+}
+
+/**
+ * ep93xx_spi_transfer() - queue message to be transferred
+ * @spi: target SPI device
+ * @msg: message to be transferred
+ *
+ * This function is called by SPI device drivers when they are going to transfer
+ * a new message. It simply puts the message in the queue and schedules
+ * workqueue to perform the actual transfer later on.
+ *
+ * Returns %0 on success and negative error in case of failure.
+ */
+static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+       struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
+       struct spi_transfer *t;
+       unsigned long flags;
+
+       if (!msg || !msg->complete)
+               return -EINVAL;
+
+       /* first validate each transfer */
+       list_for_each_entry(t, &msg->transfers, transfer_list) {
+               if (t->bits_per_word) {
+                       if (t->bits_per_word < 4 || t->bits_per_word > 16)
+                               return -EINVAL;
+               }
+               if (t->speed_hz && t->speed_hz < espi->min_rate)
+                               return -EINVAL;
+       }
+
+       /*
+        * Now that we own the message, let's initialize it so that it is
+        * suitable for us. We use @msg->status to signal whether there was
+        * error in transfer and @msg->state is used to hold pointer to the
+        * current transfer (or %NULL if no active current transfer).
+        */
+       msg->state = NULL;
+       msg->status = 0;
+       msg->actual_length = 0;
+
+       spin_lock_irqsave(&espi->lock, flags);
+       if (!espi->running) {
+               spin_unlock_irqrestore(&espi->lock, flags);
+               return -ESHUTDOWN;
+       }
+       list_add_tail(&msg->queue, &espi->msg_queue);
+       queue_work(espi->wq, &espi->msg_work);
+       spin_unlock_irqrestore(&espi->lock, flags);
+
+       return 0;
+}
+
+/**
+ * ep93xx_spi_cleanup() - cleans up master controller specific state
+ * @spi: SPI device to cleanup
+ *
+ * This function releases master controller specific state for given @spi
+ * device.
+ */
+static void ep93xx_spi_cleanup(struct spi_device *spi)
+{
+       struct ep93xx_spi_chip *chip;
+
+       chip = spi_get_ctldata(spi);
+       if (chip) {
+               if (chip->ops && chip->ops->cleanup)
+                       chip->ops->cleanup(spi);
+               spi_set_ctldata(spi, NULL);
+               kfree(chip);
+       }
+}
+
+/**
+ * ep93xx_spi_chip_setup() - configures hardware according to given @chip
+ * @espi: ep93xx SPI controller struct
+ * @chip: chip specific settings
+ *
+ * This function sets up the actual hardware registers with settings given in
+ * @chip. Note that no validation is done so make sure that callers validate
+ * settings before calling this.
+ */
+static void ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
+                                 const struct ep93xx_spi_chip *chip)
+{
+       u16 cr0;
+
+       cr0 = chip->div_scr << SSPCR0_SCR_SHIFT;
+       cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT;
+       cr0 |= chip->dss;
+
+       dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
+               chip->spi->mode, chip->div_cpsr, chip->div_scr, chip->dss);
+       dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0);
+
+       ep93xx_spi_write_u8(espi, SSPCPSR, chip->div_cpsr);
+       ep93xx_spi_write_u16(espi, SSPCR0, cr0);
+}
+
+static inline int bits_per_word(const struct ep93xx_spi *espi)
+{
+       struct spi_message *msg = espi->current_msg;
+       struct spi_transfer *t = msg->state;
+
+       return t->bits_per_word ? t->bits_per_word : msg->spi->bits_per_word;
+}
+
+static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
+{
+       if (bits_per_word(espi) > 8) {
+               u16 tx_val = 0;
+
+               if (t->tx_buf)
+                       tx_val = ((u16 *)t->tx_buf)[espi->tx];
+               ep93xx_spi_write_u16(espi, SSPDR, tx_val);
+               espi->tx += sizeof(tx_val);
+       } else {
+               u8 tx_val = 0;
+
+               if (t->tx_buf)
+                       tx_val = ((u8 *)t->tx_buf)[espi->tx];
+               ep93xx_spi_write_u8(espi, SSPDR, tx_val);
+               espi->tx += sizeof(tx_val);
+       }
+}
+
+static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
+{
+       if (bits_per_word(espi) > 8) {
+               u16 rx_val;
+
+               rx_val = ep93xx_spi_read_u16(espi, SSPDR);
+               if (t->rx_buf)
+                       ((u16 *)t->rx_buf)[espi->rx] = rx_val;
+               espi->rx += sizeof(rx_val);
+       } else {
+               u8 rx_val;
+
+               rx_val = ep93xx_spi_read_u8(espi, SSPDR);
+               if (t->rx_buf)
+                       ((u8 *)t->rx_buf)[espi->rx] = rx_val;
+               espi->rx += sizeof(rx_val);
+       }
+}
+
+/**
+ * ep93xx_spi_read_write() - perform next RX/TX transfer
+ * @espi: ep93xx SPI controller struct
+ *
+ * This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
+ * called several times, the whole transfer will be completed. Returns
+ * %-EINPROGRESS when current transfer was not yet completed otherwise %0.
+ *
+ * When this function is finished, RX FIFO should be empty and TX FIFO should be
+ * full.
+ */
+static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
+{
+       struct spi_message *msg = espi->current_msg;
+       struct spi_transfer *t = msg->state;
+
+       /* read as long as RX FIFO has frames in it */
+       while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
+               ep93xx_do_read(espi, t);
+               espi->fifo_level--;
+       }
+
+       /* write as long as TX FIFO has room */
+       while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
+               ep93xx_do_write(espi, t);
+               espi->fifo_level++;
+       }
+
+       if (espi->rx == t->len) {
+               msg->actual_length += t->len;
+               return 0;
+       }
+
+       return -EINPROGRESS;
+}
+
+/**
+ * ep93xx_spi_process_transfer() - processes one SPI transfer
+ * @espi: ep93xx SPI controller struct
+ * @msg: current message
+ * @t: transfer to process
+ *
+ * This function processes one SPI transfer given in @t. Function waits until
+ * transfer is complete (may sleep) and updates @msg->status based on whether
+ * transfer was succesfully processed or not.
+ */
+static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
+                                       struct spi_message *msg,
+                                       struct spi_transfer *t)
+{
+       struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi);
+
+       msg->state = t;
+
+       /*
+        * Handle any transfer specific settings if needed. We use
+        * temporary chip settings here and restore original later when
+        * the transfer is finished.
+        */
+       if (t->speed_hz || t->bits_per_word) {
+               struct ep93xx_spi_chip tmp_chip = *chip;
+
+               if (t->speed_hz) {
+                       int err;
+
+                       err = ep93xx_spi_calc_divisors(espi, &tmp_chip,
+                                                      t->speed_hz);
+                       if (err) {
+                               dev_err(&espi->pdev->dev,
+                                       "failed to adjust speed\n");
+                               msg->status = err;
+                               return;
+                       }
+               }
+
+               if (t->bits_per_word)
+                       tmp_chip.dss = bits_per_word_to_dss(t->bits_per_word);
+
+               /*
+                * Set up temporary new hw settings for this transfer.
+                */
+               ep93xx_spi_chip_setup(espi, &tmp_chip);
+       }
+
+       espi->rx = 0;
+       espi->tx = 0;
+
+       /*
+        * Now everything is set up for the current transfer. We prime the TX
+        * FIFO, enable interrupts, and wait for the transfer to complete.
+        */
+       if (ep93xx_spi_read_write(espi)) {
+               ep93xx_spi_enable_interrupts(espi);
+               wait_for_completion(&espi->wait);
+       }
+
+       /*
+        * In case of error during transmit, we bail out from processing
+        * the message.
+        */
+       if (msg->status)
+               return;
+
+       /*
+        * After this transfer is finished, perform any possible
+        * post-transfer actions requested by the protocol driver.
+        */
+       if (t->delay_usecs) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(usecs_to_jiffies(t->delay_usecs));
+       }
+       if (t->cs_change) {
+               if (!list_is_last(&t->transfer_list, &msg->transfers)) {
+                       /*
+                        * In case protocol driver is asking us to drop the
+                        * chipselect briefly, we let the scheduler to handle
+                        * any "delay" here.
+                        */
+                       ep93xx_spi_cs_control(msg->spi, false);
+                       cond_resched();
+                       ep93xx_spi_cs_control(msg->spi, true);
+               }
+       }
+
+       if (t->speed_hz || t->bits_per_word)
+               ep93xx_spi_chip_setup(espi, chip);
+}
+
+/*
+ * ep93xx_spi_process_message() - process one SPI message
+ * @espi: ep93xx SPI controller struct
+ * @msg: message to process
+ *
+ * This function processes a single SPI message. We go through all transfers in
+ * the message and pass them to ep93xx_spi_process_transfer(). Chipselect is
+ * asserted during the whole message (unless per transfer cs_change is set).
+ *
+ * @msg->status contains %0 in case of success or negative error code in case of
+ * failure.
+ */
+static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
+                                      struct spi_message *msg)
+{
+       unsigned long timeout;
+       struct spi_transfer *t;
+       int err;
+
+       /*
+        * Enable the SPI controller and its clock.
+        */
+       err = ep93xx_spi_enable(espi);
+       if (err) {
+               dev_err(&espi->pdev->dev, "failed to enable SPI controller\n");
+               msg->status = err;
+               return;
+       }
+
+       /*
+        * Just to be sure: flush any data from RX FIFO.
+        */
+       timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT);
+       while (ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_RNE) {
+               if (time_after(jiffies, timeout)) {
+                       dev_warn(&espi->pdev->dev,
+                                "timeout while flushing RX FIFO\n");
+                       msg->status = -ETIMEDOUT;
+                       return;
+               }
+               ep93xx_spi_read_u16(espi, SSPDR);
+       }
+
+       /*
+        * We explicitly handle FIFO level. This way we don't have to check TX
+        * FIFO status using %SSPSR_TNF bit which may cause RX FIFO overruns.
+        */
+       espi->fifo_level = 0;
+
+       /*
+        * Update SPI controller registers according to spi device and assert
+        * the chipselect.
+        */
+       ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
+       ep93xx_spi_cs_control(msg->spi, true);
+
+       list_for_each_entry(t, &msg->transfers, transfer_list) {
+               ep93xx_spi_process_transfer(espi, msg, t);
+               if (msg->status)
+                       break;
+       }
+
+       /*
+        * Now the whole message is transferred (or failed for some reason). We
+        * deselect the device and disable the SPI controller.
+        */
+       ep93xx_spi_cs_control(msg->spi, false);
+       ep93xx_spi_disable(espi);
+}
+
+#define work_to_espi(work) (container_of((work), struct ep93xx_spi, msg_work))
+
+/**
+ * ep93xx_spi_work() - EP93xx SPI workqueue worker function
+ * @work: work struct
+ *
+ * Workqueue worker function. This function is called when there are new
+ * SPI messages to be processed. Message is taken out from the queue and then
+ * passed to ep93xx_spi_process_message().
+ *
+ * After message is transferred, protocol driver is notified by calling
+ * @msg->complete(). In case of error, @msg->status is set to negative error
+ * number, otherwise it contains zero (and @msg->actual_length is updated).
+ */
+static void ep93xx_spi_work(struct work_struct *work)
+{
+       struct ep93xx_spi *espi = work_to_espi(work);
+       struct spi_message *msg;
+
+       spin_lock_irq(&espi->lock);
+       if (!espi->running || espi->current_msg ||
+               list_empty(&espi->msg_queue)) {
+               spin_unlock_irq(&espi->lock);
+               return;
+       }
+       msg = list_first_entry(&espi->msg_queue, struct spi_message, queue);
+       list_del_init(&msg->queue);
+       espi->current_msg = msg;
+       spin_unlock_irq(&espi->lock);
+
+       ep93xx_spi_process_message(espi, msg);
+
+       /*
+        * Update the current message and re-schedule ourselves if there are
+        * more messages in the queue.
+        */
+       spin_lock_irq(&espi->lock);
+       espi->current_msg = NULL;
+       if (espi->running && !list_empty(&espi->msg_queue))
+               queue_work(espi->wq, &espi->msg_work);
+       spin_unlock_irq(&espi->lock);
+
+       /* notify the protocol driver that we are done with this message */
+       msg->complete(msg->context);
+}
+
+static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
+{
+       struct ep93xx_spi *espi = dev_id;
+       u8 irq_status = ep93xx_spi_read_u8(espi, SSPIIR);
+
+       /*
+        * If we got ROR (receive overrun) interrupt we know that something is
+        * wrong. Just abort the message.
+        */
+       if (unlikely(irq_status & SSPIIR_RORIS)) {
+               /* clear the overrun interrupt */
+               ep93xx_spi_write_u8(espi, SSPICR, 0);
+               dev_warn(&espi->pdev->dev,
+                        "receive overrun, aborting the message\n");
+               espi->current_msg->status = -EIO;
+       } else {
+               /*
+                * Interrupt is either RX (RIS) or TX (TIS). For both cases we
+                * simply execute next data transfer.
+                */
+               if (ep93xx_spi_read_write(espi)) {
+                       /*
+                        * In normal case, there still is some processing left
+                        * for current transfer. Let's wait for the next
+                        * interrupt then.
+                        */
+                       return IRQ_HANDLED;
+               }
+       }
+
+       /*
+        * Current transfer is finished, either with error or with success. In
+        * any case we disable interrupts and notify the worker to handle
+        * any post-processing of the message.
+        */
+       ep93xx_spi_disable_interrupts(espi);
+       complete(&espi->wait);
+       return IRQ_HANDLED;
+}
+
+static int __init ep93xx_spi_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct ep93xx_spi_info *info;
+       struct ep93xx_spi *espi;
+       struct resource *res;
+       int error;
+
+       info = pdev->dev.platform_data;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(*espi));
+       if (!master) {
+               dev_err(&pdev->dev, "failed to allocate spi master\n");
+               return -ENOMEM;
+       }
+
+       master->setup = ep93xx_spi_setup;
+       master->transfer = ep93xx_spi_transfer;
+       master->cleanup = ep93xx_spi_cleanup;
+       master->bus_num = pdev->id;
+       master->num_chipselect = info->num_chipselect;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
+       platform_set_drvdata(pdev, master);
+
+       espi = spi_master_get_devdata(master);
+
+       espi->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(espi->clk)) {
+               dev_err(&pdev->dev, "unable to get spi clock\n");
+               error = PTR_ERR(espi->clk);
+               goto fail_release_master;
+       }
+
+       spin_lock_init(&espi->lock);
+       init_completion(&espi->wait);
+
+       /*
+        * Calculate maximum and minimum supported clock rates
+        * for the controller.
+        */
+       espi->max_rate = clk_get_rate(espi->clk) / 2;
+       espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
+       espi->pdev = pdev;
+
+       espi->irq = platform_get_irq(pdev, 0);
+       if (espi->irq < 0) {
+               error = -EBUSY;
+               dev_err(&pdev->dev, "failed to get irq resources\n");
+               goto fail_put_clock;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "unable to get iomem resource\n");
+               error = -ENODEV;
+               goto fail_put_clock;
+       }
+
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
+       if (!res) {
+               dev_err(&pdev->dev, "unable to request iomem resources\n");
+               error = -EBUSY;
+               goto fail_put_clock;
+       }
+
+       espi->regs_base = ioremap(res->start, resource_size(res));
+       if (!espi->regs_base) {
+               dev_err(&pdev->dev, "failed to map resources\n");
+               error = -ENODEV;
+               goto fail_free_mem;
+       }
+
+       error = request_irq(espi->irq, ep93xx_spi_interrupt, 0,
+                           "ep93xx-spi", espi);
+       if (error) {
+               dev_err(&pdev->dev, "failed to request irq\n");
+               goto fail_unmap_regs;
+       }
+
+       espi->wq = create_singlethread_workqueue("ep93xx_spid");
+       if (!espi->wq) {
+               dev_err(&pdev->dev, "unable to create workqueue\n");
+               goto fail_free_irq;
+       }
+       INIT_WORK(&espi->msg_work, ep93xx_spi_work);
+       INIT_LIST_HEAD(&espi->msg_queue);
+       espi->running = true;
+
+       /* make sure that the hardware is disabled */
+       ep93xx_spi_write_u8(espi, SSPCR1, 0);
+
+       error = spi_register_master(master);
+       if (error) {
+               dev_err(&pdev->dev, "failed to register SPI master\n");
+               goto fail_free_queue;
+       }
+
+       dev_info(&pdev->dev, "EP93xx SPI Controller at 0x%08lx irq %d\n",
+                (unsigned long)res->start, espi->irq);
+
+       return 0;
+
+fail_free_queue:
+       destroy_workqueue(espi->wq);
+fail_free_irq:
+       free_irq(espi->irq, espi);
+fail_unmap_regs:
+       iounmap(espi->regs_base);
+fail_free_mem:
+       release_mem_region(res->start, resource_size(res));
+fail_put_clock:
+       clk_put(espi->clk);
+fail_release_master:
+       spi_master_put(master);
+       platform_set_drvdata(pdev, NULL);
+
+       return error;
+}
+
+static int __exit ep93xx_spi_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct ep93xx_spi *espi = spi_master_get_devdata(master);
+       struct resource *res;
+
+       spin_lock_irq(&espi->lock);
+       espi->running = false;
+       spin_unlock_irq(&espi->lock);
+
+       destroy_workqueue(espi->wq);
+
+       /*
+        * Complete remaining messages with %-ESHUTDOWN status.
+        */
+       spin_lock_irq(&espi->lock);
+       while (!list_empty(&espi->msg_queue)) {
+               struct spi_message *msg;
+
+               msg = list_first_entry(&espi->msg_queue,
+                                      struct spi_message, queue);
+               list_del_init(&msg->queue);
+               msg->status = -ESHUTDOWN;
+               spin_unlock_irq(&espi->lock);
+               msg->complete(msg->context);
+               spin_lock_irq(&espi->lock);
+       }
+       spin_unlock_irq(&espi->lock);
+
+       free_irq(espi->irq, espi);
+       iounmap(espi->regs_base);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+       clk_put(espi->clk);
+       platform_set_drvdata(pdev, NULL);
+
+       spi_unregister_master(master);
+       return 0;
+}
+
+static struct platform_driver ep93xx_spi_driver = {
+       .driver         = {
+               .name   = "ep93xx-spi",
+               .owner  = THIS_MODULE,
+       },
+       .remove         = __exit_p(ep93xx_spi_remove),
+};
+
+static int __init ep93xx_spi_init(void)
+{
+       return platform_driver_probe(&ep93xx_spi_driver, ep93xx_spi_probe);
+}
+module_init(ep93xx_spi_init);
+
+static void __exit ep93xx_spi_exit(void)
+{
+       platform_driver_unregister(&ep93xx_spi_driver);
+}
+module_exit(ep93xx_spi_exit);
+
+MODULE_DESCRIPTION("EP93xx SPI Controller driver");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-spi");