linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] Add spi100k driver and arch support
@ 2009-12-07  4:48 Cory Maccarrone
  2009-12-07  4:48 ` [PATCH 1/3] [SPI] [OMAP] Add OMAP spi100k driver Cory Maccarrone
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Cory Maccarrone @ 2009-12-07  4:48 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-omap-u79uwXL29TY76Z2rM5mHXA

This patch set implements the spi100k driver we use in the linwizard
and wing-linux projects.  This SPI driver is used for many omap7xx
devices, particularly omap850 HTC smartphones.

The first patch is directed at the SPI subsystem mailing list primarily
for review.  The other two are directed primarily at linux-omap for
review.  All three are sent to both to preserve complete context for
all to see.

Cory Maccarrone (3):
  [SPI] [OMAP] Add OMAP spi100k driver
  [OMAP] Add spi100k configuration to OMAP1
  [OMAP] Add OMAP 7xx pin muxes for SPI

 arch/arm/mach-omap1/clock.c               |    4 +
 arch/arm/mach-omap1/devices.c             |   70 ++++
 arch/arm/mach-omap1/mux.c                 |    8 +
 arch/arm/plat-omap/include/plat/mux.h     |    8 +
 arch/arm/plat-omap/include/plat/omap7xx.h |    3 +
 arch/arm/plat-omap/include/plat/spi100k.h |   15 +
 drivers/spi/Kconfig                       |    6 +
 drivers/spi/Makefile                      |    1 +
 drivers/spi/omap_spi_100k.c               |  642 +++++++++++++++++++++++++++++
 9 files changed, 757 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-omap/include/plat/spi100k.h
 create mode 100644 drivers/spi/omap_spi_100k.c


------------------------------------------------------------------------------
Join us December 9, 2009 for the Red Hat Virtual Experience,
a free event focused on virtualization and cloud computing. 
Attend in-depth sessions from your desk. Your couch. Anywhere.
http://p.sf.net/sfu/redhat-sfdev2dev

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

* [PATCH 1/3] [SPI] [OMAP] Add OMAP spi100k driver
  2009-12-07  4:48 [PATCH 0/3] Add spi100k driver and arch support Cory Maccarrone
@ 2009-12-07  4:48 ` Cory Maccarrone
       [not found]   ` <1260161299-17656-2-git-send-email-darkstar6262-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2009-12-07 18:08   ` Tony Lindgren
  2009-12-07  4:48 ` [PATCH 2/3] [OMAP] Add spi100k configuration to OMAP1 Cory Maccarrone
  2009-12-07  4:48 ` [PATCH 3/3] [OMAP] Add OMAP 7xx pin muxes for SPI Cory Maccarrone
  2 siblings, 2 replies; 8+ messages in thread
From: Cory Maccarrone @ 2009-12-07  4:48 UTC (permalink / raw)
  To: spi-devel-general, linux-omap; +Cc: Cory Maccarrone

This change adds the OMAP SPI 100k driver created by
Fabrice Crohas <fcrohas@gmail.com>.  This SPI bus is found on
OMAP7xx-series smartphones, and for many, the touchscreen is
attached to this bus.

The lion's share of the work was done by Fabrice on this driver --
I am merely porting it from the Linwizard project on his behalf.

Signed-off-by: Cory Maccarrone <darkstar6262@gmail.com>
---
 drivers/spi/Kconfig         |    6 +
 drivers/spi/Makefile        |    1 +
 drivers/spi/omap_spi_100k.c |  642 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 649 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/omap_spi_100k.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 4b6f7cb..7ef9b12 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -164,6 +164,12 @@ config SPI_OMAP24XX
 	  SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI
 	  (McSPI) modules.
 
+config SPI_OMAP_100K
+	tristate "OMAP SPI 100K"
+	depends on SPI_MASTER && (ARCH_OMAP850 || ARCH_OMAP730)
+	help
+	  OMAP SPI 100K master controller for omap7xx boards.
+
 config SPI_ORION
 	tristate "Orion SPI master (EXPERIMENTAL)"
 	depends on PLAT_ORION && EXPERIMENTAL
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 21a1182..55f670d 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_SPI_LM70_LLP)		+= spi_lm70llp.o
 obj-$(CONFIG_SPI_PXA2XX)		+= pxa2xx_spi.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)		+= omap_uwire.o
 obj-$(CONFIG_SPI_OMAP24XX)		+= omap2_mcspi.o
+obj-$(CONFIG_SPI_OMAP_100K)		+= omap_spi_100k.o
 obj-$(CONFIG_SPI_ORION)			+= orion_spi.o
 obj-$(CONFIG_SPI_PL022)			+= amba-pl022.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
diff --git a/drivers/spi/omap_spi_100k.c b/drivers/spi/omap_spi_100k.c
new file mode 100644
index 0000000..d0ebfa8
--- /dev/null
+++ b/drivers/spi/omap_spi_100k.c
@@ -0,0 +1,642 @@
+/*
+ * OMAP7xx SPI 100k controller driver
+ * Author: Fabrice Crohas <fcrohas@gmail.com>
+ * from original omap1_mcspi driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ * Author:      Samuel Ortiz <samuel.ortiz@nokia.com> and
+ *              Juha Yrj�l� <juha.yrjola@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <linux/spi/spi.h>
+
+#include <plat/clock.h>
+
+#define OMAP1_SPI100K_MAX_FREQ          48000000
+
+#define ICR_SPITAS      (OMAP7XX_ICR_BASE + 0x12)
+
+#define SPI_SETUP1      0x00
+#define SPI_SETUP2      0x02
+#define SPI_CTRL        0x04
+#define SPI_STATUS      0x06
+#define SPI_TX_LSB      0x08
+#define SPI_TX_MSB      0x0a
+#define SPI_RX_LSB      0x0c
+#define SPI_RX_MSB      0x0e
+
+#define SPI_SETUP1_INT_READ_ENABLE      (1UL << 5)
+#define SPI_SETUP1_INT_WRITE_ENABLE     (1UL << 4)
+#define SPI_SETUP1_CLOCK_DIVISOR(x)     ((x) << 1)
+#define SPI_SETUP1_CLOCK_ENABLE         (1UL << 0)
+
+#define SPI_SETUP2_ACTIVE_EDGE_FALLING  (0UL << 0)
+#define SPI_SETUP2_ACTIVE_EDGE_RISING   (1UL << 0)
+#define SPI_SETUP2_NEGATIVE_LEVEL       (0UL << 5)
+#define SPI_SETUP2_POSITIVE_LEVEL       (1UL << 5)
+#define SPI_SETUP2_LEVEL_TRIGGER        (0UL << 10)
+#define SPI_SETUP2_EDGE_TRIGGER         (1UL << 10)
+
+#define SPI_CTRL_SEN(x)                 ((x) << 7)
+#define SPI_CTRL_WORD_SIZE(x)           (((x) - 1) << 2)
+#define SPI_CTRL_WR                     (1UL << 1)
+#define SPI_CTRL_RD                     (1UL << 0)
+
+#define SPI_STATUS_WE                   (1UL << 1)
+#define SPI_STATUS_RD                   (1UL << 0)
+
+#define WRITE 0
+#define READ  1
+
+
+/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
+ * cache operations; better heuristics consider wordsize and bitrate.
+ */
+#define DMA_MIN_BYTES                   8
+
+struct omap1_spi100k {
+	struct work_struct      work;
+	/* lock protects queue and registers */
+	spinlock_t              lock;
+	struct list_head        msg_queue;
+	struct spi_master       *master;
+	struct clk              *ick;
+	struct clk              *fck;
+	/* Virtual base address of the controller */
+	void __iomem            *base;
+	unsigned long           base_addr;
+};
+
+struct omap1_spi100k_cs {
+	void __iomem            *base;
+	int                     word_len;
+};
+
+static struct workqueue_struct *omap1_spi100k_wq;
+
+#define MOD_REG_BIT(val, mask, set) do { \
+	if (set) \
+		val |= mask; \
+	else \
+		val &= ~mask; \
+} while (0)
+
+static void spi100k_enable_clock(struct spi_master *master)
+{
+	unsigned int val;
+	struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+	/* enable SPI */
+	val = omap_readw(spi100k->base_addr + SPI_SETUP1);
+	val |= SPI_SETUP1_CLOCK_ENABLE;
+	omap_writew(val, spi100k->base_addr + SPI_SETUP1);
+}
+
+static void spi100k_disable_clock(struct spi_master *master)
+{
+	unsigned int val;
+	struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+	/* disable SPI */
+	val = omap_readw(spi100k->base_addr + SPI_SETUP1);
+	val &= ~SPI_SETUP1_CLOCK_ENABLE;
+	omap_writew(val, spi100k->base_addr + SPI_SETUP1);
+}
+
+static void spi100k_write_data(struct spi_master *master, int len, int data)
+{
+	struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+	/* write 16-bit word */
+	spi100k_enable_clock(master);
+	omap_writew( data , spi100k->base_addr + SPI_TX_MSB);
+
+	omap_writew(SPI_CTRL_SEN(0) |
+		    SPI_CTRL_WORD_SIZE(len) |
+		    SPI_CTRL_WR,
+		    spi100k->base_addr + SPI_CTRL);
+
+	/* Wait for bit ack send change */
+	while((omap_readw(spi100k->base_addr + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE);
+	udelay(1000);
+
+	spi100k_disable_clock(master);
+}
+
+static int spi100k_read_data(struct spi_master *master, int len)
+{
+	int dataH,dataL;
+	struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+	spi100k_enable_clock(master);
+	omap_writew(SPI_CTRL_SEN(0) |
+		    SPI_CTRL_WORD_SIZE(len) |
+		    SPI_CTRL_RD,
+		    spi100k->base_addr + SPI_CTRL);
+
+	while((omap_readw(spi100k->base_addr + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD);
+	udelay(1000);
+
+	dataL = omap_readw(spi100k->base_addr + SPI_RX_LSB);
+	dataH = omap_readw(spi100k->base_addr + SPI_RX_MSB);
+	spi100k_disable_clock(master);
+
+	return dataL;
+}
+
+static void spi100k_open(struct spi_master *master)
+{
+	/* get control of SPI */
+	struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+	omap_writew(SPI_SETUP1_INT_READ_ENABLE |
+		    SPI_SETUP1_INT_WRITE_ENABLE |
+		    SPI_SETUP1_CLOCK_DIVISOR(0), spi100k->base_addr + SPI_SETUP1);
+
+	/* configure clock and interrupts */
+	omap_writew(SPI_SETUP2_ACTIVE_EDGE_FALLING |
+		    SPI_SETUP2_NEGATIVE_LEVEL |
+		    SPI_SETUP2_LEVEL_TRIGGER, spi100k->base_addr + SPI_SETUP2);
+
+}
+
+static void spi100k_close(struct spi_master *master)
+{
+}
+
+static void omap1_spi100k_force_cs(struct omap1_spi100k *spi100k, int enable)
+{
+	if (enable)
+		omap_writew(0x05fc, spi100k->base_addr + SPI_CTRL);
+	else
+		omap_writew(0x05fd, spi100k->base_addr + SPI_CTRL);
+}
+
+static void omap1_spi100k_set_enable(struct omap1_spi100k *spi100k, int enable)
+{
+}
+
+static unsigned
+omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
+{
+	struct omap1_spi100k    *spi100k;
+	struct omap1_spi100k_cs *cs = spi->controller_state;
+	unsigned int            count, c;
+	int                     word_len;
+
+	spi100k = spi_master_get_devdata(spi->master);
+	count = xfer->len;
+	c = count;
+	word_len = cs->word_len;
+
+	/* RX_ONLY mode needs dummy data in TX reg */
+	if (xfer->tx_buf == NULL)
+		spi100k_write_data(spi->master,word_len, 0);
+
+	if (word_len <= 8) {
+		u8              *rx;
+		const u8        *tx;
+
+		rx = xfer->rx_buf;
+		tx = xfer->tx_buf;
+		do {
+			c-=1;
+			if (xfer->tx_buf != NULL)
+				spi100k_write_data(spi->master,word_len, *tx);
+			if (xfer->rx_buf != NULL)
+				*rx = spi100k_read_data(spi->master,word_len);
+		} while(c);
+	} else if (word_len <= 16) {
+		u16             *rx;
+		const u16       *tx;
+
+		rx = xfer->rx_buf;
+		tx = xfer->tx_buf;
+		do {
+			c-=2;
+			if (xfer->tx_buf != NULL)
+				spi100k_write_data(spi->master,word_len, *tx++);
+			if (xfer->rx_buf != NULL)
+				*rx++ = spi100k_read_data(spi->master,word_len);
+		} while(c);
+	} else if (word_len <= 32) {
+		u32             *rx;
+		const u32       *tx;
+
+		rx = xfer->rx_buf;
+		tx = xfer->tx_buf;
+		do {
+			c-=4;
+			if (xfer->tx_buf != NULL)
+				spi100k_write_data(spi->master,word_len, *tx);
+			if (xfer->rx_buf != NULL)
+				*rx = spi100k_read_data(spi->master,word_len);
+		} while(c);
+	}
+	return count - c;
+}
+
+/* called only when no transfer is active to this device */
+static int omap1_spi100k_setup_transfer(struct spi_device *spi,
+		struct spi_transfer *t)
+{
+	struct omap1_spi100k *spi100k = spi_master_get_devdata(spi->master);
+	struct omap1_spi100k_cs *cs = spi->controller_state;
+	u8 word_len = spi->bits_per_word;
+
+	if (t != NULL && t->bits_per_word)
+		word_len = t->bits_per_word;
+	if (!word_len)
+		word_len = 8;
+
+	if (spi->bits_per_word > 32)
+		return -EINVAL;
+	cs->word_len = word_len;
+
+	/* SPI init before transfer */
+	omap_writew(0x3e , spi100k->base_addr + SPI_SETUP1);
+	omap_writew(0x00 , spi100k->base_addr + SPI_STATUS);
+	omap_writew(0x3e , spi100k->base_addr + SPI_CTRL);
+
+	return 0;
+}
+
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+
+static int omap1_spi100k_setup(struct spi_device *spi)
+{
+	int                     ret;
+	struct omap1_spi100k    *spi100k;
+	struct omap1_spi100k_cs *cs = spi->controller_state;
+
+	if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
+		 dev_dbg(&spi->dev, "setup: unsupported %d bit words\n",
+			spi->bits_per_word);
+		 return -EINVAL;
+	}
+
+	spi100k = spi_master_get_devdata(spi->master);
+
+	if (!cs) {
+		cs = kzalloc(sizeof *cs, GFP_KERNEL);
+		if (!cs)
+			return -ENOMEM;
+		cs->base = spi100k->base + spi->chip_select * 0x14;
+		spi->controller_state = cs;
+	}
+
+	spi100k_open(spi->master);
+
+	clk_enable(spi100k->ick);
+	clk_enable(spi100k->fck);
+
+	ret = omap1_spi100k_setup_transfer(spi, NULL);
+
+	clk_disable(spi100k->ick);
+	clk_disable(spi100k->fck);
+
+	return ret;
+}
+
+static void omap1_spi100k_cleanup(struct spi_device *spi)
+{
+	spi100k_close(spi->master);
+}
+
+static void omap1_spi100k_work(struct work_struct *work)
+{
+	struct omap1_spi100k    *spi100k;
+	int status = 0;
+
+	spi100k = container_of(work, struct omap1_spi100k, work);
+	spin_lock_irq(&spi100k->lock);
+
+	clk_enable(spi100k->ick);
+	clk_enable(spi100k->fck);
+
+	/* We only enable one channel at a time -- the one whose message is
+	 * at the head of the queue -- although this controller would gladly
+	 * arbitrate among multiple channels.  This corresponds to "single
+	 * channel" master mode.  As a side effect, we need to manage the
+	 * chipselect with the FORCE bit ... CS != channel enable.
+	 */
+	 while (!list_empty(&spi100k->msg_queue)) {
+		struct spi_message              *m;
+		struct spi_device               *spi;
+		struct spi_transfer             *t = NULL;
+		int                             cs_active = 0;
+		struct omap1_spi100k_cs         *cs;
+		int                             par_override = 0;
+
+		m = container_of(spi100k->msg_queue.next, struct spi_message,
+				 queue);
+
+		list_del_init(&m->queue);
+		spin_unlock_irq(&spi100k->lock);
+
+		spi = m->spi;
+		cs = spi->controller_state;
+
+		omap1_spi100k_set_enable(spi100k, 1);
+		list_for_each_entry(t, &m->transfers, transfer_list) {
+			if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+				status = -EINVAL;
+				break;
+			}
+			if (par_override || t->speed_hz || t->bits_per_word) {
+				par_override = 1;
+				status = omap1_spi100k_setup_transfer(spi, t);
+				if (status < 0)
+					break;
+				if (!t->speed_hz && !t->bits_per_word)
+					par_override = 0;
+			}
+
+			if (!cs_active) {
+				omap1_spi100k_force_cs(spi100k, 1);
+				cs_active = 1;
+			}
+
+			if (t->len) {
+				unsigned count;
+
+				/* RX_ONLY mode needs dummy data in TX reg */
+				if (t->tx_buf == NULL)
+					spi100k_write_data(spi->master, 8, 0);
+
+				count = omap1_spi100k_txrx_pio(spi, t);
+				m->actual_length += count;
+
+				if (count != t->len) {
+					status = -EIO;
+					break;
+				}
+			}
+
+			if (t->delay_usecs)
+				udelay(t->delay_usecs);
+
+			/* ignore the "leave it on after last xfer" hint */
+
+			if (t->cs_change) {
+				omap1_spi100k_force_cs(spi100k, 0);
+				cs_active = 0;
+			}
+		}
+
+		/* Restore defaults if they were overriden */
+		if (par_override) {
+			par_override = 0;
+			status = omap1_spi100k_setup_transfer(spi, NULL);
+		}
+
+		if (cs_active)
+			omap1_spi100k_force_cs(spi100k, 0);
+
+		omap1_spi100k_set_enable(spi100k, 0);
+
+		m->status = status;
+		m->complete(m->context);
+
+		spin_lock_irq(&spi100k->lock);
+	}
+
+	clk_disable(spi100k->ick);
+	clk_disable(spi100k->fck);
+	spin_unlock_irq(&spi100k->lock);
+
+	if (status < 0) {
+		printk(KERN_WARNING "spi transfer failed with %d\n", status);
+	}
+}
+
+static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m)
+{
+	struct omap1_spi100k    *spi100k;
+	unsigned long           flags;
+	struct spi_transfer     *t;
+
+	m->actual_length = 0;
+	m->status = 0;
+
+	/* reject invalid messages and transfers */
+	if (list_empty(&m->transfers) || !m->complete)
+		return -EINVAL;
+
+	list_for_each_entry(t, &m->transfers, transfer_list) {
+		const void      *tx_buf = t->tx_buf;
+		void            *rx_buf = t->rx_buf;
+		unsigned        len = t->len;
+
+		if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ
+				|| (len && !(rx_buf || tx_buf))
+				|| (t->bits_per_word &&
+					(  t->bits_per_word < 4
+					|| t->bits_per_word > 32))) {
+			dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
+					t->speed_hz,
+					len,
+					tx_buf ? "tx" : "",
+					rx_buf ? "rx" : "",
+					t->bits_per_word);
+			return -EINVAL;
+		}
+
+		if (t->speed_hz && t->speed_hz < OMAP1_SPI100K_MAX_FREQ/(1<<16)) {
+			dev_dbg(&spi->dev, "%d Hz max exceeds %d\n",
+					t->speed_hz,
+					OMAP1_SPI100K_MAX_FREQ/(1<<16));
+			return -EINVAL;
+		}
+
+	}
+
+	spi100k = spi_master_get_devdata(spi->master);
+
+	spin_lock_irqsave(&spi100k->lock, flags);
+	list_add_tail(&m->queue, &spi100k->msg_queue);
+	queue_work(omap1_spi100k_wq, &spi100k->work);
+	spin_unlock_irqrestore(&spi100k->lock, flags);
+
+	return 0;
+}
+
+static int __init omap1_spi100k_reset(struct omap1_spi100k *spi100k)
+{
+	return 0;
+}
+
+static int __devinit omap1_spi100k_probe(struct platform_device *pdev)
+{
+	struct spi_master       *master;
+	struct omap1_spi100k    *spi100k;
+	struct resource         *r;
+	int                     status = 0;
+
+	if ( !pdev->id)
+		return -EINVAL;
+
+	master = spi_alloc_master(&pdev->dev, sizeof *spi100k);
+	if (master == NULL) {
+		dev_dbg(&pdev->dev, "master allocation failed\n");
+		return -ENOMEM;
+	}
+
+	if (pdev->id != -1)
+	       master->bus_num = pdev->id;
+
+	master->setup = omap1_spi100k_setup;
+	master->transfer = omap1_spi100k_transfer;
+	master->cleanup = omap1_spi100k_cleanup;
+	master->num_chipselect =2;
+	master->mode_bits = MODEBITS;
+
+	dev_set_drvdata(&pdev->dev, master);
+
+	spi100k = spi_master_get_devdata(master);
+	spi100k->master = master;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		 status = -ENODEV;
+		 goto err1;
+	}
+	if (!request_mem_region(r->start, (r->end - r->start) + 1,
+			pdev->name)) {
+	       status = -EBUSY;
+	       goto err1;
+	}
+
+	spi100k->base = (void __iomem *) OMAP2_L3_IO_ADDRESS(r->start);
+	spi100k->base_addr = (unsigned long)r->start;
+	INIT_WORK(&spi100k->work, omap1_spi100k_work);
+
+	spin_lock_init(&spi100k->lock);
+	INIT_LIST_HEAD(&spi100k->msg_queue);
+	spi100k->ick = clk_get(&pdev->dev, "ick");
+	if (IS_ERR(spi100k->ick)) {
+		dev_dbg(&pdev->dev, "can't get spi100k_ick\n");
+		status = PTR_ERR(spi100k->ick);
+		goto err1a;
+	}
+
+	spi100k->fck = clk_get(&pdev->dev, "fck");
+	if (IS_ERR(spi100k->fck)) {
+		dev_dbg(&pdev->dev, "can't get spi100k_fck\n");
+		status = PTR_ERR(spi100k->fck);
+		goto err2;
+	}
+
+	if (omap1_spi100k_reset(spi100k) < 0)
+		goto err3;
+
+	status = spi_register_master(master);
+	if (status < 0)
+		goto err3;
+
+	printk(KERN_INFO "spi Registered\n");
+	return status;
+
+err3:
+	clk_put(spi100k->fck);
+err2:
+	clk_put(spi100k->ick);
+err1a:
+	release_mem_region(r->start, (r->end - r->start) + 1);
+err1:
+	spi_master_put(master);
+	printk(KERN_INFO "Error: spi\n");
+	return status;
+}
+
+static int __exit omap1_spi100k_remove(struct platform_device *pdev)
+{
+	struct spi_master       *master;
+	struct omap1_spi100k    *spi100k;
+	struct resource         *r;
+
+	master = dev_get_drvdata(&pdev->dev);
+	spi100k = spi_master_get_devdata(master);
+
+	clk_put(spi100k->fck);
+	clk_put(spi100k->ick);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(r->start, (r->end - r->start) + 1);
+
+	spi_unregister_master(master);
+
+	return 0;
+}
+
+static struct platform_driver omap1_spi100k_driver = {
+	.driver = {
+		.name		= "omap1_spi100k",
+		.owner		= THIS_MODULE,
+	},
+	.probe		= omap1_spi100k_probe,
+	.remove		= __exit_p(omap1_spi100k_remove),
+};
+
+
+static int __init omap1_spi100k_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "In spi init\n");
+	omap1_spi100k_wq = create_singlethread_workqueue(
+			omap1_spi100k_driver.driver.name);
+
+	if (omap1_spi100k_wq == NULL) {
+		printk(KERN_INFO "Error: spi init\n");
+		return -1;
+	}
+
+	ret = platform_driver_register(&omap1_spi100k_driver);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void __exit omap1_spi100k_exit(void)
+{
+	platform_driver_unregister(&omap1_spi100k_driver);
+
+	destroy_workqueue(omap1_spi100k_wq);
+}
+
+module_init(omap1_spi100k_init);
+module_exit(omap1_spi100k_exit);
+
+MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver");
+MODULE_AUTHOR("Fabrice Crohas <fcrohas@gmail.com>");
+MODULE_LICENSE("GPL");
+
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 2/3] [OMAP] Add spi100k configuration to OMAP1
  2009-12-07  4:48 [PATCH 0/3] Add spi100k driver and arch support Cory Maccarrone
  2009-12-07  4:48 ` [PATCH 1/3] [SPI] [OMAP] Add OMAP spi100k driver Cory Maccarrone
@ 2009-12-07  4:48 ` Cory Maccarrone
  2009-12-07 18:14   ` Tony Lindgren
  2009-12-07  4:48 ` [PATCH 3/3] [OMAP] Add OMAP 7xx pin muxes for SPI Cory Maccarrone
  2 siblings, 1 reply; 8+ messages in thread
From: Cory Maccarrone @ 2009-12-07  4:48 UTC (permalink / raw)
  To: spi-devel-general, linux-omap; +Cc: Cory Maccarrone

This change implements the clocks, platform driver, and register
information necessary to use the spi100k bus with OMAP 7xx systems.

The clocks added are dummy clocks because, although we're pretty
sure there are clocks used for SPI, all current booting methods result
in proper operation without the enabling of any other clocks.

Signed-off-by: Cory Maccarrone <darkstar6262@gmail.com>
---
 arch/arm/mach-omap1/clock.c               |    4 ++
 arch/arm/mach-omap1/devices.c             |   70 +++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/omap7xx.h |    3 +
 arch/arm/plat-omap/include/plat/spi100k.h |   15 ++++++
 4 files changed, 92 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-omap/include/plat/spi100k.h

diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
index dc8ca91..e584c0f 100644
--- a/arch/arm/mach-omap1/clock.c
+++ b/arch/arm/mach-omap1/clock.c
@@ -135,6 +135,10 @@ static struct omap_clk omap_clks[] = {
 	CLK("i2c_omap.1", "fck",	&i2c_fck,	CK_16XX | CK_1510 | CK_310 | CK_7XX),
 	CLK("i2c_omap.1", "ick",	&i2c_ick,	CK_16XX),
 	CLK("i2c_omap.1", "ick",	&dummy_ck,	CK_1510 | CK_310 | CK_7XX),
+	CLK("omap1_spi100k.1", "fck",	&dummy_ck,	CK_7XX),
+	CLK("omap1_spi100k.1", "ick",	&dummy_ck,	CK_7XX),
+	CLK("omap1_spi100k.2", "fck",	&dummy_ck,	CK_7XX),
+	CLK("omap1_spi100k.2", "ick",	&dummy_ck,	CK_7XX),
 	CLK("omap_uwire", "fck",	&armxor_ck.clk,	CK_16XX | CK_1510 | CK_310),
 	CLK("omap-mcbsp.1", "ick",	&dspper_ck,	CK_16XX),
 	CLK("omap-mcbsp.1", "ick",	&dummy_ck,	CK_1510 | CK_310),
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index 23ded2d..9f1c1cc 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -24,6 +24,12 @@
 #include <mach/gpio.h>
 #include <plat/mmc.h>
 
+#if defined(CONFIG_SPI_OMAP_100K)
+#include <plat/omap7xx.h>
+#include <plat/spi100k.h>
+#include <linux/spi/spi.h>
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 #if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
@@ -196,6 +202,69 @@ void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
 
 /*-------------------------------------------------------------------------*/
 
+/* OMAP7xx SPI support */
+#if defined(CONFIG_SPI_OMAP_100K)
+
+#include <plat/omap7xx.h>
+#include <plat/spi100k.h>
+#include <linux/spi/spi.h>
+
+static struct omap_spi100k_platform_config omap_spi1_config = {
+        .num_cs         = 2,
+};
+
+static struct resource omap_spi1_resources[] = {
+	{
+		.start          = OMAP7XX_SPI1_BASE,
+		.end            = OMAP7XX_SPI1_BASE + 0x7ff,
+		.flags          = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device omap_spi1 = {
+        .name           = "omap1_spi100k",
+        .id             = 1,
+        .num_resources  = ARRAY_SIZE(omap_spi1_resources),
+        .resource       = omap_spi1_resources,
+        .dev            = {
+                .platform_data = &omap_spi1_config,
+        },
+};
+
+static struct omap_spi100k_platform_config omap_spi2_config = {
+        .num_cs         = 2,
+};
+
+static struct resource omap_spi2_resources[] = {
+        {
+                .start          = OMAP7XX_SPI2_BASE,
+                .end            = OMAP7XX_SPI2_BASE + 0x7ff,
+                .flags          = IORESOURCE_MEM,
+        },
+};
+
+struct platform_device omap_spi2 = {
+        .name           = "omap1_spi100k",
+        .id             = 2,
+        .num_resources  = ARRAY_SIZE(omap_spi2_resources),
+        .resource       = omap_spi2_resources,
+        .dev            = {
+	        .platform_data = &omap_spi2_config,
+	},
+};
+
+static void omap_init_spi100k(void)
+{
+        platform_device_register(&omap_spi1);
+        platform_device_register(&omap_spi2);
+}
+
+#else
+static inline void omap_init_spi100k(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
 #if defined(CONFIG_OMAP_STI)
 
 #define OMAP1_STI_BASE		0xfffea000
@@ -263,6 +332,7 @@ static int __init omap1_init_devices(void)
 
 	omap_init_mbox();
 	omap_init_rtc();
+	omap_init_spi100k();
 	omap_init_sti();
 
 	return 0;
diff --git a/arch/arm/plat-omap/include/plat/omap7xx.h b/arch/arm/plat-omap/include/plat/omap7xx.h
index 53f5241..48e4757 100644
--- a/arch/arm/plat-omap/include/plat/omap7xx.h
+++ b/arch/arm/plat-omap/include/plat/omap7xx.h
@@ -46,6 +46,9 @@
 #define OMAP7XX_DSPREG_SIZE	SZ_128K
 #define OMAP7XX_DSPREG_START	0xE1000000
 
+#define OMAP7XX_SPI1_BASE	0xfffc0800
+#define OMAP7XX_SPI2_BASE	0xfffc1000
+
 /*
  * ----------------------------------------------------------------------------
  * OMAP7XX specific configuration registers
diff --git a/arch/arm/plat-omap/include/plat/spi100k.h b/arch/arm/plat-omap/include/plat/spi100k.h
new file mode 100644
index 0000000..a4e877f
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/spi100k.h
@@ -0,0 +1,15 @@
+#ifndef _SPI100K_H
+#define _SPI100K_H
+
+struct omap_spi100k_platform_config {
+	unsigned short	num_cs;
+};
+
+struct omap_spi100k_device_config {
+	unsigned turbo_mode:1;
+
+	/* Do we want one channel enabled at the same time? */
+	unsigned single_channel:1;
+};
+#endif /* _SPI100K_H */
+
-- 
1.6.3.3


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

* [PATCH 3/3] [OMAP] Add OMAP 7xx pin muxes for SPI
  2009-12-07  4:48 [PATCH 0/3] Add spi100k driver and arch support Cory Maccarrone
  2009-12-07  4:48 ` [PATCH 1/3] [SPI] [OMAP] Add OMAP spi100k driver Cory Maccarrone
  2009-12-07  4:48 ` [PATCH 2/3] [OMAP] Add spi100k configuration to OMAP1 Cory Maccarrone
@ 2009-12-07  4:48 ` Cory Maccarrone
  2 siblings, 0 replies; 8+ messages in thread
From: Cory Maccarrone @ 2009-12-07  4:48 UTC (permalink / raw)
  To: spi-devel-general, linux-omap; +Cc: Cory Maccarrone

This change adds pin mux configuration for SPI100k on
omap7xx platforms.

Signed-off-by: Cory Maccarrone <darkstar6262@gmail.com>
---
 arch/arm/mach-omap1/mux.c             |    8 ++++++++
 arch/arm/plat-omap/include/plat/mux.h |    8 ++++++++
 2 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c
index 07212cc..8434137 100644
--- a/arch/arm/mach-omap1/mux.c
+++ b/arch/arm/mach-omap1/mux.c
@@ -62,6 +62,14 @@ MUX_CFG_7XX("MMC_7XX_DAT0",        2,   17,    0,   16,   1, 0)
 /* I2C interface */
 MUX_CFG_7XX("I2C_7XX_SCL",         5,    1,    0,    0,   1, 0)
 MUX_CFG_7XX("I2C_7XX_SDA",         5,    5,    0,    0,   1, 0)
+
+/* SPI pins */
+MUX_CFG_7XX("SPI_7XX_1",           6,    5,    4,    4,   1, 0)
+MUX_CFG_7XX("SPI_7XX_2",           6,    9,    4,    8,   1, 0)
+MUX_CFG_7XX("SPI_7XX_3",           6,   13,    4,   12,   1, 0)
+MUX_CFG_7XX("SPI_7XX_4",           6,   17,    4,   16,   1, 0)
+MUX_CFG_7XX("SPI_7XX_5",           8,   25,    0,   24,   0, 0)
+MUX_CFG_7XX("SPI_7XX_6",           9,    5,    0,    4,   0, 0)
 };
 #define OMAP7XX_PINS_SZ		ARRAY_SIZE(omap7xx_pins)
 #else
diff --git a/arch/arm/plat-omap/include/plat/mux.h b/arch/arm/plat-omap/include/plat/mux.h
index 8f069cc..692c90e 100644
--- a/arch/arm/plat-omap/include/plat/mux.h
+++ b/arch/arm/plat-omap/include/plat/mux.h
@@ -183,6 +183,14 @@ enum omap7xx_index {
 	/* I2C */
 	I2C_7XX_SCL,
 	I2C_7XX_SDA,
+
+	/* SPI */
+	SPI_7XX_1,
+	SPI_7XX_2,
+	SPI_7XX_3,
+	SPI_7XX_4,
+	SPI_7XX_5,
+	SPI_7XX_6,
 };
 
 enum omap1xxx_index {
-- 
1.6.3.3


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

* Re: [PATCH 1/3] [SPI] [OMAP] Add OMAP spi100k driver
       [not found]   ` <1260161299-17656-2-git-send-email-darkstar6262-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2009-12-07  5:33     ` jassi brar
  2009-12-07  6:36       ` [spi-devel-general] " Cory Maccarrone
  0 siblings, 1 reply; 8+ messages in thread
From: jassi brar @ 2009-12-07  5:33 UTC (permalink / raw)
  To: Cory Maccarrone
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-omap-u79uwXL29TY76Z2rM5mHXA

On Mon, Dec 7, 2009 at 1:48 PM, Cory Maccarrone <darkstar6262@gmail.com> wrote:
> This change adds the OMAP SPI 100k driver created by
> Fabrice Crohas <fcrohas@gmail.com>.  This SPI bus is found on
> OMAP7xx-series smartphones, and for many, the touchscreen is
> attached to this bus.
>
> The lion's share of the work was done by Fabrice on this driver --
> I am merely porting it from the Linwizard project on his behalf.
>
> Signed-off-by: Cory Maccarrone <darkstar6262@gmail.com>
> ---
>  drivers/spi/Kconfig         |    6 +
>  drivers/spi/Makefile        |    1 +
>  drivers/spi/omap_spi_100k.c |  642 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 649 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/spi/omap_spi_100k.c
>
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 4b6f7cb..7ef9b12 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -164,6 +164,12 @@ config SPI_OMAP24XX
>          SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI
>          (McSPI) modules.
>
> +config SPI_OMAP_100K
> +       tristate "OMAP SPI 100K"
> +       depends on SPI_MASTER && (ARCH_OMAP850 || ARCH_OMAP730)
> +       help
> +         OMAP SPI 100K master controller for omap7xx boards.
> +
>  config SPI_ORION
>        tristate "Orion SPI master (EXPERIMENTAL)"
>        depends on PLAT_ORION && EXPERIMENTAL
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index 21a1182..55f670d 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -22,6 +22,7 @@ obj-$(CONFIG_SPI_LM70_LLP)            += spi_lm70llp.o
>  obj-$(CONFIG_SPI_PXA2XX)               += pxa2xx_spi.o
>  obj-$(CONFIG_SPI_OMAP_UWIRE)           += omap_uwire.o
>  obj-$(CONFIG_SPI_OMAP24XX)             += omap2_mcspi.o
> +obj-$(CONFIG_SPI_OMAP_100K)            += omap_spi_100k.o
>  obj-$(CONFIG_SPI_ORION)                        += orion_spi.o
>  obj-$(CONFIG_SPI_PL022)                        += amba-pl022.o
>  obj-$(CONFIG_SPI_MPC52xx_PSC)          += mpc52xx_psc_spi.o
> diff --git a/drivers/spi/omap_spi_100k.c b/drivers/spi/omap_spi_100k.c
> new file mode 100644
> index 0000000..d0ebfa8
> --- /dev/null
> +++ b/drivers/spi/omap_spi_100k.c
> @@ -0,0 +1,642 @@
> +/*
> + * OMAP7xx SPI 100k controller driver
> + * Author: Fabrice Crohas <fcrohas@gmail.com>
> + * from original omap1_mcspi driver
> + *
> + * Copyright (C) 2005, 2006 Nokia Corporation
> + * Author:      Samuel Ortiz <samuel.ortiz@nokia.com> and
> + *              Juha Yrj�l� <juha.yrjola@nokia.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/platform_device.h>
> +#include <linux/err.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/gpio.h>
> +
> +#include <linux/spi/spi.h>
> +
> +#include <plat/clock.h>
> +
> +#define OMAP1_SPI100K_MAX_FREQ          48000000
> +
> +#define ICR_SPITAS      (OMAP7XX_ICR_BASE + 0x12)
> +
> +#define SPI_SETUP1      0x00
> +#define SPI_SETUP2      0x02
> +#define SPI_CTRL        0x04
> +#define SPI_STATUS      0x06
> +#define SPI_TX_LSB      0x08
> +#define SPI_TX_MSB      0x0a
> +#define SPI_RX_LSB      0x0c
> +#define SPI_RX_MSB      0x0e
> +
> +#define SPI_SETUP1_INT_READ_ENABLE      (1UL << 5)
> +#define SPI_SETUP1_INT_WRITE_ENABLE     (1UL << 4)
> +#define SPI_SETUP1_CLOCK_DIVISOR(x)     ((x) << 1)
> +#define SPI_SETUP1_CLOCK_ENABLE         (1UL << 0)
> +
> +#define SPI_SETUP2_ACTIVE_EDGE_FALLING  (0UL << 0)
> +#define SPI_SETUP2_ACTIVE_EDGE_RISING   (1UL << 0)
> +#define SPI_SETUP2_NEGATIVE_LEVEL       (0UL << 5)
> +#define SPI_SETUP2_POSITIVE_LEVEL       (1UL << 5)
> +#define SPI_SETUP2_LEVEL_TRIGGER        (0UL << 10)
> +#define SPI_SETUP2_EDGE_TRIGGER         (1UL << 10)
> +
> +#define SPI_CTRL_SEN(x)                 ((x) << 7)
> +#define SPI_CTRL_WORD_SIZE(x)           (((x) - 1) << 2)
> +#define SPI_CTRL_WR                     (1UL << 1)
> +#define SPI_CTRL_RD                     (1UL << 0)
> +
> +#define SPI_STATUS_WE                   (1UL << 1)
> +#define SPI_STATUS_RD                   (1UL << 0)
> +
> +#define WRITE 0
> +#define READ  1
> +
> +
> +/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
> + * cache operations; better heuristics consider wordsize and bitrate.
> + */
> +#define DMA_MIN_BYTES                   8
> +
> +struct omap1_spi100k {
> +       struct work_struct      work;
> +       /* lock protects queue and registers */
> +       spinlock_t              lock;
> +       struct list_head        msg_queue;
> +       struct spi_master       *master;
> +       struct clk              *ick;
> +       struct clk              *fck;
> +       /* Virtual base address of the controller */
> +       void __iomem            *base;
> +       unsigned long           base_addr;
> +};
> +
> +struct omap1_spi100k_cs {
> +       void __iomem            *base;
> +       int                     word_len;
> +};
> +
> +static struct workqueue_struct *omap1_spi100k_wq;
> +
> +#define MOD_REG_BIT(val, mask, set) do { \
> +       if (set) \
> +               val |= mask; \
> +       else \
> +               val &= ~mask; \
> +} while (0)
> +
> +static void spi100k_enable_clock(struct spi_master *master)
> +{
> +       unsigned int val;
> +       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
> +
> +       /* enable SPI */
> +       val = omap_readw(spi100k->base_addr + SPI_SETUP1);
> +       val |= SPI_SETUP1_CLOCK_ENABLE;
> +       omap_writew(val, spi100k->base_addr + SPI_SETUP1);
> +}
> +
> +static void spi100k_disable_clock(struct spi_master *master)
> +{
> +       unsigned int val;
> +       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
> +
> +       /* disable SPI */
> +       val = omap_readw(spi100k->base_addr + SPI_SETUP1);
> +       val &= ~SPI_SETUP1_CLOCK_ENABLE;
> +       omap_writew(val, spi100k->base_addr + SPI_SETUP1);
> +}
> +
> +static void spi100k_write_data(struct spi_master *master, int len, int data)
> +{
> +       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
> +
> +       /* write 16-bit word */
> +       spi100k_enable_clock(master);
> +       omap_writew( data , spi100k->base_addr + SPI_TX_MSB);
> +
> +       omap_writew(SPI_CTRL_SEN(0) |
> +                   SPI_CTRL_WORD_SIZE(len) |
> +                   SPI_CTRL_WR,
> +                   spi100k->base_addr + SPI_CTRL);
> +
> +       /* Wait for bit ack send change */
> +       while((omap_readw(spi100k->base_addr + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE);
> +       udelay(1000);
> +
> +       spi100k_disable_clock(master);
> +}
> +
> +static int spi100k_read_data(struct spi_master *master, int len)
> +{
> +       int dataH,dataL;
> +       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
> +
> +       spi100k_enable_clock(master);
> +       omap_writew(SPI_CTRL_SEN(0) |
> +                   SPI_CTRL_WORD_SIZE(len) |
> +                   SPI_CTRL_RD,
> +                   spi100k->base_addr + SPI_CTRL);
> +
> +       while((omap_readw(spi100k->base_addr + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD);
> +       udelay(1000);
> +
> +       dataL = omap_readw(spi100k->base_addr + SPI_RX_LSB);
> +       dataH = omap_readw(spi100k->base_addr + SPI_RX_MSB);
> +       spi100k_disable_clock(master);
> +
> +       return dataL;
> +}
> +
> +static void spi100k_open(struct spi_master *master)
> +{
> +       /* get control of SPI */
> +       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
> +
> +       omap_writew(SPI_SETUP1_INT_READ_ENABLE |
> +                   SPI_SETUP1_INT_WRITE_ENABLE |
> +                   SPI_SETUP1_CLOCK_DIVISOR(0), spi100k->base_addr + SPI_SETUP1);
> +
> +       /* configure clock and interrupts */
> +       omap_writew(SPI_SETUP2_ACTIVE_EDGE_FALLING |
> +                   SPI_SETUP2_NEGATIVE_LEVEL |
> +                   SPI_SETUP2_LEVEL_TRIGGER, spi100k->base_addr + SPI_SETUP2);
> +
> +}
> +
> +static void spi100k_close(struct spi_master *master)
> +{
> +}
setting master->cleanup = NULL shud do

> +static void omap1_spi100k_force_cs(struct omap1_spi100k *spi100k, int enable)
> +{
> +       if (enable)
> +               omap_writew(0x05fc, spi100k->base_addr + SPI_CTRL);
> +       else
> +               omap_writew(0x05fd, spi100k->base_addr + SPI_CTRL);
> +}
> +
> +static void omap1_spi100k_set_enable(struct omap1_spi100k *spi100k, int enable)
> +{
> +}
how about dropping it altogether?

> +static unsigned
> +omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
> +{
> +       struct omap1_spi100k    *spi100k;
> +       struct omap1_spi100k_cs *cs = spi->controller_state;
> +       unsigned int            count, c;
> +       int                     word_len;
> +
> +       spi100k = spi_master_get_devdata(spi->master);
> +       count = xfer->len;
> +       c = count;
> +       word_len = cs->word_len;
> +
> +       /* RX_ONLY mode needs dummy data in TX reg */
> +       if (xfer->tx_buf == NULL)
> +               spi100k_write_data(spi->master,word_len, 0);
> +
> +       if (word_len <= 8) {
> +               u8              *rx;
> +               const u8        *tx;
> +
> +               rx = xfer->rx_buf;
> +               tx = xfer->tx_buf;
> +               do {
> +                       c-=1;
> +                       if (xfer->tx_buf != NULL)
> +                               spi100k_write_data(spi->master,word_len, *tx);
> +                       if (xfer->rx_buf != NULL)
> +                               *rx = spi100k_read_data(spi->master,word_len);
> +               } while(c);
> +       } else if (word_len <= 16) {
> +               u16             *rx;
> +               const u16       *tx;
> +
> +               rx = xfer->rx_buf;
> +               tx = xfer->tx_buf;
> +               do {
> +                       c-=2;
> +                       if (xfer->tx_buf != NULL)
> +                               spi100k_write_data(spi->master,word_len, *tx++);
> +                       if (xfer->rx_buf != NULL)
> +                               *rx++ = spi100k_read_data(spi->master,word_len);
> +               } while(c);
> +       } else if (word_len <= 32) {
> +               u32             *rx;
> +               const u32       *tx;
> +
> +               rx = xfer->rx_buf;
> +               tx = xfer->tx_buf;
> +               do {
> +                       c-=4;
> +                       if (xfer->tx_buf != NULL)
> +                               spi100k_write_data(spi->master,word_len, *tx);
> +                       if (xfer->rx_buf != NULL)
> +                               *rx = spi100k_read_data(spi->master,word_len);
> +               } while(c);
> +       }
> +       return count - c;
> +}
> +
> +/* called only when no transfer is active to this device */
> +static int omap1_spi100k_setup_transfer(struct spi_device *spi,
> +               struct spi_transfer *t)
> +{
> +       struct omap1_spi100k *spi100k = spi_master_get_devdata(spi->master);
> +       struct omap1_spi100k_cs *cs = spi->controller_state;
> +       u8 word_len = spi->bits_per_word;
> +
> +       if (t != NULL && t->bits_per_word)
> +               word_len = t->bits_per_word;
> +       if (!word_len)
> +               word_len = 8;
> +
> +       if (spi->bits_per_word > 32)
> +               return -EINVAL;
> +       cs->word_len = word_len;
> +
> +       /* SPI init before transfer */
> +       omap_writew(0x3e , spi100k->base_addr + SPI_SETUP1);
> +       omap_writew(0x00 , spi100k->base_addr + SPI_STATUS);
> +       omap_writew(0x3e , spi100k->base_addr + SPI_CTRL);
> +
> +       return 0;
> +}
> +
> +/* the spi->mode bits understood by this driver: */
> +#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
> +
> +static int omap1_spi100k_setup(struct spi_device *spi)
> +{
> +       int                     ret;
> +       struct omap1_spi100k    *spi100k;
> +       struct omap1_spi100k_cs *cs = spi->controller_state;
> +
> +       if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
> +                dev_dbg(&spi->dev, "setup: unsupported %d bit words\n",
> +                       spi->bits_per_word);
> +                return -EINVAL;
> +       }
> +
> +       spi100k = spi_master_get_devdata(spi->master);
> +
> +       if (!cs) {
> +               cs = kzalloc(sizeof *cs, GFP_KERNEL);
> +               if (!cs)
> +                       return -ENOMEM;
> +               cs->base = spi100k->base + spi->chip_select * 0x14;
> +               spi->controller_state = cs;
> +       }
> +
> +       spi100k_open(spi->master);
> +
> +       clk_enable(spi100k->ick);
> +       clk_enable(spi100k->fck);
> +
> +       ret = omap1_spi100k_setup_transfer(spi, NULL);
> +
> +       clk_disable(spi100k->ick);
> +       clk_disable(spi100k->fck);
> +
> +       return ret;
> +}
> +
> +static void omap1_spi100k_cleanup(struct spi_device *spi)
> +{
> +       spi100k_close(spi->master);
> +}
no need for cleanup callback if u have nothing to do in _close.

> +static void omap1_spi100k_work(struct work_struct *work)
> +{
> +       struct omap1_spi100k    *spi100k;
> +       int status = 0;
> +
> +       spi100k = container_of(work, struct omap1_spi100k, work);
> +       spin_lock_irq(&spi100k->lock);
> +
> +       clk_enable(spi100k->ick);
> +       clk_enable(spi100k->fck);
> +
> +       /* We only enable one channel at a time -- the one whose message is
> +        * at the head of the queue -- although this controller would gladly
> +        * arbitrate among multiple channels.  This corresponds to "single
> +        * channel" master mode.  As a side effect, we need to manage the
> +        * chipselect with the FORCE bit ... CS != channel enable.
> +        */
> +        while (!list_empty(&spi100k->msg_queue)) {
> +               struct spi_message              *m;
> +               struct spi_device               *spi;
> +               struct spi_transfer             *t = NULL;
> +               int                             cs_active = 0;
> +               struct omap1_spi100k_cs         *cs;
> +               int                             par_override = 0;
> +
> +               m = container_of(spi100k->msg_queue.next, struct spi_message,
> +                                queue);
> +
> +               list_del_init(&m->queue);
> +               spin_unlock_irq(&spi100k->lock);
> +
> +               spi = m->spi;
> +               cs = spi->controller_state;
> +
> +               omap1_spi100k_set_enable(spi100k, 1);
> +               list_for_each_entry(t, &m->transfers, transfer_list) {
> +                       if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
> +                               status = -EINVAL;
> +                               break;
> +                       }
> +                       if (par_override || t->speed_hz || t->bits_per_word) {
> +                               par_override = 1;
> +                               status = omap1_spi100k_setup_transfer(spi, t);
> +                               if (status < 0)
> +                                       break;
> +                               if (!t->speed_hz && !t->bits_per_word)
> +                                       par_override = 0;
> +                       }
> +
> +                       if (!cs_active) {
> +                               omap1_spi100k_force_cs(spi100k, 1);
> +                               cs_active = 1;
> +                       }
> +
> +                       if (t->len) {
> +                               unsigned count;
> +
> +                               /* RX_ONLY mode needs dummy data in TX reg */
> +                               if (t->tx_buf == NULL)
> +                                       spi100k_write_data(spi->master, 8, 0);
> +
> +                               count = omap1_spi100k_txrx_pio(spi, t);
> +                               m->actual_length += count;
> +
> +                               if (count != t->len) {
> +                                       status = -EIO;
> +                                       break;
> +                               }
> +                       }
> +
> +                       if (t->delay_usecs)
> +                               udelay(t->delay_usecs);
> +
> +                       /* ignore the "leave it on after last xfer" hint */
> +
> +                       if (t->cs_change) {
> +                               omap1_spi100k_force_cs(spi100k, 0);
> +                               cs_active = 0;
> +                       }
> +               }
> +
> +               /* Restore defaults if they were overriden */
> +               if (par_override) {
> +                       par_override = 0;
> +                       status = omap1_spi100k_setup_transfer(spi, NULL);
> +               }
> +
> +               if (cs_active)
> +                       omap1_spi100k_force_cs(spi100k, 0);
> +
> +               omap1_spi100k_set_enable(spi100k, 0);
> +
> +               m->status = status;
> +               m->complete(m->context);
> +
> +               spin_lock_irq(&spi100k->lock);
> +       }
> +
> +       clk_disable(spi100k->ick);
> +       clk_disable(spi100k->fck);
> +       spin_unlock_irq(&spi100k->lock);
> +
> +       if (status < 0) {
> +               printk(KERN_WARNING "spi transfer failed with %d\n", status);
> +       }
no need of {}
> +}
> +
> +static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m)
> +{
> +       struct omap1_spi100k    *spi100k;
> +       unsigned long           flags;
> +       struct spi_transfer     *t;
> +
> +       m->actual_length = 0;
> +       m->status = 0;
 the status shud default to -EINPROGRESS, not success.

> +       /* reject invalid messages and transfers */
> +       if (list_empty(&m->transfers) || !m->complete)
> +               return -EINVAL;
> +
> +       list_for_each_entry(t, &m->transfers, transfer_list) {
> +               const void      *tx_buf = t->tx_buf;
> +               void            *rx_buf = t->rx_buf;
> +               unsigned        len = t->len;
> +
> +               if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ
> +                               || (len && !(rx_buf || tx_buf))
> +                               || (t->bits_per_word &&
> +                                       (  t->bits_per_word < 4
> +                                       || t->bits_per_word > 32))) {
> +                       dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
> +                                       t->speed_hz,
> +                                       len,
> +                                       tx_buf ? "tx" : "",
> +                                       rx_buf ? "rx" : "",
> +                                       t->bits_per_word);
> +                       return -EINVAL;
> +               }
> +
> +               if (t->speed_hz && t->speed_hz < OMAP1_SPI100K_MAX_FREQ/(1<<16)) {
> +                       dev_dbg(&spi->dev, "%d Hz max exceeds %d\n",
> +                                       t->speed_hz,
> +                                       OMAP1_SPI100K_MAX_FREQ/(1<<16));
> +                       return -EINVAL;
> +               }
> +
> +       }
> +
> +       spi100k = spi_master_get_devdata(spi->master);
> +
> +       spin_lock_irqsave(&spi100k->lock, flags);
> +       list_add_tail(&m->queue, &spi100k->msg_queue);
> +       queue_work(omap1_spi100k_wq, &spi100k->work);
> +       spin_unlock_irqrestore(&spi100k->lock, flags);
> +
> +       return 0;
> +}
> +
> +static int __init omap1_spi100k_reset(struct omap1_spi100k *spi100k)
> +{
> +       return 0;
> +}
> +
> +static int __devinit omap1_spi100k_probe(struct platform_device *pdev)
> +{
> +       struct spi_master       *master;
> +       struct omap1_spi100k    *spi100k;
> +       struct resource         *r;
> +       int                     status = 0;
> +
> +       if ( !pdev->id)
> +               return -EINVAL;
> +
> +       master = spi_alloc_master(&pdev->dev, sizeof *spi100k);
> +       if (master == NULL) {
> +               dev_dbg(&pdev->dev, "master allocation failed\n");
> +               return -ENOMEM;
> +       }
> +
> +       if (pdev->id != -1)
> +              master->bus_num = pdev->id;
> +
> +       master->setup = omap1_spi100k_setup;
> +       master->transfer = omap1_spi100k_transfer;
> +       master->cleanup = omap1_spi100k_cleanup;
> +       master->num_chipselect =2;
> +       master->mode_bits = MODEBITS;
> +
> +       dev_set_drvdata(&pdev->dev, master);
> +
> +       spi100k = spi_master_get_devdata(master);
> +       spi100k->master = master;
> +
> +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (r == NULL) {
> +                status = -ENODEV;
> +                goto err1;
> +       }
> +       if (!request_mem_region(r->start, (r->end - r->start) + 1,
> +                       pdev->name)) {
> +              status = -EBUSY;
> +              goto err1;
> +       }
> +
> +       spi100k->base = (void __iomem *) OMAP2_L3_IO_ADDRESS(r->start);
> +       spi100k->base_addr = (unsigned long)r->start;
> +       INIT_WORK(&spi100k->work, omap1_spi100k_work);
> +
> +       spin_lock_init(&spi100k->lock);
> +       INIT_LIST_HEAD(&spi100k->msg_queue);
> +       spi100k->ick = clk_get(&pdev->dev, "ick");
> +       if (IS_ERR(spi100k->ick)) {
> +               dev_dbg(&pdev->dev, "can't get spi100k_ick\n");
> +               status = PTR_ERR(spi100k->ick);
> +               goto err1a;
> +       }
> +
> +       spi100k->fck = clk_get(&pdev->dev, "fck");
> +       if (IS_ERR(spi100k->fck)) {
> +               dev_dbg(&pdev->dev, "can't get spi100k_fck\n");
> +               status = PTR_ERR(spi100k->fck);
> +               goto err2;
> +       }
> +
> +       if (omap1_spi100k_reset(spi100k) < 0)
> +               goto err3;
> +
> +       status = spi_register_master(master);
> +       if (status < 0)
> +               goto err3;
> +
> +       printk(KERN_INFO "spi Registered\n");
> +       return status;
> +
> +err3:
> +       clk_put(spi100k->fck);
> +err2:
> +       clk_put(spi100k->ick);
> +err1a:
> +       release_mem_region(r->start, (r->end - r->start) + 1);
> +err1:
> +       spi_master_put(master);
> +       printk(KERN_INFO "Error: spi\n");
> +       return status;
> +}
> +
> +static int __exit omap1_spi100k_remove(struct platform_device *pdev)
> +{
> +       struct spi_master       *master;
> +       struct omap1_spi100k    *spi100k;
> +       struct resource         *r;
> +
> +       master = dev_get_drvdata(&pdev->dev);
> +       spi100k = spi_master_get_devdata(master);
> +
> +       clk_put(spi100k->fck);
> +       clk_put(spi100k->ick);
> +
> +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       release_mem_region(r->start, (r->end - r->start) + 1);
> +
> +       spi_unregister_master(master);
> +
> +       return 0;
> +}
In remove you might want to wait for mssg queue to be flushed?

> +static struct platform_driver omap1_spi100k_driver = {
> +       .driver = {
> +               .name           = "omap1_spi100k",
> +               .owner          = THIS_MODULE,
> +       },
> +       .probe          = omap1_spi100k_probe,
> +       .remove         = __exit_p(omap1_spi100k_remove),
> +};
> +
> +
> +static int __init omap1_spi100k_init(void)
> +{
> +       int ret;
> +
> +       printk(KERN_INFO "In spi init\n");
> +       omap1_spi100k_wq = create_singlethread_workqueue(
> +                       omap1_spi100k_driver.driver.name);
> +
> +       if (omap1_spi100k_wq == NULL) {
> +               printk(KERN_INFO "Error: spi init\n");
> +               return -1;
> +       }
> +
> +       ret = platform_driver_register(&omap1_spi100k_driver);
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static void __exit omap1_spi100k_exit(void)
> +{
> +       platform_driver_unregister(&omap1_spi100k_driver);
> +
> +       destroy_workqueue(omap1_spi100k_wq);
> +}
> +
> +module_init(omap1_spi100k_init);
> +module_exit(omap1_spi100k_exit);
> +
> +MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver");
> +MODULE_AUTHOR("Fabrice Crohas <fcrohas@gmail.com>");
> +MODULE_LICENSE("GPL");
> +
> --
> 1.6.3.3
>
>
>
> ------------------------------------------------------------------------------
> Join us December 9, 2009 for the Red Hat Virtual Experience,
> a free event focused on virtualization and cloud computing.
> Attend in-depth sessions from your desk. Your couch. Anywhere.
> http://p.sf.net/sfu/redhat-sfdev2dev
> _______________________________________________
> spi-devel-general mailing list
> spi-devel-general@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/spi-devel-general
>
>
------------------------------------------------------------------------------
Join us December 9, 2009 for the Red Hat Virtual Experience,
a free event focused on virtualization and cloud computing. 
Attend in-depth sessions from your desk. Your couch. Anywhere.
http://p.sf.net/sfu/redhat-sfdev2dev
_______________________________________________
spi-devel-general mailing list
spi-devel-general@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

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

* Re: [spi-devel-general] [PATCH 1/3] [SPI] [OMAP] Add OMAP spi100k driver
  2009-12-07  5:33     ` jassi brar
@ 2009-12-07  6:36       ` Cory Maccarrone
  0 siblings, 0 replies; 8+ messages in thread
From: Cory Maccarrone @ 2009-12-07  6:36 UTC (permalink / raw)
  To: jassi brar; +Cc: spi-devel-general, linux-omap

On Sun, Dec 6, 2009 at 9:33 PM, jassi brar <jassisinghbrar@gmail.com> wrote:

> setting master->cleanup = NULL shud do
>
> how about dropping it altogether?
>
> no need for cleanup callback if u have nothing to do in _close.
>
> no need of {}
>
>  the status shud default to -EINPROGRESS, not success.
>
> In remove you might want to wait for mssg queue to be flushed?
>

All good points.  I'll make my corrections and resubmit.

Thanks
- Cory
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 1/3] [SPI] [OMAP] Add OMAP spi100k driver
  2009-12-07  4:48 ` [PATCH 1/3] [SPI] [OMAP] Add OMAP spi100k driver Cory Maccarrone
       [not found]   ` <1260161299-17656-2-git-send-email-darkstar6262-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2009-12-07 18:08   ` Tony Lindgren
  1 sibling, 0 replies; 8+ messages in thread
From: Tony Lindgren @ 2009-12-07 18:08 UTC (permalink / raw)
  To: Cory Maccarrone; +Cc: spi-devel-general, linux-omap

Hi,

* Cory Maccarrone <darkstar6262@gmail.com> [091206 20:48]:
> This change adds the OMAP SPI 100k driver created by
> Fabrice Crohas <fcrohas@gmail.com>.  This SPI bus is found on
> OMAP7xx-series smartphones, and for many, the touchscreen is
> attached to this bus.
> 
> The lion's share of the work was done by Fabrice on this driver --
> I am merely porting it from the Linwizard project on his behalf.
> 
> Signed-off-by: Cory Maccarrone <darkstar6262@gmail.com>
> ---
>  drivers/spi/Kconfig         |    6 +
>  drivers/spi/Makefile        |    1 +
>  drivers/spi/omap_spi_100k.c |  642 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 649 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/spi/omap_spi_100k.c

<snip>

> +static void spi100k_enable_clock(struct spi_master *master)
> +{
> +	unsigned int val;
> +	struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
> +
> +	/* enable SPI */
> +	val = omap_readw(spi100k->base_addr + SPI_SETUP1);
> +	val |= SPI_SETUP1_CLOCK_ENABLE;
> +	omap_writew(val, spi100k->base_addr + SPI_SETUP1);
> +}

Please do not use omap_read/write for the new drivers.

Instead, please use ioremap in the platform init code in
arch/arm/mach-omap1/, and pass the virtual address in
platform_data to the driver. Then you can use readw/writew
in the driver.

We have static mappings in place for ioremap, so there's
no extra overhead.

Regards,

Tony

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

* Re: [PATCH 2/3] [OMAP] Add spi100k configuration to OMAP1
  2009-12-07  4:48 ` [PATCH 2/3] [OMAP] Add spi100k configuration to OMAP1 Cory Maccarrone
@ 2009-12-07 18:14   ` Tony Lindgren
  0 siblings, 0 replies; 8+ messages in thread
From: Tony Lindgren @ 2009-12-07 18:14 UTC (permalink / raw)
  To: Cory Maccarrone; +Cc: spi-devel-general, linux-omap

* Cory Maccarrone <darkstar6262@gmail.com> [091206 20:48]:
> This change implements the clocks, platform driver, and register
> information necessary to use the spi100k bus with OMAP 7xx systems.
> 
> The clocks added are dummy clocks because, although we're pretty
> sure there are clocks used for SPI, all current booting methods result
> in proper operation without the enabling of any other clocks.
> 
> Signed-off-by: Cory Maccarrone <darkstar6262@gmail.com>
> ---
>  arch/arm/mach-omap1/clock.c               |    4 ++
>  arch/arm/mach-omap1/devices.c             |   70 +++++++++++++++++++++++++++++
>  arch/arm/plat-omap/include/plat/omap7xx.h |    3 +
>  arch/arm/plat-omap/include/plat/spi100k.h |   15 ++++++
>  4 files changed, 92 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/plat-omap/include/plat/spi100k.h
> 
> diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
> index dc8ca91..e584c0f 100644
> --- a/arch/arm/mach-omap1/clock.c
> +++ b/arch/arm/mach-omap1/clock.c
> @@ -135,6 +135,10 @@ static struct omap_clk omap_clks[] = {
>  	CLK("i2c_omap.1", "fck",	&i2c_fck,	CK_16XX | CK_1510 | CK_310 | CK_7XX),
>  	CLK("i2c_omap.1", "ick",	&i2c_ick,	CK_16XX),
>  	CLK("i2c_omap.1", "ick",	&dummy_ck,	CK_1510 | CK_310 | CK_7XX),
> +	CLK("omap1_spi100k.1", "fck",	&dummy_ck,	CK_7XX),
> +	CLK("omap1_spi100k.1", "ick",	&dummy_ck,	CK_7XX),
> +	CLK("omap1_spi100k.2", "fck",	&dummy_ck,	CK_7XX),
> +	CLK("omap1_spi100k.2", "ick",	&dummy_ck,	CK_7XX),
>  	CLK("omap_uwire", "fck",	&armxor_ck.clk,	CK_16XX | CK_1510 | CK_310),
>  	CLK("omap-mcbsp.1", "ick",	&dspper_ck,	CK_16XX),
>  	CLK("omap-mcbsp.1", "ick",	&dummy_ck,	CK_1510 | CK_310),
> diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
> index 23ded2d..9f1c1cc 100644
> --- a/arch/arm/mach-omap1/devices.c
> +++ b/arch/arm/mach-omap1/devices.c
> @@ -24,6 +24,12 @@
>  #include <mach/gpio.h>
>  #include <plat/mmc.h>
>  
> +#if defined(CONFIG_SPI_OMAP_100K)
> +#include <plat/omap7xx.h>
> +#include <plat/spi100k.h>
> +#include <linux/spi/spi.h>
> +#endif
> +

Please don't ifdef includes, you should be able to include them even
if the driver is not selected.


>  /*-------------------------------------------------------------------------*/
>  
>  #if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
> @@ -196,6 +202,69 @@ void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
>  
>  /*-------------------------------------------------------------------------*/
>  
> +/* OMAP7xx SPI support */
> +#if defined(CONFIG_SPI_OMAP_100K)
> +
> +#include <plat/omap7xx.h>
> +#include <plat/spi100k.h>
> +#include <linux/spi/spi.h>
> +
> +static struct omap_spi100k_platform_config omap_spi1_config = {
> +        .num_cs         = 2,
> +};
> +
> +static struct resource omap_spi1_resources[] = {
> +	{
> +		.start          = OMAP7XX_SPI1_BASE,
> +		.end            = OMAP7XX_SPI1_BASE + 0x7ff,
> +		.flags          = IORESOURCE_MEM,
> +	},
> +};
> +
> +struct platform_device omap_spi1 = {
> +        .name           = "omap1_spi100k",
> +        .id             = 1,
> +        .num_resources  = ARRAY_SIZE(omap_spi1_resources),
> +        .resource       = omap_spi1_resources,
> +        .dev            = {
> +                .platform_data = &omap_spi1_config,
> +        },
> +};
> +
> +static struct omap_spi100k_platform_config omap_spi2_config = {
> +        .num_cs         = 2,
> +};
> +
> +static struct resource omap_spi2_resources[] = {
> +        {
> +                .start          = OMAP7XX_SPI2_BASE,
> +                .end            = OMAP7XX_SPI2_BASE + 0x7ff,
> +                .flags          = IORESOURCE_MEM,
> +        },
> +};
> +
> +struct platform_device omap_spi2 = {
> +        .name           = "omap1_spi100k",
> +        .id             = 2,
> +        .num_resources  = ARRAY_SIZE(omap_spi2_resources),
> +        .resource       = omap_spi2_resources,
> +        .dev            = {
> +	        .platform_data = &omap_spi2_config,
> +	},
> +};
> +
> +static void omap_init_spi100k(void)
> +{
> +        platform_device_register(&omap_spi1);
> +        platform_device_register(&omap_spi2);
> +}
> +
> +#else
> +static inline void omap_init_spi100k(void) {}
> +#endif

Here you can do the ioremap I mentioned in the comments for
the driver patch.

Regards,

Tony

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

end of thread, other threads:[~2009-12-07 18:14 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-12-07  4:48 [PATCH 0/3] Add spi100k driver and arch support Cory Maccarrone
2009-12-07  4:48 ` [PATCH 1/3] [SPI] [OMAP] Add OMAP spi100k driver Cory Maccarrone
     [not found]   ` <1260161299-17656-2-git-send-email-darkstar6262-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2009-12-07  5:33     ` jassi brar
2009-12-07  6:36       ` [spi-devel-general] " Cory Maccarrone
2009-12-07 18:08   ` Tony Lindgren
2009-12-07  4:48 ` [PATCH 2/3] [OMAP] Add spi100k configuration to OMAP1 Cory Maccarrone
2009-12-07 18:14   ` Tony Lindgren
2009-12-07  4:48 ` [PATCH 3/3] [OMAP] Add OMAP 7xx pin muxes for SPI Cory Maccarrone

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