linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 1/6] spi: s6000 spi host driver
@ 2009-03-23 15:34 Daniel Glöckner
  2009-03-23 15:34 ` [patch 2/6] xtensa: add s6000 spi host to s6105 platform Daniel Glöckner
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Daniel Glöckner @ 2009-03-23 15:34 UTC (permalink / raw)
  To: Chris Zankel, David Brownell
  Cc: spi-devel-general, linux-kernel, Johannes Weiner, Daniel Glöckner

From: Johannes Weiner <jw@emlix.com>

The host controller has a 128 bit buffer which is shared between rx and tx.
Filling and reading of this buffer happens in a dedicated workqueue.
We always fill it with an integer number of words but don't cross
spi_transfer boundaries.

The driver usually uses interrupts but falls back to polling if the
transfer is expected to finish within a certain window of time.

Signed-off-by: Johannes Weiner <jw@emlix.com>
Signed-off-by: Daniel Glöckner <dg@emlix.com>
---
 drivers/spi/Kconfig           |    6 +
 drivers/spi/Makefile          |    1 +
 drivers/spi/spi_s6000.c       |  648 +++++++++++++++++++++++++++++++++++++++++
 drivers/spi/spi_s6000.h       |   26 ++
 include/linux/spi/spi_s6000.h |   10 +
 5 files changed, 691 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/spi_s6000.c
 create mode 100644 drivers/spi/spi_s6000.h
 create mode 100644 include/linux/spi/spi_s6000.h

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 83a185d..c373717 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -197,6 +197,12 @@ config SPI_S3C24XX_GPIO
 	  the inbuilt hardware cannot provide the transfer mode, or
 	  where the board is using non hardware connected pins.
 
+config SPI_S6000
+	tristate "S6000 SPI master"
+	depends on SPI_MASTER && XTENSA_VARIANT_S6000
+	help
+	  SPI driver for the Stretch S6000 family SoCs.
+
 config SPI_SH_SCI
 	tristate "SuperH SCI SPI controller"
 	depends on SUPERH
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 5d04519..3a4dae7 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC83xx)		+= spi_mpc83xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx.o
+obj-$(CONFIG_SPI_S6000)			+= spi_s6000.o
 obj-$(CONFIG_SPI_TXX9)			+= spi_txx9.o
 obj-$(CONFIG_SPI_XILINX)		+= xilinx_spi.o
 obj-$(CONFIG_SPI_SH_SCI)		+= spi_sh_sci.o
diff --git a/drivers/spi/spi_s6000.c b/drivers/spi/spi_s6000.c
new file mode 100644
index 0000000..3f3eb92
--- /dev/null
+++ b/drivers/spi/spi_s6000.c
@@ -0,0 +1,648 @@
+/*
+ * s6000 SPI master driver
+ *
+ * Copyright (C) 2009 emlix GmbH
+ * Authors:	Johannes Weiner <jw@emlix.com>
+ *		Daniel Gloeckner <dg@emlix.com>
+ *
+ * All code subject to the GNU GPL version 2.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_s6000.h>
+#include <asm/io.h>
+
+#include "spi_s6000.h"
+
+static unsigned long irq_thres = 20000;
+module_param(irq_thres, ulong, 0644);
+
+/* Maximum transfer chunk */
+#define CHUNK_MAX_BITS	(1 << 7)
+#define CHUNK_MAX	(CHUNK_MAX_BITS / 8)
+
+/* Master state */
+struct s6spi {
+	u8 __iomem *mem;
+	struct mutex mutex;
+	spinlock_t lock;
+	struct spi_transfer *xfer;
+	unsigned int busylen;
+	unsigned int remain;
+	unsigned int bits;
+	struct spi_device *spi;
+	struct list_head messages;
+	struct work_struct work;
+	struct workqueue_struct *workqueue;
+	struct clk *clk;
+	struct resource *region;
+	int irq;
+	u32 speed;
+	u8 scratch[CHUNK_MAX_BITS]; /* _BITS for bits_per_word == 1 */
+	u8 cs_deasserted;
+	u8 went_busy;
+};
+
+struct bufstate {
+	u32 __iomem *reg;
+	u32 val;
+	int fill;
+};
+
+#define SPI_READ(s6spi, reg) readl(s6spi->mem + reg)
+#define SPI_WRITE(s6spi, reg, val) writel(val, s6spi->mem + reg)
+
+static u32 get_rx(struct bufstate *bs, int bits)
+{
+	u32 val = bs->val;
+	bs->val >>= bits;
+	bs->fill -= bits;
+	if (bs->fill < 0) {
+		bs->val = readl(bs->reg);
+		bs->reg++;
+		if (bits + bs->fill == 0)
+			val = bs->val; /* there may have been garbage in val */
+		else
+			val |= bs->val << (bits + bs->fill);
+		bs->val >>= -bs->fill;
+		bs->fill += 32;
+	}
+	if (bits < 32)
+		val &= (1 << bits) - 1;
+	return val;
+}
+
+static void put_tx(struct bufstate *bs, u32 val, int bits)
+{
+	bs->val |= val << bs->fill;
+	bs->fill += bits;
+	if (bs->fill >= 32) {
+		bs->fill -= 32;
+		writel(bs->val, bs->reg);
+		bs->val = 0; /* catch u32 >> 32 case */
+		if (bs->fill)
+			bs->val = val >> (bits - bs->fill);
+		bs->reg++;
+	}
+	bs->val &= (1 << bs->fill) - 1;
+}
+
+/*
+ * s6spi_read_rx - read words from receive registers
+ * @s6spi: Device structure
+ * @rx_buf: pointer to buffer for received words
+ * @xfer_len: size of buffer in bytes
+ * @bits: bits per word
+ * @returns: number of bytes written to buffer or -EINVAL
+ */
+static int s6spi_read_rx(struct s6spi *s6spi, void *rx_buf)
+{
+	struct spi_device *spi = s6spi->spi;
+	unsigned int len, xfer_len, bits;
+	struct bufstate bs;
+	int i;
+
+	xfer_len = s6spi->busylen;
+	bits = s6spi->bits;
+	len = CHUNK_MAX_BITS / bits;
+
+	bs.reg = (u32 __iomem *)(s6spi->mem + S6_SPI_RX0);
+	bs.val = 0;
+	bs.fill = 0;
+
+	if (bits <= 8) {
+		u8 *buf = rx_buf;
+		if (len > xfer_len)
+			len = xfer_len;
+		if (spi->mode & SPI_LSB_FIRST)
+			for (i = 0; i < len; i++)
+				buf[i] = get_rx(&bs, bits);
+		else
+			for (i = len; i--;)
+				buf[i] = get_rx(&bs, bits);
+	} else if (bits <= 16) {
+		u16 *buf = rx_buf;
+		xfer_len /= 2;
+		if (len > xfer_len)
+			len = xfer_len;
+		if (spi->mode & SPI_LSB_FIRST)
+			for (i = 0; i < len; i++)
+				buf[i] = get_rx(&bs, bits);
+		else
+			for (i = len; i--;)
+				buf[i] = get_rx(&bs, bits);
+		len *= 2;
+	} else if (bits <= 32) {
+		u32 *buf = rx_buf;
+		xfer_len /= 4;
+		if (len > xfer_len)
+			len = xfer_len;
+		if (spi->mode & SPI_LSB_FIRST)
+			for (i = 0; i < len; i++)
+				buf[i] = get_rx(&bs, bits);
+		else
+			for (i = len; i--;)
+				buf[i] = get_rx(&bs, bits);
+		len *= 4;
+	} else
+		return -EINVAL;
+	return len;
+}
+
+/*
+ * s6spi_write_tx - write words to transmit registers
+ * @s6spi: Device structure
+ * @rx_buf: pointer to buffer of words to send
+ * @xfer_len: size of buffer in bytes
+ * @bits: bits per word
+ * @returns: number of bytes taken from the buffer or -EINVAL
+ */
+static int s6spi_write_tx(struct s6spi *s6spi, const void *tx_buf)
+{
+	struct spi_device *spi = s6spi->spi;
+	unsigned int len, xfer_len, bits;
+	struct bufstate bs;
+	int i;
+	unsigned int words, ctrl;
+
+	xfer_len = s6spi->remain;
+	bits = s6spi->bits;
+	words = CHUNK_MAX_BITS / bits;
+
+	bs.reg = (u32 __iomem *)(s6spi->mem + S6_SPI_TX0);
+	bs.val = 0;
+	bs.fill = 0;
+
+	if (bits <= 8) {
+		u8 *buf = (u8 *)tx_buf;
+		if (words > xfer_len)
+			words = xfer_len;
+		if (spi->mode & SPI_LSB_FIRST)
+			for (i = 0; i < words; i++)
+				put_tx(&bs, buf[i], bits);
+		else
+			for (i = words; i--;)
+				put_tx(&bs, buf[i], bits);
+		len = words;
+	} else if (bits <= 16) {
+		u16 *buf = (u16 *)tx_buf;
+		xfer_len /= 2;
+		if (words > xfer_len)
+			words = xfer_len;
+		if (spi->mode & SPI_LSB_FIRST)
+			for (i = 0; i < words; i++)
+				put_tx(&bs, buf[i], bits);
+		else
+			for (i = words; i--;)
+				put_tx(&bs, buf[i], bits);
+		len = words * 2;
+	} else if (bits <= 32) {
+		u32 *buf = (u32 *)tx_buf;
+		xfer_len /= 4;
+		if (words > xfer_len)
+			words = xfer_len;
+		if (spi->mode & SPI_LSB_FIRST)
+			for (i = 0; i < words; i++)
+				put_tx(&bs, buf[i], bits);
+		else
+			for (i = words; i--;)
+				put_tx(&bs, buf[i], bits);
+		len = words * 4;
+	} else
+		return -EINVAL;
+	if (bs.fill)
+		writel(bs.val, bs.reg);
+
+	ctrl = SPI_READ(s6spi, S6_SPI_CTRL);
+	ctrl &= ~((CHUNK_MAX_BITS - 1) << S6_SPI_CTRL_CHAR_LEN);
+	ctrl |=	((words * bits) & (CHUNK_MAX_BITS - 1)) << S6_SPI_CTRL_CHAR_LEN;
+	SPI_WRITE(s6spi, S6_SPI_CTRL, ctrl);
+
+	return len;
+}
+
+static void s6spi_init_hw(struct s6spi *s6spi)
+{
+	SPI_WRITE(s6spi, S6_SPI_CTRL, 0);
+	SPI_WRITE(s6spi, S6_SPI_SS, s6spi->cs_deasserted);
+}
+
+static void s6spi_set_speed(struct s6spi *s6spi, u32 hz)
+{
+	u32 divider;
+
+	if (!hz) {
+		printk(KERN_ERR "s6spi: 0Hz bus speed requested\n");
+		return;
+	}
+	if (s6spi->speed == hz)
+		return;
+	s6spi->speed = hz;
+	/*
+	 *            clock
+	 * hz = -----------------
+	 *      (divider + 1) * 2
+	 */
+	divider = (clk_get_rate(s6spi->clk) + (2 * hz) - 1) / (2 * hz) - 1;
+	if (divider > S6_SPI_DIVIDER_MAX)
+		divider = S6_SPI_DIVIDER_MAX;
+	SPI_WRITE(s6spi, S6_SPI_DIVIDER, divider);
+}
+
+static void s6spi_set_parms(struct spi_device *spi)
+{
+	struct s6spi *s6spi = spi_master_get_devdata(spi->master);
+	u32 ctrl;
+	int cpol = !!(spi->mode & SPI_CPOL);
+
+	ctrl = SPI_READ(s6spi, S6_SPI_CTRL);
+	/*
+	 * 0			= S6_SPI_CTRL_Tx_NEG
+	 * 0 | CPHA		= S6_SPI_CTRL_Rx_NEG
+	 * CPOL | 0		= S6_SPI_CTRL_Rx_NEG
+	 * CPOL | CPHA		= S6_SPI_CTRL_Tx_NEG
+	 */
+	if (spi->mode & SPI_CPHA)
+		cpol = !cpol;
+
+	ctrl |= cpol << S6_SPI_CTRL_Rx_NEG;
+	ctrl |= !cpol << S6_SPI_CTRL_Tx_NEG;
+
+	if (cpol)
+		ctrl |= (1 << S6_SPI_CTRL_CPOL);
+	if (spi->mode & SPI_LSB_FIRST)
+		ctrl |= (1 << S6_SPI_CTRL_LSB);
+	SPI_WRITE(s6spi, S6_SPI_CTRL, ctrl);
+}
+
+static void s6spi_chip_select(struct spi_device *spi, int on)
+{
+	struct s6spi *s6spi = spi_master_get_devdata(spi->master);
+	u32 value = s6spi->cs_deasserted;
+
+	if (on) {
+		s6spi_set_parms(spi);
+		value ^= 1 << spi->chip_select;
+	}
+	SPI_WRITE(s6spi, S6_SPI_SS, value);
+}
+
+static int s6spi_go_busy(struct s6spi *s6spi)
+{
+	int use_irq;
+	u32 ctrl, divider, bits;
+	divider = SPI_READ(s6spi, S6_SPI_DIVIDER) & S6_SPI_DIVIDER_MAX;
+	divider++;
+	ctrl = SPI_READ(s6spi, S6_SPI_CTRL);
+	bits = (ctrl >> S6_SPI_CTRL_CHAR_LEN) & (CHUNK_MAX_BITS - 1);
+	if (!bits)
+		bits = CHUNK_MAX_BITS;
+	use_irq = (bits * divider > irq_thres);
+	s6spi->went_busy = use_irq;
+	ctrl &= ~(1 << S6_SPI_CTRL_IE);
+	ctrl |= use_irq << S6_SPI_CTRL_IE;
+	ctrl |= 1 << S6_SPI_CTRL_GO_BSY;
+	SPI_WRITE(s6spi, S6_SPI_CTRL, ctrl);
+	return use_irq;
+}
+
+static u32 s6spi_is_busy(struct s6spi *s6spi)
+{
+	return SPI_READ(s6spi, S6_SPI_CTRL) & (1 << S6_SPI_CTRL_GO_BSY);
+}
+
+static void s6spi_int_clear(struct s6spi *s6spi)
+{
+	SPI_WRITE(s6spi, S6_SPI_INT_CLR, 1);
+}
+
+static void s6spi_setup_xfer(struct s6spi *s6spi)
+{
+	struct spi_transfer *xfer = s6spi->xfer;
+	struct spi_device *spi = s6spi->spi;
+	u32 speed;
+
+	speed = xfer->speed_hz;
+	if (!speed)
+		speed = spi->max_speed_hz;
+	s6spi_set_speed(s6spi, speed);
+
+	s6spi->bits = xfer->bits_per_word;
+	if (!s6spi->bits)
+		s6spi->bits = spi->bits_per_word;
+	if (!s6spi->bits)
+		s6spi->bits = 8;
+}
+
+static int s6spi_start_xfer(struct s6spi *s6spi)
+{
+	const void *tx_buf;
+	struct spi_transfer *xfer = s6spi->xfer;
+
+	if (!xfer) {			/* Next message */
+		struct spi_device *spi;
+		struct spi_message *msg;
+
+		if (list_empty(&s6spi->messages))
+			return 1;
+
+		msg = list_first_entry(&s6spi->messages,
+				struct spi_message, queue);
+		xfer = list_first_entry(&msg->transfers,
+				struct spi_transfer, transfer_list);
+
+		msg->status = -EINPROGRESS;
+		msg->actual_length = 0;
+
+		spi = msg->spi;
+		s6spi->spi = spi;
+		s6spi_chip_select(spi, 1);
+
+		s6spi->xfer = xfer;
+		s6spi->remain = xfer->len;
+		s6spi_setup_xfer(s6spi);
+	} else if (!s6spi->remain) {	/* Next transfer in message */
+		if (xfer->delay_usecs)
+			udelay(xfer->delay_usecs);
+		if (xfer->cs_change) {
+			s6spi_chip_select(s6spi->spi, 0);
+			udelay(1);
+			s6spi_chip_select(s6spi->spi, 1);
+		}
+		xfer = list_entry(xfer->transfer_list.next,
+				struct spi_transfer, transfer_list);
+		s6spi->xfer = xfer;
+		s6spi->remain = xfer->len;
+		s6spi_setup_xfer(s6spi);
+	}
+
+	tx_buf = s6spi->scratch;
+	if (xfer->tx_buf)
+		tx_buf = xfer->tx_buf + xfer->len - s6spi->remain;
+
+	s6spi->busylen = s6spi_write_tx(s6spi, tx_buf);
+	return s6spi_go_busy(s6spi);
+}
+
+static void s6spi_end_xfer(struct s6spi *s6spi)
+{
+	void *rx_buf;
+	struct spi_message *msg;
+	struct spi_transfer *xfer = s6spi->xfer;
+
+	if (!xfer)
+		return;
+
+	rx_buf = xfer->rx_buf + xfer->len - s6spi->remain;
+	s6spi->remain -= s6spi->busylen;
+
+	msg = list_first_entry(&s6spi->messages, struct spi_message, queue);
+	msg->actual_length += s6spi->busylen;
+
+	if (xfer->rx_buf)
+		s6spi_read_rx(s6spi, rx_buf);
+
+	if (s6spi->remain)
+		return;
+
+	if (xfer->transfer_list.next == &msg->transfers) {
+		/*
+		 * Last transfer, complete the message
+		 * and check the message queue.
+		 */
+		if (xfer->delay_usecs)
+			udelay(xfer->delay_usecs);
+		if (!xfer->cs_change)
+			s6spi_chip_select(msg->spi, 0);
+		s6spi->xfer = NULL;
+
+		spin_lock(&s6spi->lock);
+		list_del(&msg->queue);
+		spin_unlock(&s6spi->lock);
+
+		msg->status = 0;
+		msg->complete(msg->context);
+	}
+}
+
+static irqreturn_t s6spi_interrupt(int irq, void *dev_id)
+{
+	struct spi_master *master = dev_id;
+	struct s6spi *s6spi = spi_master_get_devdata(master);
+
+	s6spi_int_clear(s6spi);
+	if (!s6spi->went_busy || s6spi_is_busy(s6spi))
+		return IRQ_NONE;
+	s6spi->went_busy = 0;
+	queue_work(s6spi->workqueue, &s6spi->work);
+	return IRQ_HANDLED;
+}
+
+static void s6spi_worker(struct work_struct *ws)
+{
+	int use_irq;
+	struct s6spi *s6spi = container_of(ws, struct s6spi, work);
+
+	do {
+		while (s6spi_is_busy(s6spi));
+
+		mutex_lock(&s6spi->mutex);
+		s6spi_end_xfer(s6spi);
+		use_irq = s6spi_start_xfer(s6spi);
+		mutex_unlock(&s6spi->mutex);
+	} while (!use_irq);
+}
+
+static int s6spi_setup(struct spi_device *spi)
+{
+	u8 mask;
+	struct s6spi *s6spi = spi_master_get_devdata(spi->master);
+
+	mask = 1 << spi->chip_select;
+	mutex_lock(&s6spi->mutex);
+	if (spi->mode & SPI_CS_HIGH)
+		s6spi->cs_deasserted |= mask;
+	else
+		s6spi->cs_deasserted &= ~mask;
+	if (!s6spi->xfer)
+		s6spi_chip_select(spi, 0);
+	mutex_unlock(&s6spi->mutex);
+
+	return 0;
+}
+
+static int s6spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+	struct s6spi *s6spi = spi_master_get_devdata(spi->master);
+
+	if (list_empty(&msg->transfers))
+		return -EINVAL;
+
+	spin_lock(&s6spi->lock);
+	list_add_tail(&msg->queue, &s6spi->messages);
+	spin_unlock(&s6spi->lock);
+
+	if (!s6spi->xfer)
+		queue_work(s6spi->workqueue, &s6spi->work);
+
+	return 0;
+}
+
+static int __devinit s6spi_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct s6spi *s6spi;
+	struct spi_master *master;
+	struct resource *res;
+	const char *clock;
+
+	master = spi_alloc_master(&pdev->dev, sizeof(struct s6spi));
+	if (!master)
+		return -ENOMEM;
+
+	master->bus_num = -1;
+	master->setup = s6spi_setup;
+	master->transfer = s6spi_transfer;
+	master->num_chipselect = 8;
+	platform_set_drvdata(pdev, master);
+
+	ret = platform_get_irq(pdev, 0);
+	if (ret < 0)
+		goto error_master;
+
+	s6spi = spi_master_get_devdata(master);
+	s6spi->irq = ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -EINVAL;
+		goto error_master;
+	}
+	s6spi->region = request_mem_region(res->start,
+					   res->end - res->start + 1,
+					   pdev->dev.bus_id);
+	if (!s6spi->region) {
+		ret = -EBUSY;
+		goto error_master;
+	}
+	s6spi->mem = ioremap_nocache(res->start, res->end - res->start + 1);
+	if (!s6spi->mem) {
+		ret = -ENOMEM;
+		goto error_region;
+	}
+
+	s6spi->cs_deasserted = 0;
+	clock = 0;
+	if (pdev->dev.platform_data) {
+		struct s6_spi_platform_data *pdata = pdev->dev.platform_data;
+		s6spi->cs_deasserted = pdata->cs_polarity;
+		master->bus_num = pdata->bus_num;
+		clock = pdata->clock;
+	}
+
+	s6spi->clk = clk_get(&pdev->dev, clock);
+	if (IS_ERR(s6spi->clk)) {
+		ret = PTR_ERR(s6spi->clk);
+		goto error_mapping;
+	}
+	ret = clk_enable(s6spi->clk);
+	if (ret < 0)
+		goto error_clk_put;
+
+	s6spi->workqueue = create_workqueue("spi_s6000");
+	if (!s6spi->workqueue) {
+		ret = -ENOMEM;
+		goto error_clk_dis;
+	}
+
+	ret = request_irq(s6spi->irq, s6spi_interrupt, IRQF_SHARED,
+			  pdev->dev.bus_id, master);
+	if (ret < 0)
+		goto error_wq;
+
+	INIT_WORK(&s6spi->work, s6spi_worker);
+	mutex_init(&s6spi->mutex);
+	spin_lock_init(&s6spi->lock);
+	INIT_LIST_HEAD(&s6spi->messages);
+
+	s6spi->speed = 0;
+	s6spi_init_hw(s6spi);
+
+	ret = spi_register_master(master);
+	if (ret < 0)
+		goto error_irq;
+
+
+	printk(KERN_INFO "s6spi: S6000 SPI master driver <info@emlix.com>\n");
+	return 0;
+
+error_irq:
+	free_irq(s6spi->irq, master);
+error_wq:
+	destroy_workqueue(s6spi->workqueue);
+error_clk_dis:
+	clk_disable(s6spi->clk);
+error_clk_put:
+	clk_put(s6spi->clk);
+error_mapping:
+	iounmap(s6spi->mem);
+error_region:
+	release_mem_region(s6spi->region->start,
+			   s6spi->region->end - s6spi->region->start + 1);
+error_master:
+	spi_master_put(master);
+	return ret;
+}
+
+static int __devexit s6spi_remove(struct platform_device *pdev)
+{
+	struct s6spi *s6spi;
+	struct spi_master *master;
+
+	master = platform_get_drvdata(pdev);
+	s6spi = spi_master_get_devdata(master);
+
+	/* TODO: wait for transfers to finish */
+	destroy_workqueue(s6spi->workqueue);
+	iounmap(s6spi->mem);
+	release_mem_region(s6spi->region->start,
+			   s6spi->region->end - s6spi->region->start + 1);
+	clk_disable(s6spi->clk);
+	clk_put(s6spi->clk);
+	free_irq(s6spi->irq, master);
+	spi_unregister_master(master);
+	return 0;
+}
+
+static struct platform_driver s6spi_driver = {
+	.probe	= s6spi_probe,
+	.remove = __devexit_p(s6spi_remove),
+	.driver	= {
+		.name	= "spi_s6000",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init s6spi_init(void)
+{
+	return platform_driver_register(&s6spi_driver);
+}
+module_init(s6spi_init);
+
+static void __exit s6spi_exit(void)
+{
+	platform_driver_unregister(&s6spi_driver);
+}
+module_exit(s6spi_exit);
+
+MODULE_AUTHOR("Johannes Weiner <jw@emlix.com>");
+MODULE_DESCRIPTION("S6000 SPI master driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_s6000.h b/drivers/spi/spi_s6000.h
new file mode 100644
index 0000000..eff82e3
--- /dev/null
+++ b/drivers/spi/spi_s6000.h
@@ -0,0 +1,26 @@
+#ifndef __DRIVERS_SPI_SPI_S6000_H
+#define __DRIVERS_SPI_SPI_S6000_H
+
+#define S6_SPI_RX0		0x00
+#define S6_SPI_RX1		0x04
+#define S6_SPI_RX2		0x08
+#define S6_SPI_RX3		0x0C
+#define S6_SPI_TX0		0x00
+#define S6_SPI_TX1		0x04
+#define S6_SPI_TX2		0x08
+#define S6_SPI_TX3		0x0C
+#define S6_SPI_CTRL		0x10
+#define S6_SPI_CTRL_GO_BSY		0
+#define S6_SPI_CTRL_Rx_NEG		1
+#define S6_SPI_CTRL_Tx_NEG		2
+#define S6_SPI_CTRL_CHAR_LEN		3
+#define S6_SPI_CTRL_LSB			10
+#define S6_SPI_CTRL_IE			11
+#define S6_SPI_CTRL_ASS			12
+#define S6_SPI_CTRL_CPOL		13
+#define S6_SPI_DIVIDER		0x14
+#define S6_SPI_DIVIDER_MAX		0xffff
+#define S6_SPI_SS		0x18
+#define S6_SPI_INT_CLR		0x20
+
+#endif
diff --git a/include/linux/spi/spi_s6000.h b/include/linux/spi/spi_s6000.h
new file mode 100644
index 0000000..9a02bb5
--- /dev/null
+++ b/include/linux/spi/spi_s6000.h
@@ -0,0 +1,10 @@
+#ifndef __LINUX_SPI_SPI_S6000_H
+#define __LINUX_SPI_SPI_S6000_H
+
+struct s6_spi_platform_data {
+	const char *clock;
+	s16 bus_num;
+	u8 cs_polarity;
+};
+
+#endif
-- 
1.6.2.107.ge47ee

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

* [patch 2/6] xtensa: add s6000 spi host to s6105 platform
  2009-03-23 15:34 [patch 1/6] spi: s6000 spi host driver Daniel Glöckner
@ 2009-03-23 15:34 ` Daniel Glöckner
  2009-03-23 15:34 ` [patch 3/6] xtensa: add spi mmc " Daniel Glöckner
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Daniel Glöckner @ 2009-03-23 15:34 UTC (permalink / raw)
  To: Chris Zankel, David Brownell
  Cc: spi-devel-general, linux-kernel, Daniel Glöckner

Signed-off-by: Daniel Glöckner <dg@emlix.com>
---
 arch/xtensa/platforms/s6105/device.c |   48 ++++++++++++++++++++++++++++++++++
 arch/xtensa/platforms/s6105/setup.c  |    5 +++-
 2 files changed, 52 insertions(+), 1 deletions(-)

diff --git a/arch/xtensa/platforms/s6105/device.c b/arch/xtensa/platforms/s6105/device.c
index 9394e6f..a7ea916 100644
--- a/arch/xtensa/platforms/s6105/device.c
+++ b/arch/xtensa/platforms/s6105/device.c
@@ -14,6 +14,8 @@
 #include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_s6000.h>
 
 #include <variant/hardware.h>
 #include <variant/dmac.h>
@@ -24,6 +26,7 @@
 #define UART_INTNUM		4
 #define GMAC_INTNUM		5
 #define I2C_INTNUM		6
+#define SPI_INTNUM		11
 
 static const signed char gpio3_irq_mappings[] = {
 	S6_INTC_GPIO(3),
@@ -49,11 +52,17 @@ static const signed char i2c_irq_mappings[] = {
 	-1
 };
 
+static const signed char spi_irq_mappings[] = {
+	S6_INTC_SPI,
+	-1
+};
+
 const signed char *platform_irq_mappings[NR_IRQS] = {
 	[GPIO3_INTNUM] = gpio3_irq_mappings,
 	[UART_INTNUM] = uart_irq_mappings,
 	[GMAC_INTNUM] = gmac_irq_mappings,
 	[I2C_INTNUM] = i2c_irq_mappings,
+	[SPI_INTNUM] = spi_irq_mappings,
 };
 
 static struct plat_serial8250_port serial_platform_data[] = {
@@ -173,6 +182,36 @@ static struct i2c_board_info __initdata s6_i2c_devices[] = {
 	},
 };
 
+static struct resource s6_spi_resource[] = {
+	{
+		.name   = "mem",
+		.start  = (resource_size_t)S6_REG_SPI,
+		.end    = (resource_size_t)S6_REG_SPI + 0x1000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "irq",
+		.start  = (resource_size_t)SPI_INTNUM,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+#define S6_SPI_BUS_NUM	0
+
+static __devinitdata struct s6_spi_platform_data s6_spi_pdata = {
+	.bus_num     = S6_SPI_BUS_NUM,
+	.cs_polarity = 0x00,
+	.clock       = "PCLK",
+};
+
+#define S6_SPI_CS_BOOT_FLASH	0
+#define S6_SPI_CS_BACK_PANEL	1
+#define S6_SPI_CS_EXPANSION	3
+#define S6_SPI_CS_MMC_SLOT	4
+
+static struct spi_board_info __initdata s6_spi_devices[] = {
+};
+
 static struct platform_device platform_devices[] = {
 	{
 		.name = "serial8250",
@@ -195,6 +234,14 @@ static struct platform_device platform_devices[] = {
 			.platform_data = &s6_i2c_pdata,
 		},
 	},
+	{
+		.name = "spi_s6000",
+		.resource = s6_spi_resource,
+		.num_resources = ARRAY_SIZE(s6_spi_resource),
+		.dev = {
+			.platform_data = &s6_spi_pdata,
+		},
+	},
 };
 
 static int __init device_init(void)
@@ -203,6 +250,7 @@ static int __init device_init(void)
 
 	i2c_register_board_info(S6_I2C_BUS_NUM, s6_i2c_devices,
 				ARRAY_SIZE(s6_i2c_devices));
+	spi_register_board_info(s6_spi_devices, ARRAY_SIZE(s6_spi_devices));
 	s6_gmac_resource[5].start = prepare_phy_irq(GPIO_PHY_IRQ);
 
 	for (i = 0; i < ARRAY_SIZE(platform_devices); i++)
diff --git a/arch/xtensa/platforms/s6105/setup.c b/arch/xtensa/platforms/s6105/setup.c
index e64db1c..5ffa148 100644
--- a/arch/xtensa/platforms/s6105/setup.c
+++ b/arch/xtensa/platforms/s6105/setup.c
@@ -58,7 +58,10 @@ void __init platform_setup(char **cmdline)
 
 void __init platform_init(bp_tag_t *first)
 {
-	s6_setup_gpio(0);
+	s6_setup_gpio(1 << GPIO_SPI_CS0 |
+			1 << GPIO_SPI_CS1 |
+			1 << GPIO_SPI_CS3 |
+			1 << GPIO_SPI_CS4);
 	gpio_request(GPIO_LED1_NGREEN, "led1_green");
 	gpio_request(GPIO_LED1_RED, "led1_red");
 	gpio_direction_output(GPIO_LED1_NGREEN, 1);
-- 
1.6.2.107.ge47ee

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

* [patch 3/6] xtensa: add spi mmc host to s6105 platform
  2009-03-23 15:34 [patch 1/6] spi: s6000 spi host driver Daniel Glöckner
  2009-03-23 15:34 ` [patch 2/6] xtensa: add s6000 spi host to s6105 platform Daniel Glöckner
@ 2009-03-23 15:34 ` Daniel Glöckner
  2009-03-24 20:09   ` David Brownell
  2009-03-23 15:34 ` [patch 4/6] xtensa: add m25p80 " Daniel Glöckner
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Daniel Glöckner @ 2009-03-23 15:34 UTC (permalink / raw)
  To: Chris Zankel, David Brownell
  Cc: spi-devel-general, linux-kernel, Daniel Glöckner

Signed-off-by: Daniel Glöckner <dg@emlix.com>
---
 arch/xtensa/platforms/s6105/device.c |   55 ++++++++++++++++++++++++++++++++++
 1 files changed, 55 insertions(+), 0 deletions(-)

diff --git a/arch/xtensa/platforms/s6105/device.c b/arch/xtensa/platforms/s6105/device.c
index a7ea916..789448e 100644
--- a/arch/xtensa/platforms/s6105/device.c
+++ b/arch/xtensa/platforms/s6105/device.c
@@ -11,9 +11,11 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/phy.h>
+#include <linux/mmc/host.h>
 #include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
+#include <linux/spi/mmc_spi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_s6000.h>
 
@@ -209,7 +211,60 @@ static __devinitdata struct s6_spi_platform_data s6_spi_pdata = {
 #define S6_SPI_CS_EXPANSION	3
 #define S6_SPI_CS_MMC_SLOT	4
 
+static int __devinit s6_init_mmc_host(struct device *spi,
+				      irqreturn_t (*handler)(int, void *),
+				      void *mmc)
+{
+	int ret;
+	ret = gpio_request(GPIO_SD_WP, "mmc_wp");
+	if (ret < 0)
+		return ret;
+	ret = gpio_request(GPIO_SD_IRQ, "mmc_irq");
+	if (ret < 0)
+		return ret;
+	ret = gpio_direction_input(GPIO_SD_WP);
+	if (ret < 0)
+		return ret;
+	ret = gpio_direction_input(GPIO_SD_IRQ);
+	if (ret < 0)
+		return ret;
+	ret = gpio_to_irq(GPIO_SD_IRQ);
+	if (ret < 0)
+		return ret;
+	ret = request_irq(ret, handler,
+			  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			  "mmc_slot", mmc);
+	return ret;
+}
+
+static void __devexit s6_exit_mmc_host(struct device *spi, void *mmc)
+{
+	free_irq(gpio_to_irq(GPIO_SD_IRQ), mmc);
+	gpio_free(GPIO_SD_IRQ);
+	gpio_free(GPIO_SD_WP);
+}
+
+static int s6_mmc_get_ro(struct device *spi)
+{
+	return gpio_get_value(GPIO_SD_WP);
+}
+
+static struct mmc_spi_platform_data s6_spi_mmc_pdata = {
+	.caps = 0,
+	.ocr_mask = MMC_VDD_32_33,
+	.init = s6_init_mmc_host,
+	.exit = __devexit_p(s6_exit_mmc_host),
+	.get_ro = s6_mmc_get_ro,
+};
+
 static struct spi_board_info __initdata s6_spi_devices[] = {
+	{
+		.modalias = "mmc_spi",
+		.platform_data = &s6_spi_mmc_pdata,
+		.bus_num = S6_SPI_BUS_NUM,
+		.chip_select = S6_SPI_CS_MMC_SLOT,
+		.max_speed_hz = 50000000,
+	},
 };
 
 static struct platform_device platform_devices[] = {
-- 
1.6.2.107.ge47ee

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

* [patch 4/6] xtensa: add m25p80 to s6105 platform
  2009-03-23 15:34 [patch 1/6] spi: s6000 spi host driver Daniel Glöckner
  2009-03-23 15:34 ` [patch 2/6] xtensa: add s6000 spi host to s6105 platform Daniel Glöckner
  2009-03-23 15:34 ` [patch 3/6] xtensa: add spi mmc " Daniel Glöckner
@ 2009-03-23 15:34 ` Daniel Glöckner
  2009-03-23 15:34 ` [patch 5/6] xtensa: enable s6000 spi host in s6105_defconfig Daniel Glöckner
  2009-03-23 15:34 ` [patch 6/6] xtensa: enable spi mmc " Daniel Glöckner
  4 siblings, 0 replies; 9+ messages in thread
From: Daniel Glöckner @ 2009-03-23 15:34 UTC (permalink / raw)
  To: Chris Zankel, David Brownell
  Cc: spi-devel-general, linux-kernel, Daniel Glöckner

The spi_board_info is enclosed in #ifdef CONFIG_MTD_M25P80 to not
interfere with the mmc_spi driver if not used. When mmc_spi is fixed
to work on a shared bus, this #ifdef can be removed.

The stage2 partition contains the kernels for all processors in the
device. In our case a Linux kernel for the SCP core and maybe a
non-Linux kernel for the AUX core. The size of the stage2 partition
is not hardcoded in the bootloader. It depends on the first few bytes
of that partition. Remaining space up to the boot config can be used
for other purposes (f.ex. a filesystem).

The boot configuration is expected at address 0xfff800. The flash chip
ignores the upper two address bits. Rounding down to sectors then
yields an offset of 0x3f0000 for that partition.

Signed-off-by: Daniel Glöckner <dg@emlix.com>
---
 arch/xtensa/platforms/s6105/device.c |   47 ++++++++++++++++++++++++++++++++++
 1 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/arch/xtensa/platforms/s6105/device.c b/arch/xtensa/platforms/s6105/device.c
index 789448e..bc254ac 100644
--- a/arch/xtensa/platforms/s6105/device.c
+++ b/arch/xtensa/platforms/s6105/device.c
@@ -12,9 +12,12 @@
 #include <linux/irq.h>
 #include <linux/phy.h>
 #include <linux/mmc/host.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
 #include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
+#include <linux/spi/flash.h>
 #include <linux/spi/mmc_spi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_s6000.h>
@@ -211,6 +214,36 @@ static __devinitdata struct s6_spi_platform_data s6_spi_pdata = {
 #define S6_SPI_CS_EXPANSION	3
 #define S6_SPI_CS_MMC_SLOT	4
 
+static struct mtd_partition s6_spi_flash_partitions[] = {
+	{
+		.name = "bootloader",
+		.size = 0x10000,
+		.offset = 0,
+	},
+	{
+		.name = "stage2",
+		.size = 0x360000,
+		.offset = 0x10000,
+	},
+	{
+		.name = "filesystem",
+		.size = 0x90000,
+		.offset = 0x370000,
+	},
+	{ /* actually 0x800 bytes at 0xfff800 */
+		.name = "bootconfig",
+		.size = 0x10000,
+		.offset = 0x3f0000,
+	}
+};
+
+static struct flash_platform_data s6_spi_flash_pdata = {
+	.name = "m25p80",
+	.parts = s6_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(s6_spi_flash_partitions),
+	.type = "m25p32",
+};
+
 static int __devinit s6_init_mmc_host(struct device *spi,
 				      irqreturn_t (*handler)(int, void *),
 				      void *mmc)
@@ -258,6 +291,20 @@ static struct mmc_spi_platform_data s6_spi_mmc_pdata = {
 };
 
 static struct spi_board_info __initdata s6_spi_devices[] = {
+#ifdef CONFIG_MTD_M25P80
+	{
+		.modalias = "m25p80",
+		.platform_data = &s6_spi_flash_pdata,
+		.bus_num = S6_SPI_BUS_NUM,
+		.chip_select = S6_SPI_CS_BOOT_FLASH,
+#ifdef CONFIG_M25PXX_USE_FAST_READ
+		.max_speed_hz = 50000000,
+#else
+		.max_speed_hz = 33000000,
+#endif
+		.mode = SPI_MODE_3
+	},
+#endif
 	{
 		.modalias = "mmc_spi",
 		.platform_data = &s6_spi_mmc_pdata,
-- 
1.6.2.107.ge47ee

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

* [patch 5/6] xtensa: enable s6000 spi host in s6105_defconfig
  2009-03-23 15:34 [patch 1/6] spi: s6000 spi host driver Daniel Glöckner
                   ` (2 preceding siblings ...)
  2009-03-23 15:34 ` [patch 4/6] xtensa: add m25p80 " Daniel Glöckner
@ 2009-03-23 15:34 ` Daniel Glöckner
  2009-03-23 15:37   ` Daniel Glöckner
  2009-03-23 15:34 ` [patch 6/6] xtensa: enable spi mmc " Daniel Glöckner
  4 siblings, 1 reply; 9+ messages in thread
From: Daniel Glöckner @ 2009-03-23 15:34 UTC (permalink / raw)
  To: Chris Zankel, David Brownell
  Cc: spi-devel-general, linux-kernel, Daniel Glöckner

---
 arch/xtensa/configs/s6105_defconfig |   20 +++++++++++++++++++-
 1 files changed, 19 insertions(+), 1 deletions(-)

diff --git a/arch/xtensa/configs/s6105_defconfig b/arch/xtensa/configs/s6105_defconfig
index e398710..02bab6e 100644
--- a/arch/xtensa/configs/s6105_defconfig
+++ b/arch/xtensa/configs/s6105_defconfig
@@ -260,6 +260,7 @@ CONFIG_MISC_DEVICES=y
 # EEPROM support
 #
 CONFIG_EEPROM_AT24=y
+# CONFIG_EEPROM_AT25 is not set
 # CONFIG_EEPROM_LEGACY is not set
 # CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
@@ -409,7 +410,22 @@ CONFIG_I2C_S6000=y
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
-# CONFIG_SPI is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_S6000=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_REQUIRE_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
@@ -433,6 +449,8 @@ CONFIG_GPIOLIB=y
 #
 # SPI GPIO expanders:
 #
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
-- 
1.6.2.107.ge47ee

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

* [patch 6/6] xtensa: enable spi mmc host in s6105_defconfig
  2009-03-23 15:34 [patch 1/6] spi: s6000 spi host driver Daniel Glöckner
                   ` (3 preceding siblings ...)
  2009-03-23 15:34 ` [patch 5/6] xtensa: enable s6000 spi host in s6105_defconfig Daniel Glöckner
@ 2009-03-23 15:34 ` Daniel Glöckner
  4 siblings, 0 replies; 9+ messages in thread
From: Daniel Glöckner @ 2009-03-23 15:34 UTC (permalink / raw)
  To: Chris Zankel, David Brownell
  Cc: spi-devel-general, linux-kernel, Daniel Glöckner

Signed-off-by: Daniel Glöckner <dg@emlix.com>
---
 arch/xtensa/configs/s6105_defconfig |   22 +++++++++++++++++++---
 1 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/arch/xtensa/configs/s6105_defconfig b/arch/xtensa/configs/s6105_defconfig
index 02bab6e..c5ea056 100644
--- a/arch/xtensa/configs/s6105_defconfig
+++ b/arch/xtensa/configs/s6105_defconfig
@@ -509,7 +509,23 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_DISPLAY_SUPPORT is not set
 # CONFIG_SOUND is not set
 # CONFIG_USB_SUPPORT is not set
-# CONFIG_MMC is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_SPI=y
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
 # CONFIG_ACCESSIBILITY is not set
@@ -646,9 +662,9 @@ CONFIG_GENERIC_FIND_LAST_BIT=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
-# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC_ITU_T=y
 # CONFIG_CRC32 is not set
-# CONFIG_CRC7 is not set
+CONFIG_CRC7=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
-- 
1.6.2.107.ge47ee

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

* Re: [patch 5/6] xtensa: enable s6000 spi host in s6105_defconfig
  2009-03-23 15:34 ` [patch 5/6] xtensa: enable s6000 spi host in s6105_defconfig Daniel Glöckner
@ 2009-03-23 15:37   ` Daniel Glöckner
  0 siblings, 0 replies; 9+ messages in thread
From: Daniel Glöckner @ 2009-03-23 15:37 UTC (permalink / raw)
  To: Chris Zankel, David Brownell; +Cc: spi-devel-general, linux-kernel

"

On 03/23/2009 04:34 PM, Daniel Glöckner wrote:
> ---
>  arch/xtensa/configs/s6105_defconfig |   20 +++++++++++++++++++-
>  1 files changed, 19 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/xtensa/configs/s6105_defconfig b/arch/xtensa/configs/s6105_defconfig
> index e398710..02bab6e 100644

Signed-off-by: Daniel Glöckner <dg@emlix.com>


-- 
Dipl.-Math. Daniel Glöckner, emlix GmbH, http://www.emlix.com
Fon +49 551 30664-0, Fax -11, Bahnhofsallee 1b, 37081 Göttingen, Germany
Geschäftsführung: Dr. Uwe Kracke, Dr. Cord Seele, Ust-IdNr.: DE 205 198 055
Sitz der Gesellschaft: Göttingen, Amtsgericht Göttingen HR B 3160

emlix - your embedded linux partner

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

* Re: [patch 3/6] xtensa: add spi mmc host to s6105 platform
  2009-03-23 15:34 ` [patch 3/6] xtensa: add spi mmc " Daniel Glöckner
@ 2009-03-24 20:09   ` David Brownell
  2009-04-02 10:31     ` Daniel Glöckner
  0 siblings, 1 reply; 9+ messages in thread
From: David Brownell @ 2009-03-24 20:09 UTC (permalink / raw)
  To: Daniel Glöckner; +Cc: Chris Zankel, spi-devel-general, linux-kernel

On Monday 23 March 2009, Daniel Glöckner wrote:
> Signed-off-by: Daniel Glöckner <dg@emlix.com>

Looks OK to me.  FWIW I don't expect to ack arch patches
that just use public interfaces...


> ---
>  arch/xtensa/platforms/s6105/device.c |   55 ++++++++++++++++++++++++++++++++++
>  1 files changed, 55 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/xtensa/platforms/s6105/device.c b/arch/xtensa/platforms/s6105/device.c
> index a7ea916..789448e 100644
> --- a/arch/xtensa/platforms/s6105/device.c
> +++ b/arch/xtensa/platforms/s6105/device.c
> @@ -11,9 +11,11 @@
>  #include <linux/init.h>
>  #include <linux/irq.h>
>  #include <linux/phy.h>
> +#include <linux/mmc/host.h>
>  #include <linux/platform_device.h>
>  #include <linux/serial.h>
>  #include <linux/serial_8250.h>
> +#include <linux/spi/mmc_spi.h>
>  #include <linux/spi/spi.h>
>  #include <linux/spi/spi_s6000.h>
>  
> @@ -209,7 +211,60 @@ static __devinitdata struct s6_spi_platform_data s6_spi_pdata = {
>  #define S6_SPI_CS_EXPANSION	3
>  #define S6_SPI_CS_MMC_SLOT	4
>  
> +static int __devinit s6_init_mmc_host(struct device *spi,
> +				      irqreturn_t (*handler)(int, void *),
> +				      void *mmc)
> +{
> +	int ret;
> +	ret = gpio_request(GPIO_SD_WP, "mmc_wp");
> +	if (ret < 0)
> +		return ret;
> +	ret = gpio_request(GPIO_SD_IRQ, "mmc_irq");
> +	if (ret < 0)
> +		return ret;
> +	ret = gpio_direction_input(GPIO_SD_WP);
> +	if (ret < 0)
> +		return ret;
> +	ret = gpio_direction_input(GPIO_SD_IRQ);
> +	if (ret < 0)
> +		return ret;
> +	ret = gpio_to_irq(GPIO_SD_IRQ);
> +	if (ret < 0)
> +		return ret;
> +	ret = request_irq(ret, handler,
> +			  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
> +			  "mmc_slot", mmc);
> +	return ret;
> +}
> +
> +static void __devexit s6_exit_mmc_host(struct device *spi, void *mmc)
> +{
> +	free_irq(gpio_to_irq(GPIO_SD_IRQ), mmc);
> +	gpio_free(GPIO_SD_IRQ);
> +	gpio_free(GPIO_SD_WP);
> +}
> +
> +static int s6_mmc_get_ro(struct device *spi)
> +{
> +	return gpio_get_value(GPIO_SD_WP);
> +}
> +
> +static struct mmc_spi_platform_data s6_spi_mmc_pdata = {
> +	.caps = 0,
> +	.ocr_mask = MMC_VDD_32_33,
> +	.init = s6_init_mmc_host,
> +	.exit = __devexit_p(s6_exit_mmc_host),
> +	.get_ro = s6_mmc_get_ro,
> +};
> +
>  static struct spi_board_info __initdata s6_spi_devices[] = {
> +	{
> +		.modalias = "mmc_spi",
> +		.platform_data = &s6_spi_mmc_pdata,
> +		.bus_num = S6_SPI_BUS_NUM,
> +		.chip_select = S6_SPI_CS_MMC_SLOT,
> +		.max_speed_hz = 50000000,
> +	},
>  };
>  
>  static struct platform_device platform_devices[] = {
> -- 
> 1.6.2.107.ge47ee
> 
> 

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

* Re: [patch 3/6] xtensa: add spi mmc host to s6105 platform
  2009-03-24 20:09   ` David Brownell
@ 2009-04-02 10:31     ` Daniel Glöckner
  0 siblings, 0 replies; 9+ messages in thread
From: Daniel Glöckner @ 2009-04-02 10:31 UTC (permalink / raw)
  To: David Brownell
  Cc: Chris Zankel, spi-devel-general, linux-kernel, Johannes Weiner

On 03/24/2009 09:09 PM, David Brownell wrote:
> Looks OK to me.  FWIW I don't expect to ack arch patches
> that just use public interfaces...

Then what do you think of patch 1/6 aka "spi: s6000 spi host driver"?

  Daniel

-- 
Dipl.-Math. Daniel Glöckner, emlix GmbH, http://www.emlix.com
Fon +49 551 30664-0, Fax -11, Bahnhofsallee 1b, 37081 Göttingen, Germany
Geschäftsführung: Dr. Uwe Kracke, Dr. Cord Seele, Ust-IdNr.: DE 205 198 055
Sitz der Gesellschaft: Göttingen, Amtsgericht Göttingen HR B 3160

emlix - your embedded linux partner

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

end of thread, other threads:[~2009-04-02 10:31 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-03-23 15:34 [patch 1/6] spi: s6000 spi host driver Daniel Glöckner
2009-03-23 15:34 ` [patch 2/6] xtensa: add s6000 spi host to s6105 platform Daniel Glöckner
2009-03-23 15:34 ` [patch 3/6] xtensa: add spi mmc " Daniel Glöckner
2009-03-24 20:09   ` David Brownell
2009-04-02 10:31     ` Daniel Glöckner
2009-03-23 15:34 ` [patch 4/6] xtensa: add m25p80 " Daniel Glöckner
2009-03-23 15:34 ` [patch 5/6] xtensa: enable s6000 spi host in s6105_defconfig Daniel Glöckner
2009-03-23 15:37   ` Daniel Glöckner
2009-03-23 15:34 ` [patch 6/6] xtensa: enable spi mmc " Daniel Glöckner

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).