All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/2] spi: driver for Cirrus EP93xx SPI controller
@ 2010-05-02 14:38 ` Mika Westerberg
  0 siblings, 0 replies; 28+ messages in thread
From: Mika Westerberg @ 2010-05-02 14:38 UTC (permalink / raw)
  To: spi-devel-general
  Cc: grant.likely, hartleys, ryan, martinwguy, linux-arm-kernel

Hello,

This series implements SPI master driver for Cirrus Logic EP93xx SPI
controllers.

This is sixth iteration of the driver.

Changes to the previous version:
	- addressed most review comments by H. Hartley Sweeten
	- incorporated GPIO chipselect patch by H. Hartley Sweeten

I tested this on TS-7260 board with at25 and mmc_spi drivers. Now that I have
Sim.One board, which is EP9307 based, I also tested with that (I hacked the
board a bit to get EGPIO9 as a chip select).

Note that patch 2/2 depends on patch that is already in Russell's patch
tracking system:
	http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=5998/1

Thanks,
MW

Mika Westerberg (2):
  spi: implemented driver for Cirrus EP93xx SPI controller
  ep93xx: SPI driver platform support code

 Documentation/spi/ep93xx_spi                    |   95 +++
 arch/arm/mach-ep93xx/clock.c                    |   13 +
 arch/arm/mach-ep93xx/core.c                     |   53 ++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h  |   27 +
 arch/arm/mach-ep93xx/include/mach/platform.h    |    4 +
 drivers/spi/Kconfig                             |   10 +
 drivers/spi/Makefile                            |    1 +
 drivers/spi/ep93xx_spi.c                        |  986 +++++++++++++++++++++++
 9 files changed, 1190 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/spi/ep93xx_spi
 create mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
 create mode 100644 drivers/spi/ep93xx_spi.c

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 0/2] spi: driver for Cirrus EP93xx SPI controller
@ 2010-05-02 14:38 ` Mika Westerberg
  0 siblings, 0 replies; 28+ messages in thread
From: Mika Westerberg @ 2010-05-02 14:38 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

This series implements SPI master driver for Cirrus Logic EP93xx SPI
controllers.

This is sixth iteration of the driver.

Changes to the previous version:
	- addressed most review comments by H. Hartley Sweeten
	- incorporated GPIO chipselect patch by H. Hartley Sweeten

I tested this on TS-7260 board with at25 and mmc_spi drivers. Now that I have
Sim.One board, which is EP9307 based, I also tested with that (I hacked the
board a bit to get EGPIO9 as a chip select).

Note that patch 2/2 depends on patch that is already in Russell's patch
tracking system:
	http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=5998/1

Thanks,
MW

Mika Westerberg (2):
  spi: implemented driver for Cirrus EP93xx SPI controller
  ep93xx: SPI driver platform support code

 Documentation/spi/ep93xx_spi                    |   95 +++
 arch/arm/mach-ep93xx/clock.c                    |   13 +
 arch/arm/mach-ep93xx/core.c                     |   53 ++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h  |   27 +
 arch/arm/mach-ep93xx/include/mach/platform.h    |    4 +
 drivers/spi/Kconfig                             |   10 +
 drivers/spi/Makefile                            |    1 +
 drivers/spi/ep93xx_spi.c                        |  986 +++++++++++++++++++++++
 9 files changed, 1190 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/spi/ep93xx_spi
 create mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
 create mode 100644 drivers/spi/ep93xx_spi.c

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-05-02 14:38 ` Mika Westerberg
@ 2010-05-02 14:38     ` Mika Westerberg
  -1 siblings, 0 replies; 28+ messages in thread
From: Mika Westerberg @ 2010-05-02 14:38 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: ryan-7Wk5F4Od5/oYd5yxfr4S2w, martinwguy-Re5JQEeQqe8AvxtiuMwx3w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
in EP93xx chips.

Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>
---
 Documentation/spi/ep93xx_spi                   |   95 +++
 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h |   27 +
 drivers/spi/Kconfig                            |   10 +
 drivers/spi/Makefile                           |    1 +
 drivers/spi/ep93xx_spi.c                       |  986 ++++++++++++++++++++++++
 5 files changed, 1119 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/spi/ep93xx_spi
 create mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
 create mode 100644 drivers/spi/ep93xx_spi.c

diff --git a/Documentation/spi/ep93xx_spi b/Documentation/spi/ep93xx_spi
new file mode 100644
index 0000000..6325f5b
--- /dev/null
+++ b/Documentation/spi/ep93xx_spi
@@ -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
index 0000000..0a37961
--- /dev/null
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
@@ -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 */
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a191fa2..2b2f4c3 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -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
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d7d0f89..377f845 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -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
index 0000000..2fbd489
--- /dev/null
+++ b/drivers/spi/ep93xx_spi.c
@@ -0,0 +1,986 @@
+/*
+ * 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);
+}
+
+/**
+ * ep93xx_spi_enable() - enables the SPI controller and clock
+ * @espi: ep93xx SPI controller struct
+ *
+ * This function enables the SPI controller and its clock. Returns %0 in case
+ * of success and negative error in case if failure.
+ */
+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;
+}
+
+/**
+ * ep93xx_spi_disable() - disables the SPI controller and clock
+ * @espi: ep93xx SPI controller struct
+ *
+ * Function disables SPI controller and its clock.
+ */
+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);
+}
+
+/**
+ * ep93xx_spi_enable_interrupts() - enables all SPI interrupts
+ * @espi: ep93xx SPI controller struct
+ *
+ * Enables all SPI interrupts: receive overrun (ROR), transmit, and receive.
+ */
+static inline 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);
+}
+
+/**
+ * ep93xx_spi_disable_interrupts() - disables all SPI interrupts
+ * @espi: ep93xx SPI controller struct
+ *
+ * Disables all SPI interrupts.
+ */
+static inline 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;
+}
+
+/**
+ * ep93xx_spi_cs_control() - controls chipselect for given device
+ * @spi: SPI device to select/deselect
+ * @control: select (%true) / deselect (%false)
+ *
+ * Function controls chipselect line for given SPI device.
+ *
+ * Note that this function is called from a thread context and can sleep.
+ */
+static inline 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);
+}
+
+/**
+ * bits_per_word() - returns bits per word for current message
+ */
+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);
+}
+
+/**
+ * ep93xx_spi_interrupt() - SPI interrupt handler
+ * @irq: IRQ number (not used)
+ * @dev_id: pointer to EP93xx controller struct
+ *
+ * This function handles TX/RX/ROR interrupts which come from the SPI
+ * controller.
+ */
+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-X3B1VOXEql0@public.gmane.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-spi");
-- 
1.5.6.5


------------------------------------------------------------------------------

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-05-02 14:38     ` Mika Westerberg
  0 siblings, 0 replies; 28+ messages in thread
From: Mika Westerberg @ 2010-05-02 14:38 UTC (permalink / raw)
  To: linux-arm-kernel

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>
---
 Documentation/spi/ep93xx_spi                   |   95 +++
 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h |   27 +
 drivers/spi/Kconfig                            |   10 +
 drivers/spi/Makefile                           |    1 +
 drivers/spi/ep93xx_spi.c                       |  986 ++++++++++++++++++++++++
 5 files changed, 1119 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/spi/ep93xx_spi
 create mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
 create mode 100644 drivers/spi/ep93xx_spi.c

diff --git a/Documentation/spi/ep93xx_spi b/Documentation/spi/ep93xx_spi
new file mode 100644
index 0000000..6325f5b
--- /dev/null
+++ b/Documentation/spi/ep93xx_spi
@@ -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
index 0000000..0a37961
--- /dev/null
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
@@ -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 */
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a191fa2..2b2f4c3 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -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
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d7d0f89..377f845 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -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
index 0000000..2fbd489
--- /dev/null
+++ b/drivers/spi/ep93xx_spi.c
@@ -0,0 +1,986 @@
+/*
+ * 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);
+}
+
+/**
+ * ep93xx_spi_enable() - enables the SPI controller and clock
+ * @espi: ep93xx SPI controller struct
+ *
+ * This function enables the SPI controller and its clock. Returns %0 in case
+ * of success and negative error in case if failure.
+ */
+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;
+}
+
+/**
+ * ep93xx_spi_disable() - disables the SPI controller and clock
+ * @espi: ep93xx SPI controller struct
+ *
+ * Function disables SPI controller and its clock.
+ */
+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);
+}
+
+/**
+ * ep93xx_spi_enable_interrupts() - enables all SPI interrupts
+ * @espi: ep93xx SPI controller struct
+ *
+ * Enables all SPI interrupts: receive overrun (ROR), transmit, and receive.
+ */
+static inline 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);
+}
+
+/**
+ * ep93xx_spi_disable_interrupts() - disables all SPI interrupts
+ * @espi: ep93xx SPI controller struct
+ *
+ * Disables all SPI interrupts.
+ */
+static inline 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;
+}
+
+/**
+ * ep93xx_spi_cs_control() - controls chipselect for given device
+ * @spi: SPI device to select/deselect
+ * @control: select (%true) / deselect (%false)
+ *
+ * Function controls chipselect line for given SPI device.
+ *
+ * Note that this function is called from a thread context and can sleep.
+ */
+static inline 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);
+}
+
+/**
+ * bits_per_word() - returns bits per word for current message
+ */
+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);
+}
+
+/**
+ * ep93xx_spi_interrupt() - SPI interrupt handler
+ * @irq: IRQ number (not used)
+ * @dev_id: pointer to EP93xx controller struct
+ *
+ * This function handles TX/RX/ROR interrupts which come from the SPI
+ * controller.
+ */
+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");
-- 
1.5.6.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 2/2] ep93xx: SPI driver platform support code
  2010-05-02 14:38 ` Mika Westerberg
@ 2010-05-02 14:39   ` Mika Westerberg
  -1 siblings, 0 replies; 28+ messages in thread
From: Mika Westerberg @ 2010-05-02 14:39 UTC (permalink / raw)
  To: spi-devel-general
  Cc: grant.likely, hartleys, ryan, martinwguy, linux-arm-kernel

This patch adds platform side support code for the EP93xx SPI driver. This
includes clock, resources and muxing. There is a new function: ep93xx_register_spi()
which can be used by board support code to register new SPI devices for the
board.

Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
---
Patch depends on following ARM patch:
	5998/1 ep93xx: added chip revision reading function

 arch/arm/mach-ep93xx/clock.c                    |   13 ++++++
 arch/arm/mach-ep93xx/core.c                     |   53 +++++++++++++++++++++++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
 arch/arm/mach-ep93xx/include/mach/platform.h    |    4 ++
 4 files changed, 71 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 5f80092..e29bdef 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -96,6 +96,10 @@ static struct clk clk_keypad = {
 	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
 	.set_rate	= set_keytchclk_rate,
 };
+static struct clk clk_spi = {
+	.parent		= &clk_xtali,
+	.rate		= EP93XX_EXT_CLK_RATE,
+};
 static struct clk clk_pwm = {
 	.parent		= &clk_xtali,
 	.rate		= EP93XX_EXT_CLK_RATE,
@@ -186,6 +190,7 @@ static struct clk_lookup clocks[] = {
 	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
 	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
 	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
+	INIT_CK("ep93xx-spi.0",		NULL,		&clk_spi),
 	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
 	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
 	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
@@ -473,6 +478,14 @@ static int __init ep93xx_clock_init(void)
 	/* Initialize the pll2 derived clocks */
 	clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
 
+	/*
+	 * EP93xx SSP clock rate was doubled in version E2. For more information
+	 * see:
+	 *     http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
+	 */
+	if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
+		clk_spi.rate /= 2;
+
 	pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
 		clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
 	pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 90fb591..f3b46b9 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -31,10 +31,12 @@
 #include <linux/amba/serial.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
+#include <linux/spi/spi.h>
 
 #include <mach/hardware.h>
 #include <mach/fb.h>
 #include <mach/ep93xx_keypad.h>
+#include <mach/ep93xx_spi.h>
 
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
@@ -398,6 +400,57 @@ void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
 	platform_device_register(&ep93xx_i2c_device);
 }
 
+/*************************************************************************
+ * EP93xx SPI peripheral handling
+ *************************************************************************/
+static struct ep93xx_spi_info ep93xx_spi_master_data;
+
+static struct resource ep93xx_spi_resources[] = {
+	{
+		.start	= EP93XX_SPI_PHYS_BASE,
+		.end	= EP93XX_SPI_PHYS_BASE + 0x18 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_EP93XX_SSP,
+		.end	= IRQ_EP93XX_SSP,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ep93xx_spi_device = {
+	.name		= "ep93xx-spi",
+	.id		= 0,
+	.dev		= {
+		.platform_data = &ep93xx_spi_master_data,
+	},
+	.num_resources	= ARRAY_SIZE(ep93xx_spi_resources),
+	.resource	= ep93xx_spi_resources,
+};
+
+/**
+ * ep93xx_register_spi() - registers spi platform device
+ * @info: ep93xx board specific spi master info (__initdata)
+ * @devices: SPI devices to register (__initdata)
+ * @num: number of SPI devices to register
+ *
+ * This function registers platform device for the EP93xx SPI controller and
+ * also makes sure that SPI pins are muxed so that I2S is not using those pins.
+ * Caller should allocate necessary GPIO lines before before calling this.
+ */
+void __init ep93xx_register_spi(struct ep93xx_spi_info *info,
+				struct spi_board_info *devices, int num)
+{
+	/*
+	 * When SPI is used, we need to make sure that I2S is muxed off from
+	 * SPI pins.
+	 */
+	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP);
+
+	ep93xx_spi_master_data = *info;
+	spi_register_board_info(devices, num);
+	platform_device_register(&ep93xx_spi_device);
+}
 
 /*************************************************************************
  * EP93xx LEDs
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index 93e2ecc..b1e096f 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -106,6 +106,7 @@
 
 #define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
 
+#define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)
 #define EP93XX_SPI_BASE			EP93XX_APB_IOMEM(0x000a0000)
 
 #define EP93XX_IRDA_BASE		EP93XX_APB_IOMEM(0x000b0000)
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index c6dc14d..f11f1d7 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -6,9 +6,11 @@
 
 struct i2c_gpio_platform_data;
 struct i2c_board_info;
+struct spi_board_info;
 struct platform_device;
 struct ep93xxfb_mach_info;
 struct ep93xx_keypad_platform_data;
+struct ep93xx_spi_info;
 
 struct ep93xx_eth_data
 {
@@ -36,6 +38,8 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
 void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
 void ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
 			 struct i2c_board_info *devices, int num);
+void ep93xx_register_spi(struct ep93xx_spi_info *info,
+			 struct spi_board_info *devices, int num);
 void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
 void ep93xx_register_pwm(int pwm0, int pwm1);
 int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
-- 
1.5.6.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 2/2] ep93xx: SPI driver platform support code
@ 2010-05-02 14:39   ` Mika Westerberg
  0 siblings, 0 replies; 28+ messages in thread
From: Mika Westerberg @ 2010-05-02 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds platform side support code for the EP93xx SPI driver. This
includes clock, resources and muxing. There is a new function: ep93xx_register_spi()
which can be used by board support code to register new SPI devices for the
board.

Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
---
Patch depends on following ARM patch:
	5998/1 ep93xx: added chip revision reading function

 arch/arm/mach-ep93xx/clock.c                    |   13 ++++++
 arch/arm/mach-ep93xx/core.c                     |   53 +++++++++++++++++++++++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
 arch/arm/mach-ep93xx/include/mach/platform.h    |    4 ++
 4 files changed, 71 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 5f80092..e29bdef 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -96,6 +96,10 @@ static struct clk clk_keypad = {
 	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
 	.set_rate	= set_keytchclk_rate,
 };
+static struct clk clk_spi = {
+	.parent		= &clk_xtali,
+	.rate		= EP93XX_EXT_CLK_RATE,
+};
 static struct clk clk_pwm = {
 	.parent		= &clk_xtali,
 	.rate		= EP93XX_EXT_CLK_RATE,
@@ -186,6 +190,7 @@ static struct clk_lookup clocks[] = {
 	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
 	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
 	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
+	INIT_CK("ep93xx-spi.0",		NULL,		&clk_spi),
 	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
 	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
 	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
@@ -473,6 +478,14 @@ static int __init ep93xx_clock_init(void)
 	/* Initialize the pll2 derived clocks */
 	clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
 
+	/*
+	 * EP93xx SSP clock rate was doubled in version E2. For more information
+	 * see:
+	 *     http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
+	 */
+	if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
+		clk_spi.rate /= 2;
+
 	pr_info("PLL1 running at %ld MHz, PLL2@%ld MHz\n",
 		clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
 	pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 90fb591..f3b46b9 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -31,10 +31,12 @@
 #include <linux/amba/serial.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
+#include <linux/spi/spi.h>
 
 #include <mach/hardware.h>
 #include <mach/fb.h>
 #include <mach/ep93xx_keypad.h>
+#include <mach/ep93xx_spi.h>
 
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
@@ -398,6 +400,57 @@ void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
 	platform_device_register(&ep93xx_i2c_device);
 }
 
+/*************************************************************************
+ * EP93xx SPI peripheral handling
+ *************************************************************************/
+static struct ep93xx_spi_info ep93xx_spi_master_data;
+
+static struct resource ep93xx_spi_resources[] = {
+	{
+		.start	= EP93XX_SPI_PHYS_BASE,
+		.end	= EP93XX_SPI_PHYS_BASE + 0x18 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_EP93XX_SSP,
+		.end	= IRQ_EP93XX_SSP,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ep93xx_spi_device = {
+	.name		= "ep93xx-spi",
+	.id		= 0,
+	.dev		= {
+		.platform_data = &ep93xx_spi_master_data,
+	},
+	.num_resources	= ARRAY_SIZE(ep93xx_spi_resources),
+	.resource	= ep93xx_spi_resources,
+};
+
+/**
+ * ep93xx_register_spi() - registers spi platform device
+ * @info: ep93xx board specific spi master info (__initdata)
+ * @devices: SPI devices to register (__initdata)
+ * @num: number of SPI devices to register
+ *
+ * This function registers platform device for the EP93xx SPI controller and
+ * also makes sure that SPI pins are muxed so that I2S is not using those pins.
+ * Caller should allocate necessary GPIO lines before before calling this.
+ */
+void __init ep93xx_register_spi(struct ep93xx_spi_info *info,
+				struct spi_board_info *devices, int num)
+{
+	/*
+	 * When SPI is used, we need to make sure that I2S is muxed off from
+	 * SPI pins.
+	 */
+	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP);
+
+	ep93xx_spi_master_data = *info;
+	spi_register_board_info(devices, num);
+	platform_device_register(&ep93xx_spi_device);
+}
 
 /*************************************************************************
  * EP93xx LEDs
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index 93e2ecc..b1e096f 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -106,6 +106,7 @@
 
 #define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
 
+#define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)
 #define EP93XX_SPI_BASE			EP93XX_APB_IOMEM(0x000a0000)
 
 #define EP93XX_IRDA_BASE		EP93XX_APB_IOMEM(0x000b0000)
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index c6dc14d..f11f1d7 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -6,9 +6,11 @@
 
 struct i2c_gpio_platform_data;
 struct i2c_board_info;
+struct spi_board_info;
 struct platform_device;
 struct ep93xxfb_mach_info;
 struct ep93xx_keypad_platform_data;
+struct ep93xx_spi_info;
 
 struct ep93xx_eth_data
 {
@@ -36,6 +38,8 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
 void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
 void ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
 			 struct i2c_board_info *devices, int num);
+void ep93xx_register_spi(struct ep93xx_spi_info *info,
+			 struct spi_board_info *devices, int num);
 void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
 void ep93xx_register_pwm(int pwm0, int pwm1);
 int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
-- 
1.5.6.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [spi-devel-general] [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-05-02 14:38     ` Mika Westerberg
@ 2010-05-03  0:18       ` Linus Walleij
  -1 siblings, 0 replies; 28+ messages in thread
From: Linus Walleij @ 2010-05-03  0:18 UTC (permalink / raw)
  To: Mika Westerberg; +Cc: spi-devel-general, ryan, martinwguy, linux-arm-kernel

2010/5/2 Mika Westerberg <mika.westerberg@iki.fi>:

> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> in EP93xx chips.
(...)
> +#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

When I look at this it's quite obvious that this is the same hardware or very
close (maybe a redux version) of the thing supported by
drivers/spi/amba-pl022.c.

What is the difference really? I suspect this is a PL022 PrimeCell straight off.
Even the CPSR algorithm is the same, just written differently.

Can you make a hexdump of the PrimeCell ID registers at offset
base+0xffe0..0xffff and post the contents?

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [spi-devel-general] [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-05-03  0:18       ` Linus Walleij
  0 siblings, 0 replies; 28+ messages in thread
From: Linus Walleij @ 2010-05-03  0:18 UTC (permalink / raw)
  To: linux-arm-kernel

2010/5/2 Mika Westerberg <mika.westerberg@iki.fi>:

> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> in EP93xx chips.
(...)
> +#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

When I look at this it's quite obvious that this is the same hardware or very
close (maybe a redux version) of the thing supported by
drivers/spi/amba-pl022.c.

What is the difference really? I suspect this is a PL022 PrimeCell straight off.
Even the CPSR algorithm is the same, just written differently.

Can you make a hexdump of the PrimeCell ID registers at offset
base+0xffe0..0xffff and post the contents?

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-05-03  0:18       ` Linus Walleij
@ 2010-05-03  4:21           ` Mika Westerberg
  -1 siblings, 0 replies; 28+ messages in thread
From: Mika Westerberg @ 2010-05-03  4:21 UTC (permalink / raw)
  To: Linus Walleij
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w, martinwguy-Re5JQEeQqe8AvxtiuMwx3w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Mon, May 03, 2010 at 02:18:44AM +0200, Linus Walleij wrote:
> 2010/5/2 Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>:
> 
> > This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> > in EP93xx chips.
> (...)
> > +#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
> 
> When I look at this it's quite obvious that this is the same hardware or very
> close (maybe a redux version) of the thing supported by
> drivers/spi/amba-pl022.c.

Yeah. It looks pretty similar. Although there seems to be differences. Documentation
of the controller can be found in:

	http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf

It does not mention anything about AMBA PL022.

> What is the difference really? I suspect this is a PL022 PrimeCell straight off.
> Even the CPSR algorithm is the same, just written differently.

There are differences, for example PL022 has 4 interrupt registers (SSPIMSC, SSPRIS,
SSPMIS and SSPICR) whereas EP93xx has only one. SSPCR1 is different (in EP93xx we have
interrupt enable/disable bits there) etc.

> Can you make a hexdump of the PrimeCell ID registers at offset
> base+0xffe0..0xffff and post the contents?

Here it is, you probably meant base + 0xfe0 .. 0xfff, right?

[    2.410000] 0xc6070fe0: 0x0
[    2.410000] 0xc6070fe4: 0x0
[    2.410000] 0xc6070fe8: 0x0
[    2.420000] 0xc6070fec: 0x0
[    2.420000] 0xc6070ff0: 0x0
[    2.420000] 0xc6070ff4: 0x0
[    2.430000] 0xc6070ff8: 0x0
[    2.430000] 0xc6070ffc: 0x0

Thanks,
MW

------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [spi-devel-general] [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-05-03  4:21           ` Mika Westerberg
  0 siblings, 0 replies; 28+ messages in thread
From: Mika Westerberg @ 2010-05-03  4:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, May 03, 2010 at 02:18:44AM +0200, Linus Walleij wrote:
> 2010/5/2 Mika Westerberg <mika.westerberg@iki.fi>:
> 
> > This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> > in EP93xx chips.
> (...)
> > +#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
> 
> When I look at this it's quite obvious that this is the same hardware or very
> close (maybe a redux version) of the thing supported by
> drivers/spi/amba-pl022.c.

Yeah. It looks pretty similar. Although there seems to be differences. Documentation
of the controller can be found in:

	http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf

It does not mention anything about AMBA PL022.

> What is the difference really? I suspect this is a PL022 PrimeCell straight off.
> Even the CPSR algorithm is the same, just written differently.

There are differences, for example PL022 has 4 interrupt registers (SSPIMSC, SSPRIS,
SSPMIS and SSPICR) whereas EP93xx has only one. SSPCR1 is different (in EP93xx we have
interrupt enable/disable bits there) etc.

> Can you make a hexdump of the PrimeCell ID registers at offset
> base+0xffe0..0xffff and post the contents?

Here it is, you probably meant base + 0xfe0 .. 0xfff, right?

[    2.410000] 0xc6070fe0: 0x0
[    2.410000] 0xc6070fe4: 0x0
[    2.410000] 0xc6070fe8: 0x0
[    2.420000] 0xc6070fec: 0x0
[    2.420000] 0xc6070ff0: 0x0
[    2.420000] 0xc6070ff4: 0x0
[    2.430000] 0xc6070ff8: 0x0
[    2.430000] 0xc6070ffc: 0x0

Thanks,
MW

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-05-03  4:21           ` [spi-devel-general] " Mika Westerberg
@ 2010-05-03 13:18               ` Linus Walleij
  -1 siblings, 0 replies; 28+ messages in thread
From: Linus Walleij @ 2010-05-03 13:18 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w, martinwguy-Re5JQEeQqe8AvxtiuMwx3w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

2010/5/3 Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>:

> Yeah. It looks pretty similar. Although there seems to be differences. Documentation
> of the controller can be found in:
>
>        http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf
>
> It does not mention anything about AMBA PL022.

They have surely based the hardware on the PL022. A diff document would
surely be useful, can Cirrus answer that kind of questions for you?

Hm, it has to be *really* different to warrant a totally new driver
duplicate code is never fun...

>> Can you make a hexdump of the PrimeCell ID registers at offset
>> base+0xffe0..0xffff and post the contents?
>
> Here it is, you probably meant base + 0xfe0 .. 0xfff, right?
>
> [    2.410000] 0xc6070fe0: 0x0
> [    2.410000] 0xc6070fe4: 0x0
> [    2.410000] 0xc6070fe8: 0x0
> [    2.420000] 0xc6070fec: 0x0
> [    2.420000] 0xc6070ff0: 0x0
> [    2.420000] 0xc6070ff4: 0x0
> [    2.430000] 0xc6070ff8: 0x0
> [    2.430000] 0xc6070ffc: 0x0

Looks like it's been blanked out so atleast it is not identifying itself as
a PL022 anymore.

It could also be that PL022 and the Cirrus controller has some common
ancestor...

Yours,
Linus Walleij

------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [spi-devel-general] [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-05-03 13:18               ` Linus Walleij
  0 siblings, 0 replies; 28+ messages in thread
From: Linus Walleij @ 2010-05-03 13:18 UTC (permalink / raw)
  To: linux-arm-kernel

2010/5/3 Mika Westerberg <mika.westerberg@iki.fi>:

> Yeah. It looks pretty similar. Although there seems to be differences. Documentation
> of the controller can be found in:
>
> ? ? ? ?http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf
>
> It does not mention anything about AMBA PL022.

They have surely based the hardware on the PL022. A diff document would
surely be useful, can Cirrus answer that kind of questions for you?

Hm, it has to be *really* different to warrant a totally new driver
duplicate code is never fun...

>> Can you make a hexdump of the PrimeCell ID registers at offset
>> base+0xffe0..0xffff and post the contents?
>
> Here it is, you probably meant base + 0xfe0 .. 0xfff, right?
>
> [ ? ?2.410000] 0xc6070fe0: 0x0
> [ ? ?2.410000] 0xc6070fe4: 0x0
> [ ? ?2.410000] 0xc6070fe8: 0x0
> [ ? ?2.420000] 0xc6070fec: 0x0
> [ ? ?2.420000] 0xc6070ff0: 0x0
> [ ? ?2.420000] 0xc6070ff4: 0x0
> [ ? ?2.430000] 0xc6070ff8: 0x0
> [ ? ?2.430000] 0xc6070ffc: 0x0

Looks like it's been blanked out so atleast it is not identifying itself as
a PL022 anymore.

It could also be that PL022 and the Cirrus controller has some common
ancestor...

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-05-03  0:18       ` Linus Walleij
@ 2010-05-03 17:00           ` H Hartley Sweeten
  -1 siblings, 0 replies; 28+ messages in thread
From: H Hartley Sweeten @ 2010-05-03 17:00 UTC (permalink / raw)
  To: Linus Walleij, Mika Westerberg
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w, martinwguy-Re5JQEeQqe8AvxtiuMwx3w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Sunday, May 02, 2010 5:19 PM, Linus Walleij wrote:
> 2010/5/2 Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>:
>> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
>> in EP93xx chips.
>(...)
>> +#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
>
> When I look at this it's quite obvious that this is the same hardware or very
> close (maybe a redux version) of the thing supported by
> drivers/spi/amba-pl022.c.
>
> What is the difference really? I suspect this is a PL022 PrimeCell straight off.
> Even the CPSR algorithm is the same, just written differently.
>
> Can you make a hexdump of the PrimeCell ID registers at offset
> base+0xffe0..0xffff and post the contents?

Linus,

As Mika already pointed out, the ep93xx ssp peripheral does not have a valid
PeripheralID or PrimeCellID to identify it as an AMBA PL022 peripheral.

It probably was originally based on the PL022 but I think Cirrus hacked it
enough that the generic amba-pl022 driver will not work with it, at least
without a number of ugly #ifdef hacks.

Or, I could be wrong.  It appears the amba-pl022 driver doesn't actually match
the ARM spec for the PL022.

#define SSP_CR0(r)	(r + 0x000)

/*
 * 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)

The spec says that the DSS bits are only bits 3:0 (16-bit transfers), the
driver has them as bits 4:0 (32-bit transfers).
HALFDUP is not listed in the spec, and FRF is listed as bits 5:4.
CSS is not listed in the spec.

The PL022 spec actually matches the EP93xx usage.

#define SSP_CR1(r)	(r + 0x004)

/*
 * 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)

Bits 15:4 are listed as reserved in the spec, bits 3:0 match the spec. 
The EP93xx usage of this register is different.

0  RIE    Receive FIFO interrupt enable
1  TIE    Transmit FIFO interrupt enable
2  RORIE  Receive FIFO overrun interrupt enable
3  LBM    Loop back mode
4  SSE    Synchronous serial port enable
5  MS     Master / Slave mode select
6  SOD    Slave-mode output disable

#define SSP_DR(r)	(r + 0x008)

/*
 * SSP Data Register - SSP_DR
 */
#define SSP_DR_MASK_DATA	0xFFFFFFFF

The PL022 spec only shows the peripheral as supporting up to 16-bit transfers.
This is the limit for the EP93xx also but the amba-pl022 driver actually supports
up to 32-bit transfers.

#define SSP_SR(r)	(r + 0x00C)

/*
 * 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 */

#define SSP_CPSR(r)	(r + 0x010)

/*
 * SSP Clock Prescale Register  - SSP_CPSR
 */
#define SSP_CPSR_MASK_CPSDVSR	(0xFFUL << 0)

These match the spec and the EP93xx usage.

#define SSP_IMSC(r)	(r + 0x014)

/*
 * 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 */

In the EP93xx this register is called SSPIIR / SSPICR.  It is the interrupt
status register for reads and the interrupt clear register for writes.  For
reads it is defined as:

0  RIS    SSP Receive FIFO service request
1  TIS    SSP Transmit FIFO service request
2  RORIS  SSP Receive FIFO overrun interrupt status

For writes, any value written clears the RORIS bit.

The other registers listed for the amba-pl022 do not exist in the EP93xx
implementation.

The biggest problem I can see trying to use the amba-pl022 with the ep93xx
are the missing Peripheral ID and PrimeCell ID registers.  The AMBA bus driver
will not be able to match the driver to the device.

Beyond that, once the amba-pl022 driver supports DMA transfers the implementation
needed for the EP93xx will be completely different.

I think it's best to leave these as separate drivers.  Cirrus has stopped
development of their ARM processors so we have no hope of ever getting a full
pl022 compatible version.

Regards,
Hartley





------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [spi-devel-general] [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-05-03 17:00           ` H Hartley Sweeten
  0 siblings, 0 replies; 28+ messages in thread
From: H Hartley Sweeten @ 2010-05-03 17:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday, May 02, 2010 5:19 PM, Linus Walleij wrote:
> 2010/5/2 Mika Westerberg <mika.westerberg@iki.fi>:
>> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
>> in EP93xx chips.
>(...)
>> +#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
>
> When I look at this it's quite obvious that this is the same hardware or very
> close (maybe a redux version) of the thing supported by
> drivers/spi/amba-pl022.c.
>
> What is the difference really? I suspect this is a PL022 PrimeCell straight off.
> Even the CPSR algorithm is the same, just written differently.
>
> Can you make a hexdump of the PrimeCell ID registers at offset
> base+0xffe0..0xffff and post the contents?

Linus,

As Mika already pointed out, the ep93xx ssp peripheral does not have a valid
PeripheralID or PrimeCellID to identify it as an AMBA PL022 peripheral.

It probably was originally based on the PL022 but I think Cirrus hacked it
enough that the generic amba-pl022 driver will not work with it, at least
without a number of ugly #ifdef hacks.

Or, I could be wrong.  It appears the amba-pl022 driver doesn't actually match
the ARM spec for the PL022.

#define SSP_CR0(r)	(r + 0x000)

/*
 * 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)

The spec says that the DSS bits are only bits 3:0 (16-bit transfers), the
driver has them as bits 4:0 (32-bit transfers).
HALFDUP is not listed in the spec, and FRF is listed as bits 5:4.
CSS is not listed in the spec.

The PL022 spec actually matches the EP93xx usage.

#define SSP_CR1(r)	(r + 0x004)

/*
 * 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)

Bits 15:4 are listed as reserved in the spec, bits 3:0 match the spec. 
The EP93xx usage of this register is different.

0  RIE    Receive FIFO interrupt enable
1  TIE    Transmit FIFO interrupt enable
2  RORIE  Receive FIFO overrun interrupt enable
3  LBM    Loop back mode
4  SSE    Synchronous serial port enable
5  MS     Master / Slave mode select
6  SOD    Slave-mode output disable

#define SSP_DR(r)	(r + 0x008)

/*
 * SSP Data Register - SSP_DR
 */
#define SSP_DR_MASK_DATA	0xFFFFFFFF

The PL022 spec only shows the peripheral as supporting up to 16-bit transfers.
This is the limit for the EP93xx also but the amba-pl022 driver actually supports
up to 32-bit transfers.

#define SSP_SR(r)	(r + 0x00C)

/*
 * 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 */

#define SSP_CPSR(r)	(r + 0x010)

/*
 * SSP Clock Prescale Register  - SSP_CPSR
 */
#define SSP_CPSR_MASK_CPSDVSR	(0xFFUL << 0)

These match the spec and the EP93xx usage.

#define SSP_IMSC(r)	(r + 0x014)

/*
 * 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 */

In the EP93xx this register is called SSPIIR / SSPICR.  It is the interrupt
status register for reads and the interrupt clear register for writes.  For
reads it is defined as:

0  RIS    SSP Receive FIFO service request
1  TIS    SSP Transmit FIFO service request
2  RORIS  SSP Receive FIFO overrun interrupt status

For writes, any value written clears the RORIS bit.

The other registers listed for the amba-pl022 do not exist in the EP93xx
implementation.

The biggest problem I can see trying to use the amba-pl022 with the ep93xx
are the missing Peripheral ID and PrimeCell ID registers.  The AMBA bus driver
will not be able to match the driver to the device.

Beyond that, once the amba-pl022 driver supports DMA transfers the implementation
needed for the EP93xx will be completely different.

I think it's best to leave these as separate drivers.  Cirrus has stopped
development of their ARM processors so we have no hope of ever getting a full
pl022 compatible version.

Regards,
Hartley

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-05-02 14:38     ` Mika Westerberg
@ 2010-05-03 18:45         ` H Hartley Sweeten
  -1 siblings, 0 replies; 28+ messages in thread
From: H Hartley Sweeten @ 2010-05-03 18:45 UTC (permalink / raw)
  To: Mika Westerberg, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Sunday, May 02, 2010 7:39 AM, Mika Westerberg wrote:
>
> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> in EP93xx chips.
>
> Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>

A couple nitpick comments below that you can choose to ignore if you wish.

> ---
>  Documentation/spi/ep93xx_spi                   |   95 +++
>  arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h |   27 +
>  drivers/spi/Kconfig                            |   10 +
>  drivers/spi/Makefile                           |    1 +
>  drivers/spi/ep93xx_spi.c                       |  986 ++++++++++++++++++++++++
>  5 files changed, 1119 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/spi/ep93xx_spi
>  create mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
>  create mode 100644 drivers/spi/ep93xx_spi.c
>
> diff --git a/Documentation/spi/ep93xx_spi b/Documentation/spi/ep93xx_spi
> new file mode 100644
> index 0000000..6325f5b
> --- /dev/null
> +++ b/Documentation/spi/ep93xx_spi
> @@ -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.

This looks good.

> 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
> index 0000000..0a37961
> --- /dev/null
> +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
> @@ -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 */

Again, good.

> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index a191fa2..2b2f4c3 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -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

Good.

> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index d7d0f89..377f845 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -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

Good.

> diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c
> new file mode 100644
> index 0000000..2fbd489
> --- /dev/null
> +++ b/drivers/spi/ep93xx_spi.c
> @@ -0,0 +1,986 @@
> +/*
> + * 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);
> +}
> +
> +/**
> + * ep93xx_spi_enable() - enables the SPI controller and clock
> + * @espi: ep93xx SPI controller struct
> + *
> + * This function enables the SPI controller and its clock. Returns %0 in case
> + * of success and negative error in case if failure.
> + */

Most of these comments are overkill.  The functions are adequately described
by the name of the function.  Also, the DocBook style comments are typically
used only for exported functions.

> +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;
> +}
> +
> +/**
> + * ep93xx_spi_disable() - disables the SPI controller and clock
> + * @espi: ep93xx SPI controller struct
> + *
> + * Function disables SPI controller and its clock.
> + */
> +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);
> +}
> +
> +/**
> + * ep93xx_spi_enable_interrupts() - enables all SPI interrupts
> + * @espi: ep93xx SPI controller struct
> + *
> + * Enables all SPI interrupts: receive overrun (ROR), transmit, and receive.
> + */
> +static inline 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);
> +}
> +
> +/**
> + * ep93xx_spi_disable_interrupts() - disables all SPI interrupts
> + * @espi: ep93xx SPI controller struct
> + *
> + * Disables all SPI interrupts.
> + */
> +static inline void
> +ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)

These two functions really don't need the 'inline', the compiler can figure it out
as needed.  Also, if you remove the 'inline' you can then coalesce the lines into
a <80 line.

> +{
> +     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;
> +}
> +
> +/**
> + * ep93xx_spi_cs_control() - controls chipselect for given device
> + * @spi: SPI device to select/deselect
> + * @control: select (%true) / deselect (%false)
> + *
> + * Function controls chipselect line for given SPI device.
> + *
> + * Note that this function is called from a thread context and can sleep.
> + */
> +static inline void ep93xx_spi_cs_control(struct spi_device *spi,
> +                                      bool control)

Again, the inline should probably be removed and then coalesce the lines.

> +{
> +     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);
> +}
> +
> +/**
> + * bits_per_word() - returns bits per word for current message
> + */
> +static inline int bits_per_word(const struct ep93xx_spi *espi)

This inline probably make sense.  You would really have to look at the
generated assembly to know for sure.

> +{
> +     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);
> +}
> +
> +/**
> + * ep93xx_spi_interrupt() - SPI interrupt handler
> + * @irq: IRQ number (not used)
> + * @dev_id: pointer to EP93xx controller struct
> + *
> + * This function handles TX/RX/ROR interrupts which come from the SPI
> + * controller.
> + */
> +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-X3B1VOXEql0@public.gmane.org>");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:ep93xx-spi");

Overall this looks good.

For the modified chip select support, you have my:

Signed-off-by: H Hartley Sweeten <hsweeten-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org>

For the ep93xx driver in general, you have my:

Acked-by: H Hartley Sweeten <hsweeten-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org>

This driver should probably go through the spi tree.  You will need Grant Likely
to Ack this and pick it up.

Regards,
Hartley

------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-05-03 18:45         ` H Hartley Sweeten
  0 siblings, 0 replies; 28+ messages in thread
From: H Hartley Sweeten @ 2010-05-03 18:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday, May 02, 2010 7:39 AM, Mika Westerberg wrote:
>
> 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>

A couple nitpick comments below that you can choose to ignore if you wish.

> ---
>  Documentation/spi/ep93xx_spi                   |   95 +++
>  arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h |   27 +
>  drivers/spi/Kconfig                            |   10 +
>  drivers/spi/Makefile                           |    1 +
>  drivers/spi/ep93xx_spi.c                       |  986 ++++++++++++++++++++++++
>  5 files changed, 1119 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/spi/ep93xx_spi
>  create mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
>  create mode 100644 drivers/spi/ep93xx_spi.c
>
> diff --git a/Documentation/spi/ep93xx_spi b/Documentation/spi/ep93xx_spi
> new file mode 100644
> index 0000000..6325f5b
> --- /dev/null
> +++ b/Documentation/spi/ep93xx_spi
> @@ -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.

This looks good.

> 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
> index 0000000..0a37961
> --- /dev/null
> +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
> @@ -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 */

Again, good.

> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index a191fa2..2b2f4c3 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -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

Good.

> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index d7d0f89..377f845 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -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

Good.

> diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c
> new file mode 100644
> index 0000000..2fbd489
> --- /dev/null
> +++ b/drivers/spi/ep93xx_spi.c
> @@ -0,0 +1,986 @@
> +/*
> + * 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);
> +}
> +
> +/**
> + * ep93xx_spi_enable() - enables the SPI controller and clock
> + * @espi: ep93xx SPI controller struct
> + *
> + * This function enables the SPI controller and its clock. Returns %0 in case
> + * of success and negative error in case if failure.
> + */

Most of these comments are overkill.  The functions are adequately described
by the name of the function.  Also, the DocBook style comments are typically
used only for exported functions.

> +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;
> +}
> +
> +/**
> + * ep93xx_spi_disable() - disables the SPI controller and clock
> + * @espi: ep93xx SPI controller struct
> + *
> + * Function disables SPI controller and its clock.
> + */
> +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);
> +}
> +
> +/**
> + * ep93xx_spi_enable_interrupts() - enables all SPI interrupts
> + * @espi: ep93xx SPI controller struct
> + *
> + * Enables all SPI interrupts: receive overrun (ROR), transmit, and receive.
> + */
> +static inline 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);
> +}
> +
> +/**
> + * ep93xx_spi_disable_interrupts() - disables all SPI interrupts
> + * @espi: ep93xx SPI controller struct
> + *
> + * Disables all SPI interrupts.
> + */
> +static inline void
> +ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)

These two functions really don't need the 'inline', the compiler can figure it out
as needed.  Also, if you remove the 'inline' you can then coalesce the lines into
a <80 line.

> +{
> +     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;
> +}
> +
> +/**
> + * ep93xx_spi_cs_control() - controls chipselect for given device
> + * @spi: SPI device to select/deselect
> + * @control: select (%true) / deselect (%false)
> + *
> + * Function controls chipselect line for given SPI device.
> + *
> + * Note that this function is called from a thread context and can sleep.
> + */
> +static inline void ep93xx_spi_cs_control(struct spi_device *spi,
> +                                      bool control)

Again, the inline should probably be removed and then coalesce the lines.

> +{
> +     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);
> +}
> +
> +/**
> + * bits_per_word() - returns bits per word for current message
> + */
> +static inline int bits_per_word(const struct ep93xx_spi *espi)

This inline probably make sense.  You would really have to look at the
generated assembly to know for sure.

> +{
> +     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);
> +}
> +
> +/**
> + * ep93xx_spi_interrupt() - SPI interrupt handler
> + * @irq: IRQ number (not used)
> + * @dev_id: pointer to EP93xx controller struct
> + *
> + * This function handles TX/RX/ROR interrupts which come from the SPI
> + * controller.
> + */
> +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");

Overall this looks good.

For the modified chip select support, you have my:

Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>

For the ep93xx driver in general, you have my:

Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com>

This driver should probably go through the spi tree.  You will need Grant Likely
to Ack this and pick it up.

Regards,
Hartley

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-05-03 18:45         ` H Hartley Sweeten
@ 2010-05-03 19:15             ` Mika Westerberg
  -1 siblings, 0 replies; 28+ messages in thread
From: Mika Westerberg @ 2010-05-03 19:15 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Mon, May 03, 2010 at 01:45:01PM -0500, H Hartley Sweeten wrote:
(...)
> 
> Overall this looks good.
> 
> For the modified chip select support, you have my:
> 
> Signed-off-by: H Hartley Sweeten <hsweeten-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org>
> 
> For the ep93xx driver in general, you have my:
> 
> Acked-by: H Hartley Sweeten <hsweeten-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org>
> 
> This driver should probably go through the spi tree.  You will need Grant Likely
> to Ack this and pick it up.

Thanks Hartley!

I will incorporate your latest comments and submit v7.

Grant: do you have any comments on this? Is it ok for you to cycle
this through your spi tree?

Thanks,
MW

------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-05-03 19:15             ` Mika Westerberg
  0 siblings, 0 replies; 28+ messages in thread
From: Mika Westerberg @ 2010-05-03 19:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, May 03, 2010 at 01:45:01PM -0500, H Hartley Sweeten wrote:
(...)
> 
> Overall this looks good.
> 
> For the modified chip select support, you have my:
> 
> Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
> 
> For the ep93xx driver in general, you have my:
> 
> Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com>
> 
> This driver should probably go through the spi tree.  You will need Grant Likely
> to Ack this and pick it up.

Thanks Hartley!

I will incorporate your latest comments and submit v7.

Grant: do you have any comments on this? Is it ok for you to cycle
this through your spi tree?

Thanks,
MW

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/2] ep93xx: SPI driver platform support code
  2010-05-02 14:39   ` Mika Westerberg
@ 2010-05-04 17:21       ` H Hartley Sweeten
  -1 siblings, 0 replies; 28+ messages in thread
From: H Hartley Sweeten @ 2010-05-04 17:21 UTC (permalink / raw)
  To: Mika Westerberg, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Sunday, May 02, 2010 7:39 AM, Mika Westerberg wrote:
>
> This patch adds platform side support code for the EP93xx SPI driver. This
> includes clock, resources and muxing. There is a new function: ep93xx_register_spi()
> which can be used by board support code to register new SPI devices for the
> board.
>
> Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>
> ---
> Patch depends on following ARM patch:
>	5998/1 ep93xx: added chip revision reading function

There might be merge issues with the core.c and platform.h files due to this.
Hopefully not...  

That patch is already present in linux-next.  If Russell think there might
be an issue you could rebase this patch on the linux-next tree.

>
>  arch/arm/mach-ep93xx/clock.c                    |   13 ++++++
>  arch/arm/mach-ep93xx/core.c                     |   53 +++++++++++++++++++++++
>  arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
>  arch/arm/mach-ep93xx/include/mach/platform.h    |    4 ++
>  4 files changed, 71 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
> index 5f80092..e29bdef 100644
> --- a/arch/arm/mach-ep93xx/clock.c
> +++ b/arch/arm/mach-ep93xx/clock.c
> @@ -96,6 +96,10 @@ static struct clk clk_keypad = {
>  	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
>  	.set_rate	= set_keytchclk_rate,
>  };
> +static struct clk clk_spi = {
> +	.parent		= &clk_xtali,
> +	.rate		= EP93XX_EXT_CLK_RATE,
> +};
>  static struct clk clk_pwm = {
>  	.parent		= &clk_xtali,
>  	.rate		= EP93XX_EXT_CLK_RATE,
> @@ -186,6 +190,7 @@ static struct clk_lookup clocks[] = {
>  	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
>  	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
>  	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
> +	INIT_CK("ep93xx-spi.0",		NULL,		&clk_spi),
>  	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
>  	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
>  	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
> @@ -473,6 +478,14 @@ static int __init ep93xx_clock_init(void)
>  	/* Initialize the pll2 derived clocks */
>  	clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
>  
> +	/*
> +	 * EP93xx SSP clock rate was doubled in version E2. For more information
> +	 * see:
> +	 *     http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
> +	 */
> +	if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
> +		clk_spi.rate /= 2;
> +
>  	pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
>  		clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
>  	pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",

This is good.

> diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
> index 90fb591..f3b46b9 100644
> --- a/arch/arm/mach-ep93xx/core.c
> +++ b/arch/arm/mach-ep93xx/core.c
> @@ -31,10 +31,12 @@
>  #include <linux/amba/serial.h>
>  #include <linux/i2c.h>
>  #include <linux/i2c-gpio.h>
> +#include <linux/spi/spi.h>
>  
>  #include <mach/hardware.h>
>  #include <mach/fb.h>
>  #include <mach/ep93xx_keypad.h>
> +#include <mach/ep93xx_spi.h>
>  
>  #include <asm/mach/map.h>
>  #include <asm/mach/time.h>
> @@ -398,6 +400,57 @@ void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
>  	platform_device_register(&ep93xx_i2c_device);
>  }
>  
> +/*************************************************************************
> + * EP93xx SPI peripheral handling
> + *************************************************************************/
> +static struct ep93xx_spi_info ep93xx_spi_master_data;
> +
> +static struct resource ep93xx_spi_resources[] = {
> +	{
> +		.start	= EP93XX_SPI_PHYS_BASE,
> +		.end	= EP93XX_SPI_PHYS_BASE + 0x18 - 1,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start	= IRQ_EP93XX_SSP,
> +		.end	= IRQ_EP93XX_SSP,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct platform_device ep93xx_spi_device = {
> +	.name		= "ep93xx-spi",
> +	.id		= 0,
> +	.dev		= {
> +		.platform_data = &ep93xx_spi_master_data,
> +	},
> +	.num_resources	= ARRAY_SIZE(ep93xx_spi_resources),
> +	.resource	= ep93xx_spi_resources,
> +};
> +
> +/**
> + * ep93xx_register_spi() - registers spi platform device
> + * @info: ep93xx board specific spi master info (__initdata)
> + * @devices: SPI devices to register (__initdata)
> + * @num: number of SPI devices to register
> + *
> + * This function registers platform device for the EP93xx SPI controller and
> + * also makes sure that SPI pins are muxed so that I2S is not using those pins.
> + * Caller should allocate necessary GPIO lines before before calling this.

That last line is no longer true.  The GPIO allocation will now occur during the
individual spi device probes.  Just remove the line.

> + */
> +void __init ep93xx_register_spi(struct ep93xx_spi_info *info,
> +				struct spi_board_info *devices, int num)
> +{
> +	/*
> +	 * When SPI is used, we need to make sure that I2S is muxed off from
> +	 * SPI pins.
> +	 */
> +	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP);
> +
> +	ep93xx_spi_master_data = *info;
> +	spi_register_board_info(devices, num);
> +	platform_device_register(&ep93xx_spi_device);
> +}
>  
>  /*************************************************************************
>   * EP93xx LEDs

Other than the comment above, this all looks good.

> diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> index 93e2ecc..b1e096f 100644
> --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> @@ -106,6 +106,7 @@
>  
>  #define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
>  
> +#define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)
>  #define EP93XX_SPI_BASE			EP93XX_APB_IOMEM(0x000a0000)
>  
>  #define EP93XX_IRDA_BASE		EP93XX_APB_IOMEM(0x000b0000)

This is good.

> diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
> index c6dc14d..f11f1d7 100644
> --- a/arch/arm/mach-ep93xx/include/mach/platform.h
> +++ b/arch/arm/mach-ep93xx/include/mach/platform.h
> @@ -6,9 +6,11 @@
>  
>  struct i2c_gpio_platform_data;
>  struct i2c_board_info;
> +struct spi_board_info;
>  struct platform_device;
>  struct ep93xxfb_mach_info;
>  struct ep93xx_keypad_platform_data;
> +struct ep93xx_spi_info;
>  
>  struct ep93xx_eth_data
>  {
> @@ -36,6 +38,8 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
>  void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
>  void ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
>  			 struct i2c_board_info *devices, int num);
> +void ep93xx_register_spi(struct ep93xx_spi_info *info,
> +			 struct spi_board_info *devices, int num);
>  void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
>  void ep93xx_register_pwm(int pwm0, int pwm1);
>  int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);

This is good.

Please change the one comment above.  Then you have my:

Acked-by: H Hartley Sweeten <hsweeten-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org>

Thanks,
Hartley
------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 2/2] ep93xx: SPI driver platform support code
@ 2010-05-04 17:21       ` H Hartley Sweeten
  0 siblings, 0 replies; 28+ messages in thread
From: H Hartley Sweeten @ 2010-05-04 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday, May 02, 2010 7:39 AM, Mika Westerberg wrote:
>
> This patch adds platform side support code for the EP93xx SPI driver. This
> includes clock, resources and muxing. There is a new function: ep93xx_register_spi()
> which can be used by board support code to register new SPI devices for the
> board.
>
> Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
> ---
> Patch depends on following ARM patch:
>	5998/1 ep93xx: added chip revision reading function

There might be merge issues with the core.c and platform.h files due to this.
Hopefully not...  

That patch is already present in linux-next.  If Russell think there might
be an issue you could rebase this patch on the linux-next tree.

>
>  arch/arm/mach-ep93xx/clock.c                    |   13 ++++++
>  arch/arm/mach-ep93xx/core.c                     |   53 +++++++++++++++++++++++
>  arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
>  arch/arm/mach-ep93xx/include/mach/platform.h    |    4 ++
>  4 files changed, 71 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
> index 5f80092..e29bdef 100644
> --- a/arch/arm/mach-ep93xx/clock.c
> +++ b/arch/arm/mach-ep93xx/clock.c
> @@ -96,6 +96,10 @@ static struct clk clk_keypad = {
>  	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
>  	.set_rate	= set_keytchclk_rate,
>  };
> +static struct clk clk_spi = {
> +	.parent		= &clk_xtali,
> +	.rate		= EP93XX_EXT_CLK_RATE,
> +};
>  static struct clk clk_pwm = {
>  	.parent		= &clk_xtali,
>  	.rate		= EP93XX_EXT_CLK_RATE,
> @@ -186,6 +190,7 @@ static struct clk_lookup clocks[] = {
>  	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
>  	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
>  	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
> +	INIT_CK("ep93xx-spi.0",		NULL,		&clk_spi),
>  	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
>  	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
>  	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
> @@ -473,6 +478,14 @@ static int __init ep93xx_clock_init(void)
>  	/* Initialize the pll2 derived clocks */
>  	clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
>  
> +	/*
> +	 * EP93xx SSP clock rate was doubled in version E2. For more information
> +	 * see:
> +	 *     http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
> +	 */
> +	if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
> +		clk_spi.rate /= 2;
> +
>  	pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
>  		clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
>  	pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",

This is good.

> diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
> index 90fb591..f3b46b9 100644
> --- a/arch/arm/mach-ep93xx/core.c
> +++ b/arch/arm/mach-ep93xx/core.c
> @@ -31,10 +31,12 @@
>  #include <linux/amba/serial.h>
>  #include <linux/i2c.h>
>  #include <linux/i2c-gpio.h>
> +#include <linux/spi/spi.h>
>  
>  #include <mach/hardware.h>
>  #include <mach/fb.h>
>  #include <mach/ep93xx_keypad.h>
> +#include <mach/ep93xx_spi.h>
>  
>  #include <asm/mach/map.h>
>  #include <asm/mach/time.h>
> @@ -398,6 +400,57 @@ void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
>  	platform_device_register(&ep93xx_i2c_device);
>  }
>  
> +/*************************************************************************
> + * EP93xx SPI peripheral handling
> + *************************************************************************/
> +static struct ep93xx_spi_info ep93xx_spi_master_data;
> +
> +static struct resource ep93xx_spi_resources[] = {
> +	{
> +		.start	= EP93XX_SPI_PHYS_BASE,
> +		.end	= EP93XX_SPI_PHYS_BASE + 0x18 - 1,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start	= IRQ_EP93XX_SSP,
> +		.end	= IRQ_EP93XX_SSP,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct platform_device ep93xx_spi_device = {
> +	.name		= "ep93xx-spi",
> +	.id		= 0,
> +	.dev		= {
> +		.platform_data = &ep93xx_spi_master_data,
> +	},
> +	.num_resources	= ARRAY_SIZE(ep93xx_spi_resources),
> +	.resource	= ep93xx_spi_resources,
> +};
> +
> +/**
> + * ep93xx_register_spi() - registers spi platform device
> + * @info: ep93xx board specific spi master info (__initdata)
> + * @devices: SPI devices to register (__initdata)
> + * @num: number of SPI devices to register
> + *
> + * This function registers platform device for the EP93xx SPI controller and
> + * also makes sure that SPI pins are muxed so that I2S is not using those pins.
> + * Caller should allocate necessary GPIO lines before before calling this.

That last line is no longer true.  The GPIO allocation will now occur during the
individual spi device probes.  Just remove the line.

> + */
> +void __init ep93xx_register_spi(struct ep93xx_spi_info *info,
> +				struct spi_board_info *devices, int num)
> +{
> +	/*
> +	 * When SPI is used, we need to make sure that I2S is muxed off from
> +	 * SPI pins.
> +	 */
> +	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP);
> +
> +	ep93xx_spi_master_data = *info;
> +	spi_register_board_info(devices, num);
> +	platform_device_register(&ep93xx_spi_device);
> +}
>  
>  /*************************************************************************
>   * EP93xx LEDs

Other than the comment above, this all looks good.

> diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> index 93e2ecc..b1e096f 100644
> --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> @@ -106,6 +106,7 @@
>  
>  #define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
>  
> +#define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)
>  #define EP93XX_SPI_BASE			EP93XX_APB_IOMEM(0x000a0000)
>  
>  #define EP93XX_IRDA_BASE		EP93XX_APB_IOMEM(0x000b0000)

This is good.

> diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
> index c6dc14d..f11f1d7 100644
> --- a/arch/arm/mach-ep93xx/include/mach/platform.h
> +++ b/arch/arm/mach-ep93xx/include/mach/platform.h
> @@ -6,9 +6,11 @@
>  
>  struct i2c_gpio_platform_data;
>  struct i2c_board_info;
> +struct spi_board_info;
>  struct platform_device;
>  struct ep93xxfb_mach_info;
>  struct ep93xx_keypad_platform_data;
> +struct ep93xx_spi_info;
>  
>  struct ep93xx_eth_data
>  {
> @@ -36,6 +38,8 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
>  void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
>  void ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
>  			 struct i2c_board_info *devices, int num);
> +void ep93xx_register_spi(struct ep93xx_spi_info *info,
> +			 struct spi_board_info *devices, int num);
>  void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
>  void ep93xx_register_pwm(int pwm0, int pwm1);
>  int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);

This is good.

Please change the one comment above.  Then you have my:

Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com>

Thanks,
Hartley

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-05-03 17:00           ` [spi-devel-general] " H Hartley Sweeten
@ 2010-05-05  9:04               ` Linus Walleij
  -1 siblings, 0 replies; 28+ messages in thread
From: Linus Walleij @ 2010-05-05  9:04 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: Mika Westerberg, Rabin Vincent, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	martinwguy-Re5JQEeQqe8AvxtiuMwx3w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

2010/5/3 H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org>:
> On Sunday, May 02, 2010 5:19 PM, Linus Walleij wrote:

>> When I look at this it's quite obvious that this is the same hardware or very
>> close (maybe a redux version) of the thing supported by
>> drivers/spi/amba-pl022.c.
>>
>> What is the difference really? I suspect this is a PL022 PrimeCell straight off.
>> Even the CPSR algorithm is the same, just written differently.
>>
>> Can you make a hexdump of the PrimeCell ID registers at offset
>> base+0xffe0..0xffff and post the contents?
>
> As Mika already pointed out, the ep93xx ssp peripheral does not have a valid
> PeripheralID or PrimeCellID to identify it as an AMBA PL022 peripheral.

Yep, but how close is it... the raw PL022 and the ST Micro variant only differ
in a few small places.

> It probably was originally based on the PL022 but I think Cirrus hacked it
> enough that the generic amba-pl022 driver will not work with it, at least
> without a number of ugly #ifdef hacks.

The stuff we've done with vendor data is mostly done so that we alter
execution path in runtime rather than throwing in #ifdefs.

> Or, I could be wrong.  It appears the amba-pl022 driver doesn't actually match
> the ARM spec for the PL022.

You're right, the control registers are not cleanly separated into the vanilla
PL022 vs ST Micro Nomadik extensions. I will post a fixup patch soonish,
covering all the stuff you pointed out.

When you look at the code post-patch I think you will see that it
is actually even closer, to the vanilla PL022.

Sorry for the mess, I was retrofitting a driver for the ST extended
version to the plain PL022 found in U300 and missed some stuff.

By chance, Rabin pointed me to the same problems some day ago...

> The PL022 spec only shows the peripheral as supporting up to 16-bit transfers.
> This is the limit for the EP93xx also but the amba-pl022 driver actually supports
> up to 32-bit transfers.

Actually the code execution path takes this into account in
the pl022_setup() function:

	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;
		}
	}

As you see 32bit transfers will only be accepted as configuration if the
vendor data indicates that this is possible on that version of the controller.

> /*
>  * 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 */
>
> In the EP93xx this register is called SSPIIR / SSPICR.  It is the interrupt
> status register for reads and the interrupt clear register for writes.  For
> reads it is defined as:
>
> 0  RIS    SSP Receive FIFO service request
> 1  TIS    SSP Transmit FIFO service request
> 2  RORIS  SSP Receive FIFO overrun interrupt status

This seems like it is either a precursor to the PL022 or a seriously
stripped down version. I don't know if this alone warrants duplicating the
rest of the code, could be.

> The other registers listed for the amba-pl022 do not exist in the EP93xx
> implementation.

We have a stripped down version called "PL023" as well, it's simply
that we don't use the extended features and it just works, so I think
it's not much of a problem.

> The biggest problem I can see trying to use the amba-pl022 with the ep93xx
> are the missing Peripheral ID and PrimeCell ID registers.  The AMBA bus driver
> will not be able to match the driver to the device.

That is actually not a problem at all, you can hardcode a PrimeCell
ID into the platform config, and the device will be registered on the
given ID instead, like this:

struct amba_device ssp0_device = {
        .dev = {
                .coherent_dma_mask = ~0,
                .init_name = "ssp0",
                .platform_data = &ssp0_platform_data,
        },
        .res = {
                .start = U8500_SSP0_BASE,
                .end   = U8500_SSP0_BASE + SZ_4K - 1,
                .flags = IORESOURCE_MEM,
        },
        .irq = {IRQ_SSP0, NO_IRQ },
        /* PL022 Device ID */
        .periphid = 0x00041022,
};

Then you have to register it on the PrimeCell bus with

static struct amba_device *amba_devs[] __initdata = {
        &ssp0_device,
};

for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
         amba_device_register(amba_devs[i], &iomem_resource);

> Beyond that, once the amba-pl022 driver supports DMA transfers the implementation
> needed for the EP93xx will be completely different.

The idea about the PrimeCell DMA is to use the DMAdevices in the
DMA engine only, to find some common ground exactly in order to
facilitate usage with diverse platforms.

I know that there are many custom DMA implementations, the idea
is that if we can unify these under DMA engine we can abstract away
the specifics. I have already done this for two very different DMA
engines: COH901318 and DMA40 and it works. DMA controllers IMO
are not so special at all, they all share the same features and
shall hopefully all go in behind the DMA engine API.

> I think it's best to leave these as separate drivers.  Cirrus has stopped
> development of their ARM processors so we have no hope of ever getting a full
> pl022 compatible version.

I think it's worth a try to use amba-pl022.c, but hey, it's just me...

Yours,
Linus Walleij

------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [spi-devel-general] [PATCH v6 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-05-05  9:04               ` Linus Walleij
  0 siblings, 0 replies; 28+ messages in thread
From: Linus Walleij @ 2010-05-05  9:04 UTC (permalink / raw)
  To: linux-arm-kernel

2010/5/3 H Hartley Sweeten <hartleys@visionengravers.com>:
> On Sunday, May 02, 2010 5:19 PM, Linus Walleij wrote:

>> When I look at this it's quite obvious that this is the same hardware or very
>> close (maybe a redux version) of the thing supported by
>> drivers/spi/amba-pl022.c.
>>
>> What is the difference really? I suspect this is a PL022 PrimeCell straight off.
>> Even the CPSR algorithm is the same, just written differently.
>>
>> Can you make a hexdump of the PrimeCell ID registers at offset
>> base+0xffe0..0xffff and post the contents?
>
> As Mika already pointed out, the ep93xx ssp peripheral does not have a valid
> PeripheralID or PrimeCellID to identify it as an AMBA PL022 peripheral.

Yep, but how close is it... the raw PL022 and the ST Micro variant only differ
in a few small places.

> It probably was originally based on the PL022 but I think Cirrus hacked it
> enough that the generic amba-pl022 driver will not work with it, at least
> without a number of ugly #ifdef hacks.

The stuff we've done with vendor data is mostly done so that we alter
execution path in runtime rather than throwing in #ifdefs.

> Or, I could be wrong. ?It appears the amba-pl022 driver doesn't actually match
> the ARM spec for the PL022.

You're right, the control registers are not cleanly separated into the vanilla
PL022 vs ST Micro Nomadik extensions. I will post a fixup patch soonish,
covering all the stuff you pointed out.

When you look at the code post-patch I think you will see that it
is actually even closer, to the vanilla PL022.

Sorry for the mess, I was retrofitting a driver for the ST extended
version to the plain PL022 found in U300 and missed some stuff.

By chance, Rabin pointed me to the same problems some day ago...

> The PL022 spec only shows the peripheral as supporting up to 16-bit transfers.
> This is the limit for the EP93xx also but the amba-pl022 driver actually supports
> up to 32-bit transfers.

Actually the code execution path takes this into account in
the pl022_setup() function:

	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;
		}
	}

As you see 32bit transfers will only be accepted as configuration if the
vendor data indicates that this is possible on that version of the controller.

> /*
> ?* 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 */
>
> In the EP93xx this register is called SSPIIR / SSPICR. ?It is the interrupt
> status register for reads and the interrupt clear register for writes. ?For
> reads it is defined as:
>
> 0 ?RIS ? ?SSP Receive FIFO service request
> 1 ?TIS ? ?SSP Transmit FIFO service request
> 2 ?RORIS ?SSP Receive FIFO overrun interrupt status

This seems like it is either a precursor to the PL022 or a seriously
stripped down version. I don't know if this alone warrants duplicating the
rest of the code, could be.

> The other registers listed for the amba-pl022 do not exist in the EP93xx
> implementation.

We have a stripped down version called "PL023" as well, it's simply
that we don't use the extended features and it just works, so I think
it's not much of a problem.

> The biggest problem I can see trying to use the amba-pl022 with the ep93xx
> are the missing Peripheral ID and PrimeCell ID registers. ?The AMBA bus driver
> will not be able to match the driver to the device.

That is actually not a problem at all, you can hardcode a PrimeCell
ID into the platform config, and the device will be registered on the
given ID instead, like this:

struct amba_device ssp0_device = {
        .dev = {
                .coherent_dma_mask = ~0,
                .init_name = "ssp0",
                .platform_data = &ssp0_platform_data,
        },
        .res = {
                .start = U8500_SSP0_BASE,
                .end   = U8500_SSP0_BASE + SZ_4K - 1,
                .flags = IORESOURCE_MEM,
        },
        .irq = {IRQ_SSP0, NO_IRQ },
        /* PL022 Device ID */
        .periphid = 0x00041022,
};

Then you have to register it on the PrimeCell bus with

static struct amba_device *amba_devs[] __initdata = {
        &ssp0_device,
};

for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
         amba_device_register(amba_devs[i], &iomem_resource);

> Beyond that, once the amba-pl022 driver supports DMA transfers the implementation
> needed for the EP93xx will be completely different.

The idea about the PrimeCell DMA is to use the DMAdevices in the
DMA engine only, to find some common ground exactly in order to
facilitate usage with diverse platforms.

I know that there are many custom DMA implementations, the idea
is that if we can unify these under DMA engine we can abstract away
the specifics. I have already done this for two very different DMA
engines: COH901318 and DMA40 and it works. DMA controllers IMO
are not so special at all, they all share the same features and
shall hopefully all go in behind the DMA engine API.

> I think it's best to leave these as separate drivers. ?Cirrus has stopped
> development of their ARM processors so we have no hope of ever getting a full
> pl022 compatible version.

I think it's worth a try to use amba-pl022.c, but hey, it's just me...

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/2] ep93xx: SPI driver platform support code
  2010-05-04 17:21       ` H Hartley Sweeten
@ 2010-05-05 14:26           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 28+ messages in thread
From: Russell King - ARM Linux @ 2010-05-05 14:26 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	martinwguy-Re5JQEeQqe8AvxtiuMwx3w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tue, May 04, 2010 at 12:21:36PM -0500, H Hartley Sweeten wrote:
> That patch is already present in linux-next.  If Russell think there might
> be an issue you could rebase this patch on the linux-next tree.

If this patch depends on 5998/1, then I'll take it via the ep93xx branch
(which has 5998/1 on.)  It's only touching files in arch/arm so there
shouldn't be any problem with that.

------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 2/2] ep93xx: SPI driver platform support code
@ 2010-05-05 14:26           ` Russell King - ARM Linux
  0 siblings, 0 replies; 28+ messages in thread
From: Russell King - ARM Linux @ 2010-05-05 14:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 04, 2010 at 12:21:36PM -0500, H Hartley Sweeten wrote:
> That patch is already present in linux-next.  If Russell think there might
> be an issue you could rebase this patch on the linux-next tree.

If this patch depends on 5998/1, then I'll take it via the ep93xx branch
(which has 5998/1 on.)  It's only touching files in arch/arm so there
shouldn't be any problem with that.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* RE: [PATCH v6 2/2] ep93xx: SPI driver platform support code
  2010-05-05 14:26           ` Russell King - ARM Linux
@ 2010-05-11  0:24             ` H Hartley Sweeten
  -1 siblings, 0 replies; 28+ messages in thread
From: H Hartley Sweeten @ 2010-05-11  0:24 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: Russell King - ARM Linux, martinwguy, grant.likely, ryan,
	spi-devel-general, linux-arm-kernel

On Wednesday, May 05, 2010 7:26 AM, Russell King wrote:
> On Tue, May 04, 2010 at 12:21:36PM -0500, H Hartley Sweeten wrote:
>> That patch is already present in linux-next.  If Russell think there might
>> be an issue you could rebase this patch on the linux-next tree.
>
> If this patch depends on 5998/1, then I'll take it via the ep93xx branch
> (which has 5998/1 on.)  It's only touching files in arch/arm so there
> shouldn't be any problem with that.


Mika,

Any word from the spi group on PATCH v6 1/2?

Russell wants this patch (v6 2/2) to go through his tree, please add it to
his patch system.  It will not be a problem if this patch goes in before the
actual driver since nothing "breaks".  If the driver goes in first it will
not work due to the missing clock resource, even if a user were to hack in the
platform init code.

Regards,
Hartley

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 2/2] ep93xx: SPI driver platform support code
@ 2010-05-11  0:24             ` H Hartley Sweeten
  0 siblings, 0 replies; 28+ messages in thread
From: H Hartley Sweeten @ 2010-05-11  0:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday, May 05, 2010 7:26 AM, Russell King wrote:
> On Tue, May 04, 2010 at 12:21:36PM -0500, H Hartley Sweeten wrote:
>> That patch is already present in linux-next.  If Russell think there might
>> be an issue you could rebase this patch on the linux-next tree.
>
> If this patch depends on 5998/1, then I'll take it via the ep93xx branch
> (which has 5998/1 on.)  It's only touching files in arch/arm so there
> shouldn't be any problem with that.


Mika,

Any word from the spi group on PATCH v6 1/2?

Russell wants this patch (v6 2/2) to go through his tree, please add it to
his patch system.  It will not be a problem if this patch goes in before the
actual driver since nothing "breaks".  If the driver goes in first it will
not work due to the missing clock resource, even if a user were to hack in the
platform init code.

Regards,
Hartley

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/2] ep93xx: SPI driver platform support code
  2010-05-11  0:24             ` H Hartley Sweeten
@ 2010-05-11  6:13                 ` Mika Westerberg
  -1 siblings, 0 replies; 28+ messages in thread
From: Mika Westerberg @ 2010-05-11  6:13 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: Russell King - ARM Linux, martinwguy-Re5JQEeQqe8AvxtiuMwx3w,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Mon, May 10, 2010 at 07:24:24PM -0500, H Hartley Sweeten wrote:
> On Wednesday, May 05, 2010 7:26 AM, Russell King wrote:
> > On Tue, May 04, 2010 at 12:21:36PM -0500, H Hartley Sweeten wrote:
> >> That patch is already present in linux-next.  If Russell think there might
> >> be an issue you could rebase this patch on the linux-next tree.
> >
> > If this patch depends on 5998/1, then I'll take it via the ep93xx branch
> > (which has 5998/1 on.)  It's only touching files in arch/arm so there
> > shouldn't be any problem with that.
> 
> 
> Mika,
> 
> Any word from the spi group on PATCH v6 1/2?

Nothing yet.

> Russell wants this patch (v6 2/2) to go through his tree, please add it to
> his patch system.  It will not be a problem if this patch goes in before the
> actual driver since nothing "breaks".  If the driver goes in first it will
> not work due to the missing clock resource, even if a user were to hack in the
> platform init code.

OK, will do that later on today.

Regards,
MW

------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 2/2] ep93xx: SPI driver platform support code
@ 2010-05-11  6:13                 ` Mika Westerberg
  0 siblings, 0 replies; 28+ messages in thread
From: Mika Westerberg @ 2010-05-11  6:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, May 10, 2010 at 07:24:24PM -0500, H Hartley Sweeten wrote:
> On Wednesday, May 05, 2010 7:26 AM, Russell King wrote:
> > On Tue, May 04, 2010 at 12:21:36PM -0500, H Hartley Sweeten wrote:
> >> That patch is already present in linux-next.  If Russell think there might
> >> be an issue you could rebase this patch on the linux-next tree.
> >
> > If this patch depends on 5998/1, then I'll take it via the ep93xx branch
> > (which has 5998/1 on.)  It's only touching files in arch/arm so there
> > shouldn't be any problem with that.
> 
> 
> Mika,
> 
> Any word from the spi group on PATCH v6 1/2?

Nothing yet.

> Russell wants this patch (v6 2/2) to go through his tree, please add it to
> his patch system.  It will not be a problem if this patch goes in before the
> actual driver since nothing "breaks".  If the driver goes in first it will
> not work due to the missing clock resource, even if a user were to hack in the
> platform init code.

OK, will do that later on today.

Regards,
MW

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2010-05-11  6:13 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-02 14:38 [PATCH v6 0/2] spi: driver for Cirrus EP93xx SPI controller Mika Westerberg
2010-05-02 14:38 ` Mika Westerberg
     [not found] ` <cover.1272805161.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
2010-05-02 14:38   ` [PATCH v6 1/2] spi: implemented " Mika Westerberg
2010-05-02 14:38     ` Mika Westerberg
2010-05-03  0:18     ` [spi-devel-general] " Linus Walleij
2010-05-03  0:18       ` Linus Walleij
     [not found]       ` <h2r63386a3d1005021718k31125e4fz43a08025997b5c5c-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-05-03  4:21         ` Mika Westerberg
2010-05-03  4:21           ` [spi-devel-general] " Mika Westerberg
     [not found]           ` <20100503042123.GM26418-WfG2TfFPcQ9S6P4I59wummXnswh1EIUO@public.gmane.org>
2010-05-03 13:18             ` Linus Walleij
2010-05-03 13:18               ` [spi-devel-general] " Linus Walleij
2010-05-03 17:00         ` H Hartley Sweeten
2010-05-03 17:00           ` [spi-devel-general] " H Hartley Sweeten
     [not found]           ` <0D753D10438DA54287A00B0270842697636E9BA5D3-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-05-05  9:04             ` Linus Walleij
2010-05-05  9:04               ` [spi-devel-general] " Linus Walleij
     [not found]     ` <0dce0e9fdb6af35854d26d7bd0d8af5a5ea8f76a.1272805161.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
2010-05-03 18:45       ` H Hartley Sweeten
2010-05-03 18:45         ` H Hartley Sweeten
     [not found]         ` <0D753D10438DA54287A00B0270842697636EADDB8E-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-05-03 19:15           ` Mika Westerberg
2010-05-03 19:15             ` Mika Westerberg
2010-05-02 14:39 ` [PATCH v6 2/2] ep93xx: SPI driver platform support code Mika Westerberg
2010-05-02 14:39   ` Mika Westerberg
     [not found]   ` <865b5d7ca0fae1977a1fadcdabdb715e3ea1604d.1272805161.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
2010-05-04 17:21     ` H Hartley Sweeten
2010-05-04 17:21       ` H Hartley Sweeten
     [not found]       ` <0D753D10438DA54287A00B0270842697636EB838E1-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-05-05 14:26         ` Russell King - ARM Linux
2010-05-05 14:26           ` Russell King - ARM Linux
2010-05-11  0:24           ` H Hartley Sweeten
2010-05-11  0:24             ` H Hartley Sweeten
     [not found]             ` <0D753D10438DA54287A00B0270842697636EE74B65-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-05-11  6:13               ` Mika Westerberg
2010-05-11  6:13                 ` Mika Westerberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.