linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 0/2] spi: driver for Cirrus EP93xx SPI controller
@ 2010-04-28 17:51 Mika Westerberg
       [not found] ` <cover.1272476431.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
  0 siblings, 1 reply; 7+ messages in thread
From: Mika Westerberg @ 2010-04-28 17:51 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hello,

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

This is fifth iteration of the driver.

Changes to the previous version:
	- addressed review comments
	- added priming the TX FIFO when transfer is started
	- in case of ROR interrupt we clear it
	- added documentation in Documentation/spi/ep93xx_spi which provides
	  sample code how the driver can be hooked into platform data

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                    |  102 +++
 arch/arm/mach-ep93xx/clock.c                    |   13 +
 arch/arm/mach-ep93xx/core.c                     |   50 ++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h  |   32 +
 arch/arm/mach-ep93xx/include/mach/platform.h    |    4 +
 drivers/spi/Kconfig                             |   11 +
 drivers/spi/Makefile                            |    1 +
 drivers/spi/ep93xx_spi.c                        |  972 +++++++++++++++++++++++
 9 files changed, 1186 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] 7+ messages in thread

* [PATCH v5 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
       [not found] ` <cover.1272476431.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
@ 2010-04-28 17:51   ` Mika Westerberg
       [not found]     ` <c24e9af6062e579499a1cb5782cdfe44e91cb9a1.1272476431.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
  2010-04-28 17:51   ` [PATCH v5 2/2] ep93xx: SPI driver platform support code Mika Westerberg
  2010-04-28 22:30   ` [PATCH v5 0/2] spi: driver for Cirrus EP93xx SPI controller H Hartley Sweeten
  2 siblings, 1 reply; 7+ messages in thread
From: Mika Westerberg @ 2010-04-28 17:51 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).

Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>
---
 Documentation/spi/ep93xx_spi                   |  102 +++
 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h |   32 +
 drivers/spi/Kconfig                            |   11 +
 drivers/spi/Makefile                           |    1 +
 drivers/spi/ep93xx_spi.c                       |  972 ++++++++++++++++++++++++
 5 files changed, 1118 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..bbb6fc2
--- /dev/null
+++ b/Documentation/spi/ep93xx_spi
@@ -0,0 +1,102 @@
+Cirrus EP93xx SPI controller driver HOWTO
+=========================================
+
+ep93xx_spi driver brings SPI master support for EP93xx SPI controller. Driver
+supports EP9301, EP9302, EP9307, EP9312 and EP9315 chips. 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>
+
+/*
+ * First declare our SD/MMC card as spi_board_info. We only have one device on
+ * this bus (this is also what mmc_spi expects).
+ */
+static struct spi_board_info ts72xx_spi_devices[] __initconst = {
+	{
+		.modalias	= "mmc_spi",
+		/*
+		 * 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,
+	},
+};
+
+/* this is our GPIO line used for chip select */
+#define MMC_CHIP_SELECT_GPIO	EP93XX_GPIO_LINE_EGPIO9
+
+static void ts72xx_spi_cs_control(struct spi_device *spi, int value)
+{
+	gpio_set_value(MMC_CHIP_SELECT_GPIO, value);
+}
+
+static struct ep93xx_spi_info ts72xx_spi_info = {
+	.num_chipselect	= ARRAY_SIZE(ts72xx_spi_devices),
+	.cs_control	= ts72xx_spi_cs_control,
+};
+
+static void __init ts72xx_init_spi(void)
+{
+        unsigned gpio = MMC_CHIP_SELECT_GPIO;
+        int err;
+
+	/*
+	 * Allocate chip select GPIO line here and configure it as output.
+	 */
+        err = gpio_request(gpio, "ep93xx-spi");
+        if (err) {
+                pr_err("failed to allocate GPIO%d for SPI device\n", gpio);
+                return;
+        }
+
+        err = gpio_direction_output(gpio, 1);
+        if (err) {
+                pr_err("failed to configure GPIO%d for SPI device\n", gpio);
+                gpio_free(gpio);
+                return;
+        }
+
+	/*
+	 * Now we can register the device. After this, the driver should be
+	 * ready.
+	 */
+        ep93xx_register_spi(&ts72xx_spi_info, ts72xx_spi_devices,
+                            ARRAY_SIZE(ts72xx_spi_devices));
+}
+
+static void __init ts72xx_init_machine(void)
+{
+	...
+	ts72xx_init_spi();
+}
+
+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..98935d8
--- /dev/null
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
@@ -0,0 +1,32 @@
+#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
+ * @cs_control: chip select control function. Can be %NULL if not needed.
+ *
+ * This structure is passed from board support files to EP93xx SPI controller
+ * driver. It provides callback hook to control chip select lines that are
+ * allocated in board support files during the board initialization.
+ */
+struct ep93xx_spi_info {
+	int	num_chipselect;
+	/*
+	 * cs_control() - control board chipselect GPIO lines
+	 * @spi: SPI device whose chipselect is controlled
+	 * @value: value to set the chip select line to
+	 *
+	 * This function is used to control board specific chip select lines.
+	 * @value is either %0 or %1.
+	 *
+	 * This function is called from thread context and can sleep if
+	 * necessary.
+	 */
+	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..5852340 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -117,6 +117,17 @@ 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. This driver supports EP9301, EP9302, EP9307, EP9312 and EP9315
+	  chips.
+
+	  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..20d4f1d
--- /dev/null
+++ b/drivers/spi/ep93xx_spi.c
@@ -0,0 +1,972 @@
+/*
+ * Driver for Cirrus Logic EP93xx SPI controller.
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Explicit FIFO handling code was inspired by amba-pl022 driver.
+ *
+ * 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/module.h>
+#include <linux/moduleparam.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.
+ * @cs_control: chip select control function
+ *
+ * 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;
+	void				(*cs_control)(struct spi_device *, int);
+};
+
+/**
+ * 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)
+ *
+ * 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;
+};
+
+/* 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
+ * @espi: ep93xx SPI controller struct
+ * @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(const struct ep93xx_spi *espi,
+					 struct spi_device *spi,
+					 bool control)
+{
+	int value = (spi->mode & SPI_CS_HIGH) ? control : !control;
+
+	if (espi->cs_control)
+		espi->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) {
+		chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+		if (!chip)
+			return -ENOMEM;
+
+		spi_set_ctldata(spi, chip);
+		chip->spi = spi;
+	}
+
+	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(espi, 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) {
+		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 %0 when
+ * current transfer was not yet completed otherwise length of the transfer
+ * (>%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 t->len;
+	}
+
+	return 0;
+}
+
+/**
+ * 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.
+	 */
+	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(espi, msg->spi, false);
+			cond_resched();
+			ep93xx_spi_cs_control(espi, 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(espi, 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(espi, 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 that come from the SPI controller.
+ * Returns %IRQ_HANDLED when interrupt was handled and %IRQ_NONE in case the
+ * @irq was not handled.
+ */
+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->cs_control = info->cs_control;
+
+	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] 7+ messages in thread

* [PATCH v5 2/2] ep93xx: SPI driver platform support code
       [not found] ` <cover.1272476431.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
  2010-04-28 17:51   ` [PATCH v5 1/2] spi: implemented " Mika Westerberg
@ 2010-04-28 17:51   ` Mika Westerberg
  2010-04-28 18:31     ` H Hartley Sweeten
  2010-04-28 22:30   ` [PATCH v5 0/2] spi: driver for Cirrus EP93xx SPI controller H Hartley Sweeten
  2 siblings, 1 reply; 7+ messages in thread
From: Mika Westerberg @ 2010-04-28 17:51 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

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.

Patch depends on following ARM patch:
	5998/1 ep93xx: added chip revision reading function

Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>
---
 arch/arm/mach-ep93xx/clock.c                    |   13 ++++++
 arch/arm/mach-ep93xx/core.c                     |   50 +++++++++++++++++++++++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
 arch/arm/mach-ep93xx/include/mach/platform.h    |    4 ++
 4 files changed, 68 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..d57b61e 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -29,12 +29,14 @@
 #include <linux/termios.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/serial.h>
+#include <linux/spi/spi.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.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>
@@ -363,6 +365,54 @@ void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr)
 	platform_device_register(&ep93xx_eth_device);
 }
 
+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
+ * @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 i2c peripheral handling
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..52eebfd 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -4,11 +4,13 @@
 
 #ifndef __ASSEMBLY__
 
+struct spi_board_info;
 struct i2c_gpio_platform_data;
 struct i2c_board_info;
 struct platform_device;
 struct ep93xxfb_mach_info;
 struct ep93xx_keypad_platform_data;
+struct ep93xx_spi_info;
 
 struct ep93xx_eth_data
 {
@@ -34,6 +36,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_spi(struct ep93xx_spi_info *info,
+			 struct spi_board_info *devices, int num);
 void ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
 			 struct i2c_board_info *devices, int num);
 void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
-- 
1.5.6.5


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

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

* RE: [PATCH v5 2/2] ep93xx: SPI driver platform support code
  2010-04-28 17:51   ` [PATCH v5 2/2] ep93xx: SPI driver platform support code Mika Westerberg
@ 2010-04-28 18:31     ` H Hartley Sweeten
  0 siblings, 0 replies; 7+ messages in thread
From: H Hartley Sweeten @ 2010-04-28 18:31 UTC (permalink / raw)
  To: Mika Westerberg, spi-devel-general
  Cc: grant.likely, martinwguy, ryan, linux-arm-kernel

On Wednesday, April 28, 2010 10:51 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.
>
> Patch depends on following ARM patch:
>	5998/1 ep93xx: added chip revision reading function
>
> Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
> ---
>  arch/arm/mach-ep93xx/clock.c                    |   13 ++++++
>  arch/arm/mach-ep93xx/core.c                     |   50 +++++++++++++++++++++++
>  arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
>  arch/arm/mach-ep93xx/include/mach/platform.h    |    4 ++
>  4 files changed, 68 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 all looks good.

> diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
> index 90fb591..d57b61e 100644
> --- a/arch/arm/mach-ep93xx/core.c
> +++ b/arch/arm/mach-ep93xx/core.c
> @@ -29,12 +29,14 @@
>  #include <linux/termios.h>
>  #include <linux/amba/bus.h>
>  #include <linux/amba/serial.h>
> +#include <linux/spi/spi.h>

Nitpick... Please put this after the i2c includes below.

>  #include <linux/i2c.h>
>  #include <linux/i2c-gpio.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>
> @@ -363,6 +365,54 @@ void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr)
>  	platform_device_register(&ep93xx_eth_device);
>  }
>  
> +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

Please add (__initdata) at the end of the line above.

> + * @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);
> +}

Nitpick... Please move the spi block above after the i2c block below it.

>  /*************************************************************************
>   * EP93xx i2c peripheral handling

Other than the comments 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..52eebfd 100644
> --- a/arch/arm/mach-ep93xx/include/mach/platform.h
> +++ b/arch/arm/mach-ep93xx/include/mach/platform.h
> @@ -4,11 +4,13 @@
>  
>  #ifndef __ASSEMBLY__
>  
> +struct spi_board_info;
>  struct i2c_gpio_platform_data;
>  struct i2c_board_info;
>  struct platform_device;
>  struct ep93xxfb_mach_info;
>  struct ep93xx_keypad_platform_data;
> +struct ep93xx_spi_info;
>  
>  struct ep93xx_eth_data
>  {
> @@ -34,6 +36,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_spi(struct ep93xx_spi_info *info,
> +			 struct spi_board_info *devices, int num);
>  void ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
>  			 struct i2c_board_info *devices, int num);
>  void ep93xx_register_fb(struct ep93xxfb_mach_info *data);

Nitpick... Again, please move the spi stuff to after the i2c stuff.

I would like them moved since an i2c gpio expander "could" be used to provide
the chip selects for the spi controller.  Putting them in this order provides a
hint to the registration order for the devices to get the bindings correct. I
will provide the necessary patch to you shortly.

Again, this is all just nitpick stuff.

Overall this is all good.

Regards,
Hartley

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

* Re: [PATCH v5 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
       [not found]     ` <c24e9af6062e579499a1cb5782cdfe44e91cb9a1.1272476431.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
@ 2010-04-28 20:45       ` H Hartley Sweeten
  0 siblings, 0 replies; 7+ messages in thread
From: H Hartley Sweeten @ 2010-04-28 20:45 UTC (permalink / raw)
  To: Mika Westerberg, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Wednesday, April 28, 2010 10:51 AM, Mika Westerberg wrote:
>
> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
>
> Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>
> ---
>  Documentation/spi/ep93xx_spi                   |  102 +++
>  arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h |   32 +
>  drivers/spi/Kconfig                            |   11 +
>  drivers/spi/Makefile                           |    1 +
>  drivers/spi/ep93xx_spi.c                       |  972 ++++++++++++++++++++++++
>  5 files changed, 1118 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..bbb6fc2
> --- /dev/null
> +++ b/Documentation/spi/ep93xx_spi
> @@ -0,0 +1,102 @@
> +Cirrus EP93xx SPI controller driver HOWTO
> +=========================================
> +
> +ep93xx_spi driver brings SPI master support for EP93xx SPI controller. Driver
> +supports EP9301, EP9302, EP9307, EP9312 and EP9315 chips. Chip selects are
> +implemented with GPIO lines.

The "Driver supports EP9301..." is really not needed.  This driver will work with
any of the EP93xx variants.

> +
> +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>
> +
> +/*
> + * First declare our SD/MMC card as spi_board_info. We only have one device on
> + * this bus (this is also what mmc_spi expects).
> + */
> +static struct spi_board_info ts72xx_spi_devices[] __initconst = {

Not sure if it matters but I think this should be tagged '__initdata'.  Seems like
both tags and no tag are used, not sure which is more correct.

> +     {
> +             .modalias       = "mmc_spi",
> +             /*
> +              * 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,
> +     },
> +};
> +
> +/* this is our GPIO line used for chip select */
> +#define MMC_CHIP_SELECT_GPIO EP93XX_GPIO_LINE_EGPIO9
> +
> +static void ts72xx_spi_cs_control(struct spi_device *spi, int value)
> +{
> +     gpio_set_value(MMC_CHIP_SELECT_GPIO, value);
> +}
> +
> +static struct ep93xx_spi_info ts72xx_spi_info = {
> +     .num_chipselect = ARRAY_SIZE(ts72xx_spi_devices),
> +     .cs_control     = ts72xx_spi_cs_control,
> +};
> +
> +static void __init ts72xx_init_spi(void)
> +{
> +        unsigned gpio = MMC_CHIP_SELECT_GPIO;
> +        int err;
> +
> +     /*
> +      * Allocate chip select GPIO line here and configure it as output.
> +      */
> +        err = gpio_request(gpio, "ep93xx-spi");
> +        if (err) {
> +                pr_err("failed to allocate GPIO%d for SPI device\n", gpio);
> +                return;
> +        }
> +
> +        err = gpio_direction_output(gpio, 1);
> +        if (err) {
> +                pr_err("failed to configure GPIO%d for SPI device\n", gpio);
> +                gpio_free(gpio);
> +                return;
> +        }
> +
> +     /*
> +      * Now we can register the device. After this, the driver should be
> +      * ready.
> +      */
> +        ep93xx_register_spi(&ts72xx_spi_info, ts72xx_spi_devices,
> +                            ARRAY_SIZE(ts72xx_spi_devices));
> +}
> +
> +static void __init ts72xx_init_machine(void)
> +{
> +     ...
> +     ts72xx_init_spi();
> +}
> +
> +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.

Good starting point.  In a bit I will post a patch to change the chip select mechanism
to allow using non built-in gpios.  If it looks good this document will need a bit of
editing.

> 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..98935d8
> --- /dev/null
> +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
> @@ -0,0 +1,32 @@
> +#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
> + * @cs_control: chip select control function. Can be %NULL if not needed.
> + *
> + * This structure is passed from board support files to EP93xx SPI controller
> + * driver. It provides callback hook to control chip select lines that are
> + * allocated in board support files during the board initialization.
> + */
> +struct ep93xx_spi_info {
> +     int     num_chipselect;
> +     /*
> +      * cs_control() - control board chipselect GPIO lines
> +      * @spi: SPI device whose chipselect is controlled
> +      * @value: value to set the chip select line to
> +      *
> +      * This function is used to control board specific chip select lines.
> +      * @value is either %0 or %1.
> +      *
> +      * This function is called from thread context and can sleep if
> +      * necessary.
> +      */
> +     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..5852340 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -117,6 +117,17 @@ 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. This driver supports EP9301, EP9302, EP9307, EP9312 and EP9315
> +       chips.

Again, the "This driver supports..." is really not needed.

> +
> +       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..20d4f1d
> --- /dev/null
> +++ b/drivers/spi/ep93xx_spi.c
> @@ -0,0 +1,972 @@
> +/*
> + * Driver for Cirrus Logic EP93xx SPI controller.
> + *
> + * Copyright (c) 2010 Mika Westerberg
> + *
> + * Explicit FIFO handling code was inspired by amba-pl022 driver.
> + *
> + * 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/module.h>
> +#include <linux/moduleparam.h>

I don't think <linux/module.h> and <linux/moduleparam.h> are needed.

> +#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.
> + * @cs_control: chip select control function
> + *
> + * 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;
> +     void                            (*cs_control)(struct spi_device *, int);
> +};
> +
> +/**
> + * 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)
> + *
> + * 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;
> +};
> +
> +/* 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
> + * @espi: ep93xx SPI controller struct
> + * @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(const struct ep93xx_spi *espi,
> +                                      struct spi_device *spi,
> +                                      bool control)
> +{
> +     int value = (spi->mode & SPI_CS_HIGH) ? control : !control;
> +
> +     if (espi->cs_control)
> +             espi->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) {
> +             chip = kzalloc(sizeof(*chip), GFP_KERNEL);
> +             if (!chip)
> +                     return -ENOMEM;
> +
> +             spi_set_ctldata(spi, chip);
> +             chip->spi = spi;
> +     }
> +
> +     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(espi, 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) {
> +             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 %0 when
> + * current transfer was not yet completed otherwise length of the transfer
> + * (>%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)) {

It might be overkill but you might want to add:

        && espi->rx < t->len

to the end of this while statement.  It 'should' never happen, but if you
do get extra data it will cause problems...

> +             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 t->len;
> +     }
> +
> +     return 0;
> +}

Since the caller of this function doesn't use the 't->len' value, change this
function to return 0 on success and -EINPROGRESS when the transfer is still
happening.

> +
> +/**
> + * 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.
> +      */
> +     ep93xx_spi_read_write(espi);

Again, probably overkill, you should check the return value to make sure the
transfer is still in progress before enabling interrupts and waiting.

> +     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(espi, msg->spi, false);
> +                     cond_resched();
> +                     ep93xx_spi_cs_control(espi, 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(espi, 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(espi, 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 that come from the SPI controller.
> + * Returns %IRQ_HANDLED when interrupt was handled and %IRQ_NONE in case the
> + * @irq was not handled.
> + */
> +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->cs_control = info->cs_control;
> +
> +     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);

Nitpick, you have a stray TAB after the = instead of a space.

> +     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");

Regards,
Hartley

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

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

* Re: [PATCH v5 0/2] spi: driver for Cirrus EP93xx SPI controller
       [not found] ` <cover.1272476431.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
  2010-04-28 17:51   ` [PATCH v5 1/2] spi: implemented " Mika Westerberg
  2010-04-28 17:51   ` [PATCH v5 2/2] ep93xx: SPI driver platform support code Mika Westerberg
@ 2010-04-28 22:30   ` H Hartley Sweeten
       [not found]     ` <0D753D10438DA54287A00B0270842697636DB622A3-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
  2 siblings, 1 reply; 7+ messages in thread
From: H Hartley Sweeten @ 2010-04-28 22:30 UTC (permalink / raw)
  To: Mika Westerberg, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Wednesday, April 28, 2010 10:51 AM, Mika Westerberg wrote:
> 
> Hello,
> 
> This series implements SPI master driver for Cirrus Logic EP93xx SPI
> controllers.
> 
> This is fifth iteration of the driver.
> 
> Changes to the previous version:
> 	- addressed review comments
> 	- added priming the TX FIFO when transfer is started
> 	- in case of ROR interrupt we clear it
> 	- added documentation in Documentation/spi/ep93xx_spi which provides
> 	  sample code how the driver can be hooked into platform data
> 
> 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
> 

Mika,

Following is a patch to allow using built-in gpios, external gpio expanders
(spi/i2c/etc.) or really any other mechanism for the chip select.

Using your example in Documentation/spi/ep93xx_spi as a starting point, the
modified setup code would look like this:

+...
+#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[] __initconst = {
+	{
+		.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));
+}


Every spi device in struct spi_board_info would have it's own private
struct ep93xx_spi_chip_ops which is passed in the controller_data
field.

Note, this isn't a git produced patch.  I currently don't have my development
tree under git control...

---

Expand the chip select options for the ep93xx_spi driver to allow using
spi/i2c/etc. gpio expanders to provide the chip selects.

This introduces a per-chip structure to provide setup/cleanup callbacks
for the chip select mechanism and a cs_control callback that is used to
actually select/deselect the device.

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

---

--- arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h.orig	2010-04-28 14:36:14.000000000 -0700
+++ arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h	2010-04-28 15:27:39.000000000 -0700
@@ -7,25 +7,20 @@ 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
- * @cs_control: chip select control function. Can be %NULL if not needed.
- *
- * This structure is passed from board support files to EP93xx SPI controller
- * driver. It provides callback hook to control chip select lines that are
- * allocated in board support files during the board initialization.
  */
 struct ep93xx_spi_info {
 	int	num_chipselect;
-	/*
-	 * cs_control() - control board chipselect GPIO lines
-	 * @spi: SPI device whose chipselect is controlled
-	 * @value: value to set the chip select line to
-	 *
-	 * This function is used to control board specific chip select lines.
-	 * @value is either %0 or %1.
-	 *
-	 * This function is called from thread context and can sleep if
-	 * necessary.
-	 */
+};
+
+/**
+ * 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);
 };
 
--- drivers/spi/ep93xx_spi.c.orig	2010-04-28 13:06:07.000000000 -0700
+++ drivers/spi/ep93xx_spi.c	2010-04-28 15:24:47.000000000 -0700
@@ -84,7 +84,6 @@
  * @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.
- * @cs_control: chip select control function
  *
  * This structure holds EP93xx SPI controller specific information. When
  * @running is %true, driver accepts transfer requests from protocol drivers.
@@ -113,7 +112,6 @@ struct ep93xx_spi {
 	size_t				tx;
 	size_t				rx;
 	size_t				fifo_level;
-	void				(*cs_control)(struct spi_device *, int);
 };
 
 /**
@@ -123,6 +121,7 @@ struct ep93xx_spi {
  * @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
@@ -134,6 +133,7 @@ struct ep93xx_spi_chip {
 	u8			div_cpsr;
 	u8			div_scr;
 	u8			dss;
+	struct ep93xx_spi_chip_ops *ops;
 };
 
 /* converts bits per word to CR0.DSS value */
@@ -283,7 +283,6 @@ static int ep93xx_spi_calc_divisors(cons
 
 /**
  * ep93xx_spi_cs_control() - controls chipselect for given device
- * @espi: ep93xx SPI controller struct
  * @spi: SPI device to select/deselect
  * @control: select (%true) / deselect (%false)
  *
@@ -291,14 +290,13 @@ static int ep93xx_spi_calc_divisors(cons
  *
  * Note that this function is called from a thread context and can sleep.
  */
-static inline void ep93xx_spi_cs_control(const struct ep93xx_spi *espi,
-					 struct spi_device *spi,
-					 bool control)
+static void ep93xx_spi_cs_control(struct spi_device *spi, bool control)
 {
+	struct ep93xx_spi_chip *chip = spi_get_ctldata(spi);
 	int value = (spi->mode & SPI_CS_HIGH) ? control : !control;
 
-	if (espi->cs_control)
-		espi->cs_control(spi, value);
+	if (chip->ops && chip->ops->cs_control)
+		chip->ops->cs_control(spi, value);
 }
 
 /**
@@ -323,12 +321,25 @@ static int ep93xx_spi_setup(struct spi_d
 
 	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;
 
-		spi_set_ctldata(spi, chip);
 		chip->spi = spi;
+		chip->ops = spi->controller_data;
+
+		if (chip->ops && chip->ops->setup) {
+			ret = chip->ops->setup(spi);
+			if (ret) {
+				kfree(chip);
+				return ret;
+			}
+		}
+
+		spi_set_ctldata(spi, chip);
 	}
 
 	if (spi->max_speed_hz != chip->rate) {
@@ -345,7 +356,7 @@ static int ep93xx_spi_setup(struct spi_d
 
 	chip->dss = bits_per_word_to_dss(spi->bits_per_word);
 
-	ep93xx_spi_cs_control(espi, spi, false);
+	ep93xx_spi_cs_control(spi, false);
 	return 0;
 }
 
@@ -414,6 +425,8 @@ static void ep93xx_spi_cleanup(struct sp
 
 	chip = spi_get_ctldata(spi);
 	if (chip) {
+		if (chip->ops && chip->ops->cleanup)
+			chip->ops->cleanup(spi);
 		spi_set_ctldata(spi, NULL);
 		kfree(chip);
 	}
@@ -610,9 +623,9 @@ static void ep93xx_spi_process_transfer(
 			 * chipselect briefly, we let the scheduler to handle
 			 * any "delay" here.
 			 */
-			ep93xx_spi_cs_control(espi, msg->spi, false);
+			ep93xx_spi_cs_control(msg->spi, false);
 			cond_resched();
-			ep93xx_spi_cs_control(espi, msg->spi, true);
+			ep93xx_spi_cs_control(msg->spi, true);
 		}
 	}
 
@@ -674,7 +687,7 @@ static void ep93xx_spi_process_message(s
 	 * the chipselect.
 	 */
 	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
-	ep93xx_spi_cs_control(espi, msg->spi, true);
+	ep93xx_spi_cs_control(msg->spi, true);
 
 	list_for_each_entry(t, &msg->transfers, transfer_list) {
 		ep93xx_spi_process_transfer(espi, msg, t);
@@ -686,7 +699,7 @@ static void ep93xx_spi_process_message(s
 	 * Now the whole message is transferred (or failed for some reason). We
 	 * deselect the device and disable the SPI controller.
 	 */
-	ep93xx_spi_cs_control(espi, msg->spi, false);
+	ep93xx_spi_cs_control(msg->spi, false);
 	ep93xx_spi_disable(espi);
 }
 
@@ -811,7 +824,6 @@ static int __init ep93xx_spi_probe(struc
 	platform_set_drvdata(pdev, master);
 
 	espi = spi_master_get_devdata(master);
-	espi->cs_control = info->cs_control;
 
 	espi->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(espi->clk)) {
@@ -860,7 +872,7 @@ static int __init ep93xx_spi_probe(struc
 	}
 
 	error = request_irq(espi->irq, ep93xx_spi_interrupt, 0,
-			    "ep93xx-spi", espi);
+				"ep93xx-spi", espi);
 	if (error) {
 		dev_err(&pdev->dev, "failed to request irq\n");
 		goto fail_unmap_regs;
@@ -878,7 +890,7 @@ static int __init ep93xx_spi_probe(struc
 	/* make sure that the hardware is disabled */
 	ep93xx_spi_write_u8(espi, SSPCR1, 0);
 
-	error =	spi_register_master(master);
+	error = spi_register_master(master);
 	if (error) {
 		dev_err(&pdev->dev, "failed to register SPI master\n");
 		goto fail_free_queue;

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

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

* Re: [PATCH v5 0/2] spi: driver for Cirrus EP93xx SPI controller
       [not found]     ` <0D753D10438DA54287A00B0270842697636DB622A3-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
@ 2010-04-29 10:49       ` Mika Westerberg
  0 siblings, 0 replies; 7+ messages in thread
From: Mika Westerberg @ 2010-04-29 10:49 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Wed, Apr 28, 2010 at 05:30:25PM -0500, H Hartley Sweeten wrote:
> On Wednesday, April 28, 2010 10:51 AM, Mika Westerberg wrote:
> > 
> > Hello,
> > 
> > This series implements SPI master driver for Cirrus Logic EP93xx SPI
> > controllers.
> > 
> > This is fifth iteration of the driver.
> > 
> > Changes to the previous version:
> > 	- addressed review comments
> > 	- added priming the TX FIFO when transfer is started
> > 	- in case of ROR interrupt we clear it
> > 	- added documentation in Documentation/spi/ep93xx_spi which provides
> > 	  sample code how the driver can be hooked into platform data
> > 
> > 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
> > 
> 
> Mika,
> 
> Following is a patch to allow using built-in gpios, external gpio expanders
> (spi/i2c/etc.) or really any other mechanism for the chip select.

Ok, thanks. I'll wait a bit if there are more comments and then
incorporate your patch along with your review comments and post v6.
I'm really hoping that v6 would be last revision.

Regards,
MW

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

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

end of thread, other threads:[~2010-04-29 10:49 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-28 17:51 [PATCH v5 0/2] spi: driver for Cirrus EP93xx SPI controller Mika Westerberg
     [not found] ` <cover.1272476431.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
2010-04-28 17:51   ` [PATCH v5 1/2] spi: implemented " Mika Westerberg
     [not found]     ` <c24e9af6062e579499a1cb5782cdfe44e91cb9a1.1272476431.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
2010-04-28 20:45       ` H Hartley Sweeten
2010-04-28 17:51   ` [PATCH v5 2/2] ep93xx: SPI driver platform support code Mika Westerberg
2010-04-28 18:31     ` H Hartley Sweeten
2010-04-28 22:30   ` [PATCH v5 0/2] spi: driver for Cirrus EP93xx SPI controller H Hartley Sweeten
     [not found]     ` <0D753D10438DA54287A00B0270842697636DB622A3-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-29 10:49       ` Mika Westerberg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).