linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC] generic iMX-spi driver
@ 2009-02-20 14:41 Wolfram Sang
       [not found] ` <20090220144126.GA9203-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  2009-02-23  8:57 ` Paulius Zaleckas
  0 siblings, 2 replies; 13+ messages in thread
From: Wolfram Sang @ 2009-02-20 14:41 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW


[-- Attachment #1.1: Type: text/plain, Size: 49636 bytes --]

Hi,

so, _finally_ here is a first RFC for the generic SPI-driver for all
imx-platforms. So far, it is only tested on a phyCORE-i.MX27. Still, I
can control the audiomixer there. Next week, I will test it on a
phyCORE-i.MX31, too. Please note the following:

- one fat patch for now. I hope I can split it up, later, if needed.

- not yet checkpatch clean, will clean up when all the functionality
  works (mostly 80 char-issues)

- the clock-name for clk_get is hardcoded for now. Will be adapted to
  the reworked clock-framework when available.

- chip-select is not implemented yet, will do this next week. The driver
  currently works on CS0 only.

- DMA is just selectable for MX1 and untested.

- If you can comment on the "XXX"-marked issue, please do

- ATTENTION: The original FSL-driver has a bug regarding the polarity
  CPOL which got flipped. So, if you used the FSL-driver before, then
  the SPI_MODE of your spi_device has to be corrected. Just toggle
  SPI_CPOL or make SPI_MODE_0 out of SPI_MODE_2, SPI_MODE_1 out of
  SPI_MODE_3 or vice versa.

I'd be happy to hear comments, test-reports...

Have a nice weekend,

   Wolfram

not yet for upstream...

Signed-off-by: Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 arch/arm/plat-mxc/include/mach/spi_imx.h |   72 ++++
 drivers/spi/Kconfig                      |   12 +-
 drivers/spi/spi_imx.c                    |  687 +++++++++++++++++-------------
 3 files changed, 465 insertions(+), 306 deletions(-)
 create mode 100644 arch/arm/plat-mxc/include/mach/spi_imx.h

diff --git a/arch/arm/plat-mxc/include/mach/spi_imx.h b/arch/arm/plat-mxc/include/mach/spi_imx.h
new file mode 100644
index 0000000..622dcd7
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/spi_imx.h
@@ -0,0 +1,72 @@
+/*
+ * arch/arm/plat-mxc/include/mach/spi_imx.h
+ *
+ * Copyright (C) 2006 SWAPP
+ *	Andrea Paterniani <a.paterniani-03BXCEkGbFHYGGNLXY5/rw@public.gmane.org>
+ * Copyright (C) 2009 Pengutronix
+ *	Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ *
+ * Initial version inspired by:
+ *	linux-2.6.17-rc3-mm1/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef SPI_IMX_H_
+#define SPI_IMX_H_
+
+/*-------------------------------------------------------------------------*/
+/**
+ * struct spi_imx_master - device.platform_data for SPI controller devices.
+ * @num_chipselect: chipselects are used to distinguish individual
+ *	SPI slaves, and are numbered from zero to num_chipselects - 1.
+ *	each slave has a chipselect signal, but it's common that not
+ *	every chipselect is connected to a slave.
+ * @enable_dma: if true enables DMA driven transfers.
+*/
+struct spi_imx_master {
+	u8 num_chipselect;
+	u8 enable_dma:1;
+	int (*init)(struct platform_device *pdev);
+	int (*exit)(struct platform_device *pdev);
+};
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+/**
+ * struct spi_imx_chip - spi_board_info.controller_data for SPI
+ * slave devices, copied to spi_device.controller_data.
+ * @enable_loopback : used for test purpouse to internally connect RX and TX
+ *	sections.
+ * @enable_dma : enables dma transfer (provided that controller driver has
+ *	dma enabled too).
+ * @ins_ss_pulse : enable /SS pulse insertion between SPI burst.
+ * @bclk_wait : number of bclk waits between each bits_per_word SPI burst.
+ * @cs_control : function pointer to board-specific function to assert/deassert
+ *	I/O port to control HW generation of devices chip-select.
+*/
+struct spi_imx_chip {
+	u8	enable_dma:1;
+	u8	ins_ss_pulse:1;
+	u16	bclk_wait:15;
+	void (*cs_control)(u32 control);
+};
+
+/* Chip-select state */
+#define SPI_CS_ASSERT			(1 << 0)
+#define SPI_CS_DEASSERT			(1 << 1)
+/*-------------------------------------------------------------------------*/
+
+#endif /* SPI_IMX_H_*/
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 83a185d..4262a94 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -117,12 +117,18 @@ config SPI_GPIO
 	  speed with a custom version of this driver; see the source code.
 
 config SPI_IMX
-	tristate "Freescale iMX SPI controller"
-	depends on ARCH_IMX && EXPERIMENTAL
+	tristate "Freescale iMX SPI controllers"
+	depends on (ARCH_IMX || ARCH_MXC) && EXPERIMENTAL
 	help
-	  This enables using the Freescale iMX SPI controller in master
+	  This enables using the Freescale iMX SPI controllers in master
 	  mode.
 
+config SPI_IMX_DMA
+	bool "use DMA for iMX SPI controllers"
+	depends on SPI_IMX && ARCH_IMX
+	help
+	  This enables DMA usage for the Freescale iMX SPI controllers.
+
 config SPI_LM70_LLP
 	tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
 	depends on PARPORT && EXPERIMENTAL
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index 269a55e..5850a21 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 2006 SWAPP
  *	Andrea Paterniani <a.paterniani-03BXCEkGbFHYGGNLXY5/rw@public.gmane.org>
+ * Copyright (C) 2009 Pengutronix
+ *	Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  *
  * Initial version inspired by:
  *	linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c
@@ -30,95 +32,30 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/log2.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/delay.h>
 
 #include <mach/hardware.h>
-#include <mach/imx-dma.h>
 #include <mach/spi_imx.h>
+#ifdef CONFIG_SPI_IMX_DMA
+#  include <mach/imx-dma.h>
+#endif
 
 /*-------------------------------------------------------------------------*/
-/* SPI Registers offsets from peripheral base address */
-#define SPI_RXDATA		(0x00)
-#define SPI_TXDATA		(0x04)
-#define SPI_CONTROL		(0x08)
-#define SPI_INT_STATUS		(0x0C)
-#define SPI_TEST		(0x10)
-#define SPI_PERIOD		(0x14)
-#define SPI_DMA			(0x18)
-#define SPI_RESET		(0x1C)
-
-/* SPI Control Register Bit Fields & Masks */
-#define SPI_CONTROL_BITCOUNT_MASK	(0xF)		/* Bit Count Mask */
-#define SPI_CONTROL_BITCOUNT(n)		(((n) - 1) & SPI_CONTROL_BITCOUNT_MASK)
-#define SPI_CONTROL_POL			(0x1 << 4)      /* Clock Polarity Mask */
-#define SPI_CONTROL_POL_ACT_HIGH	(0x0 << 4)      /* Active high pol. (0=idle) */
-#define SPI_CONTROL_POL_ACT_LOW		(0x1 << 4)      /* Active low pol. (1=idle) */
-#define SPI_CONTROL_PHA			(0x1 << 5)      /* Clock Phase Mask */
-#define SPI_CONTROL_PHA_0		(0x0 << 5)      /* Clock Phase 0 */
-#define SPI_CONTROL_PHA_1		(0x1 << 5)      /* Clock Phase 1 */
-#define SPI_CONTROL_SSCTL		(0x1 << 6)      /* /SS Waveform Select Mask */
-#define SPI_CONTROL_SSCTL_0		(0x0 << 6)      /* Master: /SS stays low between SPI burst
-							   Slave: RXFIFO advanced by BIT_COUNT */
-#define SPI_CONTROL_SSCTL_1		(0x1 << 6)      /* Master: /SS insert pulse between SPI burst
-							   Slave: RXFIFO advanced by /SS rising edge */
-#define SPI_CONTROL_SSPOL		(0x1 << 7)      /* /SS Polarity Select Mask */
-#define SPI_CONTROL_SSPOL_ACT_LOW	(0x0 << 7)      /* /SS Active low */
-#define SPI_CONTROL_SSPOL_ACT_HIGH	(0x1 << 7)      /* /SS Active high */
-#define SPI_CONTROL_XCH			(0x1 << 8)      /* Exchange */
-#define SPI_CONTROL_SPIEN		(0x1 << 9)      /* SPI Module Enable */
-#define SPI_CONTROL_MODE		(0x1 << 10)     /* SPI Mode Select Mask */
-#define SPI_CONTROL_MODE_SLAVE		(0x0 << 10)     /* SPI Mode Slave */
-#define SPI_CONTROL_MODE_MASTER		(0x1 << 10)     /* SPI Mode Master */
-#define SPI_CONTROL_DRCTL		(0x3 << 11)     /* /SPI_RDY Control Mask */
-#define SPI_CONTROL_DRCTL_0		(0x0 << 11)     /* Ignore /SPI_RDY */
-#define SPI_CONTROL_DRCTL_1		(0x1 << 11)     /* /SPI_RDY falling edge triggers input */
-#define SPI_CONTROL_DRCTL_2		(0x2 << 11)     /* /SPI_RDY active low level triggers input */
-#define SPI_CONTROL_DATARATE		(0x7 << 13)     /* Data Rate Mask */
-#define SPI_PERCLK2_DIV_MIN		(0)		/* PERCLK2:4 */
-#define SPI_PERCLK2_DIV_MAX		(7)		/* PERCLK2:512 */
-#define SPI_CONTROL_DATARATE_MIN	(SPI_PERCLK2_DIV_MAX << 13)
-#define SPI_CONTROL_DATARATE_MAX	(SPI_PERCLK2_DIV_MIN << 13)
-#define SPI_CONTROL_DATARATE_BAD	(SPI_CONTROL_DATARATE_MIN + 1)
-
-/* SPI Interrupt/Status Register Bit Fields & Masks */
-#define SPI_STATUS_TE	(0x1 << 0)	/* TXFIFO Empty Status */
-#define SPI_STATUS_TH	(0x1 << 1)      /* TXFIFO Half Status */
-#define SPI_STATUS_TF	(0x1 << 2)      /* TXFIFO Full Status */
-#define SPI_STATUS_RR	(0x1 << 3)      /* RXFIFO Data Ready Status */
-#define SPI_STATUS_RH	(0x1 << 4)      /* RXFIFO Half Status */
-#define SPI_STATUS_RF	(0x1 << 5)      /* RXFIFO Full Status */
-#define SPI_STATUS_RO	(0x1 << 6)      /* RXFIFO Overflow */
-#define SPI_STATUS_BO	(0x1 << 7)      /* Bit Count Overflow */
-#define SPI_STATUS	(0xFF)		/* SPI Status Mask */
-#define SPI_INTEN_TE	(0x1 << 8)      /* TXFIFO Empty Interrupt Enable */
-#define SPI_INTEN_TH	(0x1 << 9)      /* TXFIFO Half Interrupt Enable */
-#define SPI_INTEN_TF	(0x1 << 10)     /* TXFIFO Full Interrupt Enable */
-#define SPI_INTEN_RE	(0x1 << 11)     /* RXFIFO Data Ready Interrupt Enable */
-#define SPI_INTEN_RH	(0x1 << 12)     /* RXFIFO Half Interrupt Enable */
-#define SPI_INTEN_RF	(0x1 << 13)     /* RXFIFO Full Interrupt Enable */
-#define SPI_INTEN_RO	(0x1 << 14)     /* RXFIFO Overflow Interrupt Enable */
-#define SPI_INTEN_BO	(0x1 << 15)     /* Bit Count Overflow Interrupt Enable */
-#define SPI_INTEN	(0xFF << 8)	/* SPI Interrupt Enable Mask */
-
 /* SPI Test Register Bit Fields & Masks */
 #define SPI_TEST_TXCNT		(0xF << 0)	/* TXFIFO Counter */
 #define SPI_TEST_RXCNT_LSB	(4)		/* RXFIFO Counter LSB */
 #define SPI_TEST_RXCNT		(0xF << 4)	/* RXFIFO Counter */
-#define SPI_TEST_SSTATUS	(0xF << 8)	/* State Machine Status */
 #define SPI_TEST_LBC		(0x1 << 14)	/* Loop Back Control */
 
 /* SPI Period Register Bit Fields & Masks */
-#define SPI_PERIOD_WAIT		(0x7FFF << 0)	/* Wait Between Transactions */
-#define SPI_PERIOD_MAX_WAIT	(0x7FFF)	/* Max Wait Between
+#define SPI_PERIOD_MAX_WAIT	(0x7FFF)	/* Wait Between Transactions
 							Transactions */
-#define SPI_PERIOD_CSRC		(0x1 << 15)	/* Period Clock Source Mask */
 #define SPI_PERIOD_CSRC_BCLK	(0x0 << 15)	/* Period Clock Source is
 							Bit Clock */
-#define SPI_PERIOD_CSRC_32768	(0x1 << 15)	/* Period Clock Source is
-							32.768 KHz Clock */
 
 /* SPI DMA Register Bit Fields & Masks */
 #define SPI_DMA_RHDMA	(0x1 << 4)	/* RXFIFO Half Status */
@@ -130,22 +67,6 @@
 #define SPI_DMA_TEDEN	(0x1 << 14)     /* TXFIFO Empty DMA Request Enable */
 #define SPI_DMA_THDEN	(0x1 << 15)     /* TXFIFO Half DMA Request Enable */
 
-/* SPI Soft Reset Register Bit Fields & Masks */
-#define SPI_RESET_START	(0x1)		/* Start */
-
-/* Default SPI configuration values */
-#define SPI_DEFAULT_CONTROL		\
-(					\
-	SPI_CONTROL_BITCOUNT(16) | 	\
-	SPI_CONTROL_POL_ACT_HIGH |	\
-	SPI_CONTROL_PHA_0 |		\
-	SPI_CONTROL_SPIEN |		\
-	SPI_CONTROL_SSCTL_1 |		\
-	SPI_CONTROL_MODE_MASTER |	\
-	SPI_CONTROL_DRCTL_0 |		\
-	SPI_CONTROL_DATARATE_MIN	\
-)
-#define SPI_DEFAULT_ENABLE_LOOPBACK	(0)
 #define SPI_DEFAULT_ENABLE_DMA		(0)
 #define SPI_DEFAULT_PERIOD_WAIT		(8)
 /*-------------------------------------------------------------------------*/
@@ -154,11 +75,10 @@
 /*-------------------------------------------------------------------------*/
 /* TX/RX SPI FIFO size */
 #define SPI_FIFO_DEPTH			(8)
-#define SPI_FIFO_BYTE_WIDTH		(2)
 #define SPI_FIFO_OVERFLOW_MARGIN	(2)
 
 /* DMA burst length for half full/empty request trigger */
-#define SPI_DMA_BLR			(SPI_FIFO_DEPTH * SPI_FIFO_BYTE_WIDTH / 2)
+#define SPI_DMA_BLR			(SPI_FIFO_DEPTH * (drv_data->version->max_bitcount / 8) / 2)
 
 /* Dummy char output to achieve reads.
    Choosing something different from all zeroes may help pattern recogition
@@ -168,12 +88,21 @@
 #define SPI_DUMMY_u32			((SPI_DUMMY_u16 << 16) | SPI_DUMMY_u16)
 
 /**
- * Macro to change a u32 field:
+ * U32_EDIT_WITH_SHIFT: Macro to change a u32 field:
  * @r : register to edit
  * @m : bit mask
- * @v : new value for the field correctly bit-alligned
+ * @v : new value
+ * @s : amount to shift for mask and value
+*/
+#define u32_EDIT_WITH_SHIFT(r, m, v, s)		r = (r & ~((m) << (s))) | ((v) << (s))
+
+/**
+ * U32_EDIT_BIT_COND: Macro to change a bit in a u32 field conditionally:
+ * @r : register to edit
+ * @c : condition according to which the bit will be set
+ * @s : amount to shift for the desired bit
 */
-#define u32_EDIT(r, m, v)		r = (r & ~(m)) | (v)
+#define u32_EDIT_BIT_COND(r, c, s)		r = (r & ~(1 << (s))) | (!!(c) << (s))
 
 /* Message state */
 #define START_STATE			((void*)0)
@@ -192,6 +121,109 @@
 /*-------------------------------------------------------------------------*/
 /* Driver data structs */
 
+struct driver_data;
+static u32 calc_datarate_linear(struct driver_data *drv_data, u32 speed_hz, u32 *val);
+static u32 calc_datarate_nonlinear(struct driver_data *drv_data, u32 speed_hz, u32 *val);
+
+struct spi_core_version {
+	u32 rxdata;
+	u32 txdata;
+	u32 ctrl;
+	u32 int_en;
+	u32 status;
+	u32 test;
+	u32 period;
+	u32 dma;
+	u32 reset;
+
+	u32 int_te;
+	u32 int_th;
+	u32 int_ro;
+	u32 int_te_en;
+	u32 int_th_en;
+	u32 int_ro_en;
+	u32 xch;
+
+	u8 bitcount_shift;
+	u8 sspol_shift;
+	u8 ssctl_shift;
+	u8 pha_shift;
+	u8 pol_shift;
+	u8 datarate_shift;
+	u8 reset_val;
+
+	u32 max_divider;
+	u32 max_bitcount;
+	u32 default_ctrl;
+	u32 (*calc_datarate)(struct driver_data *drv_data, u32 speed_hz, u32 *val);
+};
+
+static struct spi_core_version spi_core_ver_0_4 = {
+	.rxdata = 0x00,
+	.txdata = 0x04,
+	.ctrl = 0x08,
+	.int_en = 0x0c,
+	.dma = 0x10,
+	.status = 0x14,
+	.period = 0x18,
+	.test = 0x1c,
+	.reset = 0x08,
+
+	.int_te = 1 << 0,
+	.int_th = 1 << 1,
+	.int_ro = 1 << 6,
+	.int_te_en = 1 << 0,
+	.int_th_en = 1 << 1,
+	.int_ro_en = 1 << 6,
+	.xch = 1 << 2,
+
+	.bitcount_shift = 8,
+	.sspol_shift = 7,
+	.ssctl_shift = 6,
+	.pha_shift = 5,
+	.pol_shift = 4,
+	.datarate_shift = 16,
+	.reset_val = 0,
+
+	.max_divider = 512,
+	.max_bitcount = 32,
+	.default_ctrl = 0x00071f43,
+	.calc_datarate = calc_datarate_linear,
+};
+
+static struct spi_core_version spi_core_ver_0_0 = {
+	.rxdata = 0x00,
+	.txdata = 0x04,
+	.ctrl = 0x08,
+	.int_en = 0x0c,
+	.dma = 0x18,
+	.status = 0x0c,
+	.period = 0x14,
+	.test = 0x10,
+	.reset = 0x1c,
+
+	.int_te = 1 << 0,
+	.int_th = 1 << 1,
+	.int_ro = 1 << 7,
+	.int_te_en = 1 << 9,
+	.int_th_en = 1 << 10,
+	.int_ro_en = 1 << 16,
+	.xch = 1 << 9,
+
+	.bitcount_shift = 0,
+	.sspol_shift = 8,
+	.ssctl_shift = 7,
+	.pha_shift = 6,
+	.pol_shift = 5,
+	.datarate_shift = 14,
+	.reset_val = 1,
+
+	.max_divider = 512,
+	.max_bitcount = 32,
+	.default_ctrl = 0x00040c9f,
+	.calc_datarate = calc_datarate_nonlinear,
+};
+
 /* Context */
 struct driver_data {
 	/* Driver model hookup */
@@ -207,6 +239,8 @@ struct driver_data {
 	struct resource *ioarea;
 	void __iomem *regs;
 
+	struct spi_core_version *version;
+
 	/* SPI RX_DATA physical address */
 	dma_addr_t rd_data_phys;
 
@@ -269,7 +303,6 @@ struct chip_data {
 };
 /*-------------------------------------------------------------------------*/
 
-
 static void pump_messages(struct work_struct *work);
 
 static void flush(struct driver_data *drv_data)
@@ -281,17 +314,18 @@ static void flush(struct driver_data *drv_data)
 
 	/* Wait for end of transaction */
 	do {
-		control = readl(regs + SPI_CONTROL);
-	} while (control & SPI_CONTROL_XCH);
+		control = readl(regs + drv_data->version->ctrl);
+	} while (control & drv_data->version->xch);
 
 	/* Release chip select if requested, transfer delays are
 	   handled in pump_transfers */
 	if (drv_data->cs_change)
 		drv_data->cs_control(SPI_CS_DEASSERT);
 
-	/* Disable SPI to flush FIFOs */
-	writel(control & ~SPI_CONTROL_SPIEN, regs + SPI_CONTROL);
-	writel(control, regs + SPI_CONTROL);
+	/* Flush RXFIFO (not all spi-cores support hardware flushing) */
+	while (readl(regs + drv_data->version->test) & SPI_TEST_RXCNT)
+		readl(regs + drv_data->version->rxdata);
+
 }
 
 static void restore_state(struct driver_data *drv_data)
@@ -306,26 +340,16 @@ static void restore_state(struct driver_data *drv_data)
 		"    control = 0x%08X\n",
 		chip->test,
 		chip->control);
-	writel(chip->test, regs + SPI_TEST);
-	writel(chip->period, regs + SPI_PERIOD);
-	writel(0, regs + SPI_INT_STATUS);
-	writel(chip->control, regs + SPI_CONTROL);
+	writel(chip->test, regs + drv_data->version->test);
+	writel(chip->period, regs + drv_data->version->period);
+	writel(0, regs + drv_data->version->int_en);
+	writel(chip->control, regs + drv_data->version->ctrl);
 }
 
 static void null_cs_control(u32 command)
 {
 }
 
-static inline u32 data_to_write(struct driver_data *drv_data)
-{
-	return ((u32)(drv_data->tx_end - drv_data->tx)) / drv_data->n_bytes;
-}
-
-static inline u32 data_to_read(struct driver_data *drv_data)
-{
-	return ((u32)(drv_data->rx_end - drv_data->rx)) / drv_data->n_bytes;
-}
-
 static int write(struct driver_data *drv_data)
 {
 	void __iomem *regs = drv_data->regs;
@@ -334,24 +358,23 @@ static int write(struct driver_data *drv_data)
 	u8 n_bytes = drv_data->n_bytes;
 	u32 remaining_writes;
 	u32 fifo_avail_space;
-	u32 n;
-	u16 d;
+	u32 n,d;
 
 	/* Compute how many fifo writes to do */
-	remaining_writes = (u32)(tx_end - tx) / n_bytes;
+	remaining_writes = (u32)DIV_ROUND_UP(tx_end - tx, n_bytes);
 	fifo_avail_space = SPI_FIFO_DEPTH -
-				(readl(regs + SPI_TEST) & SPI_TEST_TXCNT);
+				(readl(regs + drv_data->version->test) & SPI_TEST_TXCNT);
 	if (drv_data->rx && (fifo_avail_space > SPI_FIFO_OVERFLOW_MARGIN))
 		/* Fix misunderstood receive overflow */
 		fifo_avail_space -= SPI_FIFO_OVERFLOW_MARGIN;
 	n = min(remaining_writes, fifo_avail_space);
 
 	dev_dbg(&drv_data->pdev->dev,
-		"write type %s\n"
+		"write type u%d\n"
 		"    remaining writes = %d\n"
 		"    fifo avail space = %d\n"
 		"    fifo writes      = %d\n",
-		(n_bytes == 1) ? "u8" : "u16",
+		n_bytes << 3,
 		remaining_writes,
 		fifo_avail_space,
 		n);
@@ -361,26 +384,36 @@ static int write(struct driver_data *drv_data)
 		if (drv_data->rd_only) {
 			tx += n * n_bytes;
 			while (n--)
-				writel(SPI_DUMMY_u16, regs + SPI_TXDATA);
+				writel(SPI_DUMMY_u32, regs + drv_data->version->txdata);
 		} else {
-			if (n_bytes == 1) {
+			switch (n_bytes) {
+			case 4:
 				while (n--) {
-					d = *(u8*)tx;
-					writel(d, regs + SPI_TXDATA);
-					tx += 1;
+					d = *(u32*)tx;
+					writel(d, regs + drv_data->version->txdata);
+					tx += 4;
 				}
-			} else {
+				break;
+			case 2:
 				while (n--) {
 					d = *(u16*)tx;
-					writel(d, regs + SPI_TXDATA);
+					writel(d, regs + drv_data->version->txdata);
 					tx += 2;
 				}
+				break;
+			case 1:
+				while (n--) {
+					d = *(u8*)tx;
+					writel(d, regs + drv_data->version->txdata);
+					tx += 1;
+				}
+				break;
 			}
 		}
 
 		/* Trigger transfer */
-		writel(readl(regs + SPI_CONTROL) | SPI_CONTROL_XCH,
-			regs + SPI_CONTROL);
+		writel(readl(regs + drv_data->version->ctrl) | drv_data->version->xch,
+			regs + drv_data->version->ctrl);
 
 		/* Update tx pointer */
 		drv_data->tx = tx;
@@ -397,39 +430,49 @@ static int read(struct driver_data *drv_data)
 	u8 n_bytes = drv_data->n_bytes;
 	u32 remaining_reads;
 	u32 fifo_rxcnt;
-	u32 n;
-	u16 d;
+	u32 n,d;
 
 	/* Compute how many fifo reads to do */
-	remaining_reads = (u32)(rx_end - rx) / n_bytes;
-	fifo_rxcnt = (readl(regs + SPI_TEST) & SPI_TEST_RXCNT) >>
+	remaining_reads = (u32)DIV_ROUND_UP(rx_end - rx, n_bytes);
+
+	fifo_rxcnt = (readl(regs + drv_data->version->test) & SPI_TEST_RXCNT) >>
 			SPI_TEST_RXCNT_LSB;
 	n = min(remaining_reads, fifo_rxcnt);
 
 	dev_dbg(&drv_data->pdev->dev,
-		"read type %s\n"
+		"read type u%d\n"
 		"    remaining reads = %d\n"
 		"    fifo rx count   = %d\n"
 		"    fifo reads      = %d\n",
-		(n_bytes == 1) ? "u8" : "u16",
+		n_bytes << 3,
 		remaining_reads,
 		fifo_rxcnt,
 		n);
 
 	if (n > 0) {
 		/* Read SPI RXFIFO */
-		if (n_bytes == 1) {
+		switch (n_bytes) {
+		case 4:
 			while (n--) {
-				d = readl(regs + SPI_RXDATA);
-				*((u8*)rx) = d;
-				rx += 1;
+				d = readl(regs + drv_data->version->rxdata);
+				*((u32*)rx) = d;
+				rx += 4;
 			}
-		} else {
+			break;
+		case 2:
 			while (n--) {
-				d = readl(regs + SPI_RXDATA);
+				d = readl(regs + drv_data->version->rxdata);
 				*((u16*)rx) = d;
 				rx += 2;
 			}
+			break;
+		case 1:
+			while (n--) {
+				d = readl(regs + drv_data->version->rxdata);
+				*((u8*)rx) = d;
+				rx += 1;
+			}
+			break;
 		}
 
 		/* Update rx pointer */
@@ -456,6 +499,30 @@ static void *next_transfer(struct driver_data *drv_data)
 	return DONE_STATE;
 }
 
+/* Caller already set message->status (dma is already blocked) */
+static void giveback(struct spi_message *message, struct driver_data *drv_data)
+{
+	void __iomem *regs = drv_data->regs;
+
+	/* Bring SPI to sleep; restore_state() and pump_transfer()
+	   will do new setup */
+	writel(0, regs + drv_data->version->int_en);
+	writel(0, regs + drv_data->version->dma);
+
+	/* Unconditioned deselct */
+	drv_data->cs_control(SPI_CS_DEASSERT);
+
+	message->state = NULL;
+	if (message->complete)
+		message->complete(message->context);
+
+	drv_data->cur_msg = NULL;
+	drv_data->cur_transfer = NULL;
+	drv_data->cur_chip = NULL;
+	queue_work(drv_data->workqueue, &drv_data->work);
+}
+
+#ifdef CONFIG_SPI_IMX_DMA
 static int map_dma_buffers(struct driver_data *drv_data)
 {
 	struct spi_message *msg;
@@ -568,29 +635,6 @@ static void unmap_dma_buffers(struct driver_data *drv_data)
 	}
 }
 
-/* Caller already set message->status (dma is already blocked) */
-static void giveback(struct spi_message *message, struct driver_data *drv_data)
-{
-	void __iomem *regs = drv_data->regs;
-
-	/* Bring SPI to sleep; restore_state() and pump_transfer()
-	   will do new setup */
-	writel(0, regs + SPI_INT_STATUS);
-	writel(0, regs + SPI_DMA);
-
-	/* Unconditioned deselct */
-	drv_data->cs_control(SPI_CS_DEASSERT);
-
-	message->state = NULL;
-	if (message->complete)
-		message->complete(message->context);
-
-	drv_data->cur_msg = NULL;
-	drv_data->cur_transfer = NULL;
-	drv_data->cur_chip = NULL;
-	queue_work(drv_data->workqueue, &drv_data->work);
-}
-
 static void dma_err_handler(int channel, void *data, int errcode)
 {
 	struct driver_data *drv_data = data;
@@ -618,7 +662,7 @@ static void dma_tx_handler(int channel, void *data)
 	imx_dma_disable(channel);
 
 	/* Now waits for TX FIFO empty */
-	writel(SPI_INTEN_TE, drv_data->regs + SPI_INT_STATUS);
+	writel(drv_data->version->int_te_en, drv_data->regs + drv_data->version->int_en);
 }
 
 static irqreturn_t dma_transfer(struct driver_data *drv_data)
@@ -627,11 +671,11 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
 	struct spi_message *msg = drv_data->cur_msg;
 	void __iomem *regs = drv_data->regs;
 
-	status = readl(regs + SPI_INT_STATUS);
+	status = readl(regs + drv_data->version->status);
 
-	if ((status & (SPI_INTEN_RO | SPI_STATUS_RO))
-			== (SPI_INTEN_RO | SPI_STATUS_RO)) {
-		writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
+	if ((status & (drv_data->version->int_ro_en | drv_data->version->int_ro))
+			== (drv_data->version->int_ro_en | drv_data->version->int_ro)) {
+		writel(0, regs + drv_data->version->int_en);
 
 		imx_dma_disable(drv_data->tx_channel);
 		imx_dma_disable(drv_data->rx_channel);
@@ -648,12 +692,12 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
 		return IRQ_HANDLED;
 	}
 
-	if (status & SPI_STATUS_TE) {
-		writel(status & ~SPI_INTEN_TE, regs + SPI_INT_STATUS);
+	if (status & drv_data->version->int_te) {
+		writel(status & ~drv_data->version->int_te_en, regs + drv_data->version->int_en);
 
 		if (drv_data->rx) {
 			/* Wait end of transfer before read trailing data */
-			while (readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH)
+			while (readl(regs + drv_data->version->ctrl) & drv_data->version->xch)
 				cpu_relax();
 
 			imx_dma_disable(drv_data->rx_channel);
@@ -667,9 +711,9 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
 			/* Calculate number of trailing data and read them */
 			dev_dbg(&drv_data->pdev->dev,
 				"dma_transfer - test = 0x%08X\n",
-				readl(regs + SPI_TEST));
+				readl(regs + drv_data->version->test));
 			drv_data->rx = drv_data->rx_end -
-					((readl(regs + SPI_TEST) &
+					((readl(regs + drv_data->version->test) &
 					SPI_TEST_RXCNT) >>
 					SPI_TEST_RXCNT_LSB)*drv_data->n_bytes;
 			read(drv_data);
@@ -696,6 +740,8 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
 	return IRQ_NONE;
 }
 
+#endif /* DMA */
+
 static irqreturn_t interrupt_wronly_transfer(struct driver_data *drv_data)
 {
 	struct spi_message *msg = drv_data->cur_msg;
@@ -703,11 +749,11 @@ static irqreturn_t interrupt_wronly_transfer(struct driver_data *drv_data)
 	u32 status;
 	irqreturn_t handled = IRQ_NONE;
 
-	status = readl(regs + SPI_INT_STATUS);
+	status = readl(regs + drv_data->version->status);
 
-	if (status & SPI_INTEN_TE) {
+	if (status & drv_data->version->int_te_en) {
 		/* TXFIFO Empty Interrupt on the last transfered word */
-		writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
+		writel(0, regs + drv_data->version->int_en);
 		dev_dbg(&drv_data->pdev->dev,
 			"interrupt_wronly_transfer - end of tx\n");
 
@@ -724,7 +770,7 @@ static irqreturn_t interrupt_wronly_transfer(struct driver_data *drv_data)
 
 		return IRQ_HANDLED;
 	} else {
-		while (status & SPI_STATUS_TH) {
+		while (status & drv_data->version->int_th) {
 			dev_dbg(&drv_data->pdev->dev,
 				"interrupt_wronly_transfer - status = 0x%08X\n",
 				status);
@@ -733,11 +779,11 @@ static irqreturn_t interrupt_wronly_transfer(struct driver_data *drv_data)
 			if (write(drv_data)) {
 				/* End of TXFIFO writes,
 				   now wait until TXFIFO is empty */
-				writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
+				writel(drv_data->version->int_te_en, regs + drv_data->version->int_en);
 				return IRQ_HANDLED;
 			}
 
-			status = readl(regs + SPI_INT_STATUS);
+			status = readl(regs + drv_data->version->status);
 
 			/* We did something */
 			handled = IRQ_HANDLED;
@@ -755,11 +801,11 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
 	irqreturn_t handled = IRQ_NONE;
 	unsigned long limit;
 
-	status = readl(regs + SPI_INT_STATUS);
+	status = readl(regs + drv_data->version->status);
 
-	if (status & SPI_INTEN_TE) {
+	if (status & drv_data->version->int_te_en) {
 		/* TXFIFO Empty Interrupt on the last transfered word */
-		writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
+		writel(0, regs + drv_data->version->int_en);
 		dev_dbg(&drv_data->pdev->dev,
 			"interrupt_transfer - end of tx\n");
 
@@ -769,8 +815,8 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
 		} else {
 			/* Wait for end of transaction */
 			do {
-				control = readl(regs + SPI_CONTROL);
-			} while (control & SPI_CONTROL_XCH);
+				control = readl(regs + drv_data->version->ctrl);
+			} while (control & drv_data->version->xch);
 
 			/* Release chip select if requested, transfer delays are
 			   handled in pump_transfers */
@@ -801,22 +847,22 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
 
 		return IRQ_HANDLED;
 	} else {
-		while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) {
+		while (status & (drv_data->version->int_th | drv_data->version->int_ro)) {
 			dev_dbg(&drv_data->pdev->dev,
 				"interrupt_transfer - status = 0x%08X\n",
 				status);
 
-			if (status & SPI_STATUS_RO) {
+			if (status & drv_data->version->int_ro) {
 				/* RXFIFO overrun, abort message end wait
 				   until TXFIFO is empty */
-				writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
+				writel(drv_data->version->int_te_en, regs + drv_data->version->int_en);
 
 				dev_warn(&drv_data->pdev->dev,
 					"interrupt_transfer - fifo overun\n"
 					"    data not yet written = %d\n"
 					"    data not yet read    = %d\n",
-					data_to_write(drv_data),
-					data_to_read(drv_data));
+					DIV_ROUND_UP(drv_data->tx_end - drv_data->tx, drv_data->n_bytes),
+					DIV_ROUND_UP(drv_data->rx_end - drv_data->rx, drv_data->n_bytes));
 
 				msg->state = ERROR_STATE;
 
@@ -828,11 +874,11 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
 			if (write(drv_data)) {
 				/* End of TXFIFO writes,
 				   now wait until TXFIFO is empty */
-				writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
+				writel(drv_data->version->int_te_en, regs + drv_data->version->int_en);
 				return IRQ_HANDLED;
 			}
 
-			status = readl(regs + SPI_INT_STATUS);
+			status = readl(regs + drv_data->version->status);
 
 			/* We did something */
 			handled = IRQ_HANDLED;
@@ -856,24 +902,44 @@ static irqreturn_t spi_int(int irq, void *dev_id)
 	return drv_data->transfer_handler(drv_data);
 }
 
-static inline u32 spi_speed_hz(struct driver_data *drv_data, u32 data_rate)
+static u32 calc_datarate_nonlinear(struct driver_data *drv_data, u32 speed_hz, u32 *val)
 {
-	return clk_get_rate(drv_data->clk) / (4 << ((data_rate) >> 13));
+	u32 div, max_div;
+	u32 quantized_hz = clk_get_rate(drv_data->clk);
+
+	*val &= ~(0x1f << drv_data->version->datarate_shift);
+
+	max_div = (ilog2(drv_data->version->max_divider) - 1) << 1;
+	/* we start at 2 as 0 is reserved and 1 needs speical care, see refman */
+	for (div = 2; div <= max_div; div += 2, quantized_hz >>= 1) {
+			if (quantized_hz / 4 <= speed_hz) {
+				*val |= div << drv_data->version->datarate_shift;
+				return quantized_hz / 4;
+			}
+			if (quantized_hz / 6 <= speed_hz) {
+				*val |= (div + 1) << drv_data->version->datarate_shift;
+				return quantized_hz / 6;
+			}
+	}
+	/* Nothing found, use slowest speed */
+	*val |= div << drv_data->version->datarate_shift;
+	return 0;
 }
 
-static u32 spi_data_rate(struct driver_data *drv_data, u32 speed_hz)
+static u32 calc_datarate_linear(struct driver_data *drv_data, u32 speed_hz, u32 *val)
 {
 	u32 div;
-	u32 quantized_hz = clk_get_rate(drv_data->clk) >> 2;
-
-	for (div = SPI_PERCLK2_DIV_MIN;
-		div <= SPI_PERCLK2_DIV_MAX;
-		div++, quantized_hz >>= 1) {
-			if (quantized_hz <= speed_hz)
-				/* Max available speed LEQ required speed */
-				return div << 13;
+	u32 quantized_hz = clk_get_rate(drv_data->clk) / 4;
+
+	*val &= ~(7 << drv_data->version->datarate_shift);
+	for (div = 0; div <= 7; div++, quantized_hz >>= 1) {
+			if (quantized_hz <= speed_hz) {
+				*val |= div << drv_data->version->datarate_shift;
+				return quantized_hz;
+			}
 	}
-	return SPI_CONTROL_DATARATE_BAD;
+	*val |= div << drv_data->version->datarate_shift;
+	return 0;
 }
 
 static void pump_transfers(unsigned long data)
@@ -931,7 +997,7 @@ static void pump_transfers(unsigned long data)
 	drv_data->rd_only = (drv_data->tx == NULL);
 
 	regs = drv_data->regs;
-	control = readl(regs + SPI_CONTROL);
+	control = readl(regs + drv_data->version->ctrl);
 
 	/* Bits per word setup */
 	tmp = transfer->bits_per_word;
@@ -941,27 +1007,24 @@ static void pump_transfers(unsigned long data)
 		drv_data->n_bytes = chip->n_bytes;
 	} else
 		/* Use per-transfer setup */
-		drv_data->n_bytes = (tmp <= 8) ? 1 : 2;
-	u32_EDIT(control, SPI_CONTROL_BITCOUNT_MASK, tmp - 1);
+		drv_data->n_bytes = roundup_pow_of_two(tmp) >> 3;
+	u32_EDIT_WITH_SHIFT(control, drv_data->version->max_bitcount - 1,
+				tmp - 1, drv_data->version->bitcount_shift);
 
 	/* Speed setup (surely valid because already checked) */
-	tmp = transfer->speed_hz;
-	if (tmp == 0)
-		tmp = chip->max_speed_hz;
-	tmp = spi_data_rate(drv_data, tmp);
-	u32_EDIT(control, SPI_CONTROL_DATARATE, tmp);
-
-	writel(control, regs + SPI_CONTROL);
+	drv_data->version->calc_datarate(drv_data, transfer->speed_hz ?: chip->max_speed_hz, &control);
+	writel(control, regs + drv_data->version->ctrl);
 
 	/* Assert device chip-select */
 	drv_data->cs_control(SPI_CS_ASSERT);
 
+#ifdef CONFIG_SPI_IMX_DMA
 	/* DMA cannot read/write SPI FIFOs other than 16 bits at a time; hence
 	   if bits_per_word is less or equal 8 PIO transfers are performed.
 	   Moreover DMA is convinient for transfer length bigger than FIFOs
 	   byte size. */
 	if ((drv_data->n_bytes == 2) &&
-		(drv_data->len > SPI_FIFO_DEPTH*SPI_FIFO_BYTE_WIDTH) &&
+		(drv_data->len > SPI_FIFO_DEPTH * (drv_data->version->max_bitcount / 8)) &&
 		(map_dma_buffers(drv_data) == 0)) {
 		dev_dbg(&drv_data->pdev->dev,
 			"pump dma transfer\n"
@@ -980,8 +1043,8 @@ static void pump_transfers(unsigned long data)
 		drv_data->transfer_handler = dma_transfer;
 
 		/* Trigger transfer */
-		writel(readl(regs + SPI_CONTROL) | SPI_CONTROL_XCH,
-			regs + SPI_CONTROL);
+		writel(readl(regs + drv_data->version->ctrl) | drv_data->version->xch,
+			regs + drv_data->version->ctrl);
 
 		/* Setup tx DMA */
 		if (drv_data->tx)
@@ -1023,18 +1086,20 @@ static void pump_transfers(unsigned long data)
 			imx_dma_enable(drv_data->rx_channel);
 
 			/* Enable SPI interrupt */
-			writel(SPI_INTEN_RO, regs + SPI_INT_STATUS);
+			writel(drv_data->version->int_ro_en, regs + drv_data->version->int_en);
 
 			/* Set SPI to request DMA service on both
 			   Rx and Tx half fifo watermark */
-			writel(SPI_DMA_RHDEN | SPI_DMA_THDEN, regs + SPI_DMA);
+			writel(SPI_DMA_RHDEN | SPI_DMA_THDEN, regs + drv_data->version->dma);
 		} else
 			/* Write only access -> set SPI to request DMA
 			   service on Tx half fifo watermark */
-			writel(SPI_DMA_THDEN, regs + SPI_DMA);
+			writel(SPI_DMA_THDEN, regs + drv_data->version->dma);
 
 		imx_dma_enable(drv_data->tx_channel);
-	} else {
+	} else
+#endif /* DMA */
+	{
 		dev_dbg(&drv_data->pdev->dev,
 			"pump pio transfer\n"
 			"    tx      = %p\n"
@@ -1052,10 +1117,10 @@ static void pump_transfers(unsigned long data)
 
 		/* Enable SPI interrupt */
 		if (drv_data->rx)
-			writel(SPI_INTEN_TH | SPI_INTEN_RO,
-				regs + SPI_INT_STATUS);
+			writel(drv_data->version->int_th_en | drv_data->version->int_ro_en,
+				regs + drv_data->version->int_en);
 		else
-			writel(SPI_INTEN_TH, regs + SPI_INT_STATUS);
+			writel(drv_data->version->int_th_en, regs + drv_data->version->int_en);
 	}
 }
 
@@ -1110,11 +1175,11 @@ static int transfer(struct spi_device *spi, struct spi_message *msg)
 	msg->actual_length = 0;
 
 	/* Per transfer setup check */
-	min_speed_hz = spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN);
+	min_speed_hz = clk_get_rate(drv_data->clk) / drv_data->version->max_divider;
 	max_speed_hz = spi->max_speed_hz;
 	list_for_each_entry(trans, &msg->transfers, transfer_list) {
 		tmp = trans->bits_per_word;
-		if (tmp > 16) {
+		if (tmp > drv_data->version->max_bitcount) {
 			dev_err(&drv_data->pdev->dev,
 				"message rejected : "
 				"invalid transfer bits_per_word (%d bits)\n",
@@ -1170,7 +1235,7 @@ msg_rejected:
 }
 
 /* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP)
 
 /* On first setup bad values must free chip_data memory since will cause
    spi_new_device to fail. Bad value setup from protocol driver are simply not
@@ -1181,7 +1246,7 @@ static int setup(struct spi_device *spi)
 	struct spi_imx_chip *chip_info;
 	struct chip_data *chip;
 	int first_setup = 0;
-	u32 tmp;
+	u32 bitcount, tmp, calc_hz;
 	int status = 0;
 
 	if (spi->mode & ~MODEBITS) {
@@ -1204,7 +1269,7 @@ static int setup(struct spi_device *spi)
 				"setup - cannot allocate controller state\n");
 			return -ENOMEM;
 		}
-		chip->control = SPI_DEFAULT_CONTROL;
+		chip->control = drv_data->version->default_ctrl;
 
 		if (chip_info == NULL) {
 			/* spi_board_info.controller_data not is supplied */
@@ -1218,12 +1283,12 @@ static int setup(struct spi_device *spi)
 				goto err_first_setup;
 			}
 			/* Set controller data default value */
-			chip_info->enable_loopback =
-						SPI_DEFAULT_ENABLE_LOOPBACK;
 			chip_info->enable_dma = SPI_DEFAULT_ENABLE_DMA;
 			chip_info->ins_ss_pulse = 1;
 			chip_info->bclk_wait = SPI_DEFAULT_PERIOD_WAIT;
 			chip_info->cs_control = null_cs_control;
+			//XXX: This was missing in the original driver. Bug or my misunderstanding?
+			spi->controller_data = chip_info;
 		}
 	}
 
@@ -1231,21 +1296,12 @@ static int setup(struct spi_device *spi)
 
 	if (first_setup) {
 		/* SPI loopback */
-		if (chip_info->enable_loopback)
-			chip->test = SPI_TEST_LBC;
-		else
-			chip->test = 0;
+		chip->test = (spi->mode & SPI_LOOP) ? SPI_TEST_LBC : 0;
 
 		/* SPI dma driven */
 		chip->enable_dma = chip_info->enable_dma;
 
-		/* SPI /SS pulse between spi burst */
-		if (chip_info->ins_ss_pulse)
-			u32_EDIT(chip->control,
-				SPI_CONTROL_SSCTL, SPI_CONTROL_SSCTL_1);
-		else
-			u32_EDIT(chip->control,
-				SPI_CONTROL_SSCTL, SPI_CONTROL_SSCTL_0);
+		u32_EDIT_BIT_COND(chip->control, chip_info->ins_ss_pulse, drv_data->version->ssctl_shift);
 
 		/* SPI bclk waits between each bits_per_word spi burst */
 		if (chip_info->bclk_wait > SPI_PERIOD_MAX_WAIT) {
@@ -1256,64 +1312,49 @@ static int setup(struct spi_device *spi)
 			goto err_first_setup;
 		}
 		chip->period = SPI_PERIOD_CSRC_BCLK |
-				(chip_info->bclk_wait & SPI_PERIOD_WAIT);
-	}
-
-	/* SPI mode */
-	tmp = spi->mode;
-	if (tmp & SPI_CS_HIGH) {
-		u32_EDIT(chip->control,
-				SPI_CONTROL_SSPOL, SPI_CONTROL_SSPOL_ACT_HIGH);
-	}
-	switch (tmp & SPI_MODE_3) {
-	case SPI_MODE_0:
-		tmp = 0;
-		break;
-	case SPI_MODE_1:
-		tmp = SPI_CONTROL_PHA_1;
-		break;
-	case SPI_MODE_2:
-		tmp = SPI_CONTROL_POL_ACT_LOW;
-		break;
-	default:
-		/* SPI_MODE_3 */
-		tmp = SPI_CONTROL_PHA_1 | SPI_CONTROL_POL_ACT_LOW;
-		break;
+				(chip_info->bclk_wait & SPI_PERIOD_MAX_WAIT);
 	}
-	u32_EDIT(chip->control, SPI_CONTROL_POL | SPI_CONTROL_PHA, tmp);
 
 	/* SPI word width */
-	tmp = spi->bits_per_word;
-	if (tmp == 0) {
-		tmp = 8;
+	bitcount = spi->bits_per_word;
+	if (bitcount == 0) {
+		bitcount = 8;
 		spi->bits_per_word = 8;
-	} else if (tmp > 16) {
+	} else if (bitcount > drv_data->version->max_bitcount) {
 		status = -EINVAL;
 		dev_err(&spi->dev,
 			"setup - "
 			"invalid bits_per_word (%d)\n",
-			tmp);
+			bitcount);
 		if (first_setup)
 			goto err_first_setup;
 		else {
 			/* Undo setup using chip as backup copy */
-			tmp = chip->bits_per_word;
-			spi->bits_per_word = tmp;
+			bitcount = chip->bits_per_word;
+			spi->bits_per_word = bitcount;
 		}
 	}
-	chip->bits_per_word = tmp;
-	u32_EDIT(chip->control, SPI_CONTROL_BITCOUNT_MASK, tmp - 1);
-	chip->n_bytes = (tmp <= 8) ? 1 : 2;
+	chip->bits_per_word = bitcount;
+	chip->n_bytes = roundup_pow_of_two(bitcount) >> 3;
+
+	tmp = chip->control;
+	u32_EDIT_WITH_SHIFT(tmp, drv_data->version->max_bitcount - 1,
+				bitcount - 1, drv_data->version->bitcount_shift);
+
+	u32_EDIT_BIT_COND(tmp, spi->mode & SPI_CS_HIGH, drv_data->version->sspol_shift);
+	u32_EDIT_BIT_COND(tmp, spi->mode & SPI_CPHA, drv_data->version->pha_shift);
+	u32_EDIT_BIT_COND(tmp, spi->mode & SPI_CPOL, drv_data->version->pol_shift);
+	chip->control = tmp;
 
 	/* SPI datarate */
-	tmp = spi_data_rate(drv_data, spi->max_speed_hz);
-	if (tmp == SPI_CONTROL_DATARATE_BAD) {
+	calc_hz = drv_data->version->calc_datarate(drv_data, spi->max_speed_hz, &tmp);
+	if (calc_hz == 0) {
 		status = -EINVAL;
 		dev_err(&spi->dev,
 			"setup - "
-			"HW min speed (%d Hz) exceeds required "
+			"HW min speed (%lu Hz) exceeds required "
 			"max speed (%d Hz)\n",
-			spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN),
+			clk_get_rate(drv_data->clk) / drv_data->version->max_divider,
 			spi->max_speed_hz);
 		if (first_setup)
 			goto err_first_setup;
@@ -1321,11 +1362,10 @@ static int setup(struct spi_device *spi)
 			/* Undo setup using chip as backup copy */
 			spi->max_speed_hz = chip->max_speed_hz;
 	} else {
-		u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp);
 		/* Actual rounded max_speed_hz */
-		tmp = spi_speed_hz(drv_data, tmp);
-		spi->max_speed_hz = tmp;
-		chip->max_speed_hz = tmp;
+		spi->max_speed_hz = calc_hz;
+		chip->max_speed_hz = calc_hz;
+		chip->control = tmp;
 	}
 
 	/* SPI chip-select management */
@@ -1346,15 +1386,15 @@ static int setup(struct spi_device *spi)
 		"    period wait       = %d\n"
 		"    mode              = %d\n"
 		"    bits per word     = %d\n"
-		"    min speed         = %d Hz\n"
+		"    min speed         = %lu Hz\n"
 		"    rounded max speed = %d Hz\n",
 		chip->test & SPI_TEST_LBC ? "Yes" : "No",
 		chip->enable_dma ? "Yes" : "No",
-		chip->control & SPI_CONTROL_SSCTL ? "Yes" : "No",
-		chip->period & SPI_PERIOD_WAIT,
-		spi->mode,
+		chip_info->ins_ss_pulse ? "Yes" : "No",
+		chip->period & SPI_PERIOD_MAX_WAIT,
+		spi->mode & SPI_MODE_3,
 		spi->bits_per_word,
-		spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN),
+		clk_get_rate(drv_data->clk) / drv_data->version->max_divider,
 		spi->max_speed_hz);
 	return status;
 
@@ -1479,6 +1519,16 @@ static int __init spi_imx_probe(struct platform_device *pdev)
 	drv_data->master_info = platform_info;
 	drv_data->pdev = pdev;
 
+	if (cpu_is_mx27())
+		drv_data->version = &spi_core_ver_0_0;
+	else if (cpu_is_mx31())
+		drv_data->version = &spi_core_ver_0_4;
+	else {
+		dev_err(&pdev->dev, "Could not determine spi-core-version\n");
+		status = -ENODEV;
+		goto err_no_cpu_type;
+	}
+
 	master->bus_num = pdev->id;
 	master->num_chipselect = platform_info->num_chipselect;
 	master->cleanup = cleanup;
@@ -1487,7 +1537,8 @@ static int __init spi_imx_probe(struct platform_device *pdev)
 
 	drv_data->dummy_dma_buf = SPI_DUMMY_u32;
 
-	drv_data->clk = clk_get(&pdev->dev, "perclk2");
+	//FIXME: names will be obsoleted
+	drv_data->clk = clk_get(&pdev->dev, "cspi_clk");
 	if (IS_ERR(drv_data->clk)) {
 		dev_err(&pdev->dev, "probe - cannot get clock\n");
 		status = PTR_ERR(drv_data->clk);
@@ -1495,6 +1546,10 @@ static int __init spi_imx_probe(struct platform_device *pdev)
 	}
 	clk_enable(drv_data->clk);
 
+	/* Setup any GPIO active */
+	if (platform_info->init)
+		platform_info->init(pdev);
+
 	/* Find and map resources */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
@@ -1503,20 +1558,19 @@ static int __init spi_imx_probe(struct platform_device *pdev)
 		goto err_no_iores;
 	}
 	drv_data->ioarea = request_mem_region(res->start,
-						res->end - res->start + 1,
+						resource_size(res),
 						pdev->name);
 	if (drv_data->ioarea == NULL) {
 		dev_err(&pdev->dev, "probe - cannot reserve region\n");
 		status = -ENXIO;
 		goto err_no_iores;
 	}
-	drv_data->regs = ioremap(res->start, res->end - res->start + 1);
+	drv_data->regs = ioremap(res->start, resource_size(res));
 	if (drv_data->regs == NULL) {
 		dev_err(&pdev->dev, "probe - cannot map IO\n");
 		status = -ENXIO;
 		goto err_no_iomap;
 	}
-	drv_data->rd_data_phys = (dma_addr_t)res->start;
 
 	/* Attach to IRQ */
 	irq = platform_get_irq(pdev, 0);
@@ -1531,11 +1585,14 @@ static int __init spi_imx_probe(struct platform_device *pdev)
 		goto err_no_irqres;
 	}
 
+#ifdef CONFIG_SPI_IMX_DMA
+	drv_data->rd_data_phys = (dma_addr_t)res->start;
 	/* Setup DMA if requested */
 	drv_data->tx_channel = -1;
 	drv_data->rx_channel = -1;
 	if (platform_info->enable_dma) {
 		/* Get rx DMA channel */
+		status = -ENODEV;
 		drv_data->rx_channel = imx_dma_request_by_prio("spi_imx_rx",
 							       DMA_PRIO_HIGH);
 		if (drv_data->rx_channel < 0) {
@@ -1554,7 +1611,6 @@ static int __init spi_imx_probe(struct platform_device *pdev)
 			dev_err(dev,
 				"probe - problem (%d) requesting tx channel\n",
 				drv_data->tx_channel);
-			imx_dma_free(drv_data->rx_channel);
 			goto err_no_txdma;
 		} else
 			imx_dma_setup_handlers(drv_data->tx_channel,
@@ -1575,19 +1631,16 @@ static int __init spi_imx_probe(struct platform_device *pdev)
 			break;
 		default:
 			dev_err(dev, "probe - bad SPI Id\n");
-			imx_dma_free(drv_data->rx_channel);
-			imx_dma_free(drv_data->tx_channel);
-			status = -ENODEV;
 			goto err_no_devid;
 		}
 		BLR(drv_data->rx_channel) = SPI_DMA_BLR;
 		BLR(drv_data->tx_channel) = SPI_DMA_BLR;
 	}
+#endif /* DMA */
 
 	/* Load default SPI configuration */
-	writel(SPI_RESET_START, drv_data->regs + SPI_RESET);
-	writel(0, drv_data->regs + SPI_RESET);
-	writel(SPI_DEFAULT_CONTROL, drv_data->regs + SPI_CONTROL);
+	writel(drv_data->version->reset_val, drv_data->regs + drv_data->version->reset);
+	writel(drv_data->version->default_ctrl, drv_data->regs + drv_data->version->ctrl);
 
 	/* Initial and start queue */
 	status = init_queue(drv_data);
@@ -1617,9 +1670,13 @@ err_start_queue:
 err_spi_register:
 	destroy_queue(drv_data);
 
-err_no_rxdma:
-err_no_txdma:
+#ifdef CONFIG_SPI_IMX_DMA
 err_no_devid:
+	imx_dma_free(drv_data->tx_channel);
+err_no_txdma:
+	imx_dma_free(drv_data->rx_channel);
+err_no_rxdma:
+#endif /* DMA */
 	free_irq(irq, drv_data);
 
 err_no_irqres:
@@ -1632,7 +1689,10 @@ err_no_iomap:
 err_no_iores:
 	clk_disable(drv_data->clk);
 	clk_put(drv_data->clk);
+	if (platform_info->exit)
+		platform_info->exit(pdev);
 
+err_no_cpu_type:
 err_no_clk:
 	spi_master_put(master);
 
@@ -1646,6 +1706,8 @@ static int __exit spi_imx_remove(struct platform_device *pdev)
 	struct driver_data *drv_data = platform_get_drvdata(pdev);
 	int irq;
 	int status = 0;
+	struct spi_imx_master *platform_info =
+			(struct spi_imx_master *)pdev->dev.platform_data;
 
 	if (!drv_data)
 		return 0;
@@ -1659,10 +1721,13 @@ static int __exit spi_imx_remove(struct platform_device *pdev)
 		return status;
 	}
 
+	if (platform_info->exit)
+		platform_info->exit(pdev);
+
 	/* Reset SPI */
-	writel(SPI_RESET_START, drv_data->regs + SPI_RESET);
-	writel(0, drv_data->regs + SPI_RESET);
+	writel(drv_data->version->reset_val, drv_data->regs + drv_data->version->reset);
 
+#ifdef CONFIG_SPI_IMX_DMA
 	/* Release DMA */
 	if (drv_data->master_info->enable_dma) {
 		RSSR(drv_data->rx_channel) = 0;
@@ -1670,6 +1735,7 @@ static int __exit spi_imx_remove(struct platform_device *pdev)
 		imx_dma_free(drv_data->tx_channel);
 		imx_dma_free(drv_data->rx_channel);
 	}
+#endif /* DMA */
 
 	/* Release IRQ */
 	irq = platform_get_irq(pdev, 0);
@@ -1701,8 +1767,7 @@ static void spi_imx_shutdown(struct platform_device *pdev)
 	struct driver_data *drv_data = platform_get_drvdata(pdev);
 
 	/* Reset SPI */
-	writel(SPI_RESET_START, drv_data->regs + SPI_RESET);
-	writel(0, drv_data->regs + SPI_RESET);
+	writel(drv_data->version->reset_val, drv_data->regs + drv_data->version->reset);
 
 	dev_dbg(&pdev->dev, "shutdown succeded\n");
 }
@@ -1714,12 +1779,20 @@ static int spi_imx_suspend(struct platform_device *pdev, pm_message_t state)
 	struct driver_data *drv_data = platform_get_drvdata(pdev);
 	int status = 0;
 
+	struct spi_imx_master *platform_info =
+			(struct spi_imx_master *)pdev->dev.platform_data;
+
 	status = stop_queue(drv_data);
 	if (status != 0) {
 		dev_warn(&pdev->dev, "suspend cannot stop queue\n");
 		return status;
 	}
 
+	if (platform_info->exit)
+		platform_info->exit(pdev);
+
+	clk_disable(drv_data->clk);
+
 	dev_dbg(&pdev->dev, "suspended\n");
 
 	return 0;
@@ -1730,6 +1803,14 @@ static int spi_imx_resume(struct platform_device *pdev)
 	struct driver_data *drv_data = platform_get_drvdata(pdev);
 	int status = 0;
 
+	struct spi_imx_master *platform_info =
+			(struct spi_imx_master *)pdev->dev.platform_data;
+
+	clk_enable(drv_data->clk);
+
+	if (platform_info->init)
+		platform_info->init(pdev);
+
 	/* Start the queue running */
 	status = start_queue(drv_data);
 	if (status != 0)
-- 
1.5.6.5

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-5064 |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 415 bytes --]

------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H

[-- Attachment #3: Type: text/plain, Size: 210 bytes --]

_______________________________________________
spi-devel-general mailing list
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

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

* Re: [RFC] generic iMX-spi driver
       [not found] ` <20090220144126.GA9203-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2009-02-20 14:58   ` Wolfram Sang
  2009-02-20 15:41   ` Holger Schurig
  1 sibling, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2009-02-20 14:58 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW


[-- Attachment #1.1: Type: text/plain, Size: 3162 bytes --]

Me again,

here is an example patch what I needed to do in order to switch from the
old FSL-driver to this one. Hope it helps.

---
 arch/arm/mach-mx2/devices.c     |    6 +++---
 arch/arm/mach-mx2/pcm038.c      |    7 ++++---
 drivers/mxc/pmic/Kconfig        |    2 +-
 drivers/mxc/pmic/core/mc13783.c |    2 +-
 4 files changed, 9 insertions(+), 8 deletions(-)

Index: arch/arm/mach-mx2/devices.c
===================================================================
--- arch/arm/mach-mx2/devices.c.orig
+++ arch/arm/mach-mx2/devices.c
@@ -143,14 +143,14 @@ static struct resource mxc_spi_resources
 #endif
 
 struct platform_device mxc_spi_device0 = {
-	.name = "mxc_spi",
+	.name = "spi_imx",
 	.id = 0,
 	.num_resources = ARRAY_SIZE(mxc_spi_resources0),
 	.resource = mxc_spi_resources0,
 };
 
 struct platform_device mxc_spi_device1 = {
-	.name = "mxc_spi",
+	.name = "spi_imx",
 	.id = 1,
 	.num_resources = ARRAY_SIZE(mxc_spi_resources1),
 	.resource = mxc_spi_resources1,
@@ -158,7 +158,7 @@ struct platform_device mxc_spi_device1 =
 
 #ifdef CONFIG_MACH_MX27
 struct platform_device mxc_spi_device2 = {
-	.name = "mxc_spi",
+	.name = "spi_imx",
 	.id = 2,
 	.num_resources = ARRAY_SIZE(mxc_spi_resources2),
 	.resource = mxc_spi_resources2,
Index: arch/arm/mach-mx2/pcm038.c
===================================================================
--- arch/arm/mach-mx2/pcm038.c.orig
+++ arch/arm/mach-mx2/pcm038.c
@@ -37,7 +37,8 @@
 #include <mach/iomux-mx1-mx2.h>
 #include <mach/gpio.h>
 #include <mach/i2c.h>
-#include <mach/imx_spi.h>
+//#include <mach/imx_spi.h>
+#include <mach/spi_imx.h>
 #include <mach/imx-uart.h>
 #include <mach/imx_ssi.h>
 #include <mach/pmic/platform.h>
@@ -178,8 +179,8 @@ static int gpio_spi_inactive_0(struct pl
 	return 0;
 }
 
-static struct mxc_spi_master pcm038_spi_0_data = {
-	.maxchipselect = 4,	/* FIXME */
+static struct spi_imx_master pcm038_spi_0_data = {
+	.num_chipselect = 4,	/* FIXME */
 	.init = gpio_spi_active_0,
 	.exit = gpio_spi_inactive_0,
 };
Index: drivers/mxc/pmic/Kconfig
===================================================================
--- drivers/mxc/pmic/Kconfig.orig
+++ drivers/mxc/pmic/Kconfig
@@ -6,7 +6,7 @@ menu "MXC PMIC support"
 
 config MXC_SPI_PMIC_CORE
 	tristate "PMIC Protocol support (SPI interface)"
-	depends on ARCH_MX2 && SPI_MXC
+	depends on ARCH_MX2 && (SPI_MXC || SPI_IMX)
 	default n
 	help
       	  This is the PMIC core/protocol driver for the Freescale MXC application.
Index: drivers/mxc/pmic/core/mc13783.c
===================================================================
--- drivers/mxc/pmic/core/mc13783.c.orig
+++ drivers/mxc/pmic/core/mc13783.c
@@ -117,7 +117,7 @@ int pmic_spi_setup(struct spi_device *sp
 	/* Setup the SPI slave i.e.PMIC */
 	pmic_drv_data.spi = spi;
 
-	spi->mode = SPI_MODE_2 | SPI_CS_HIGH;
+	spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
 	spi->bits_per_word = 32;
 
 	return spi_setup(spi);

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 415 bytes --]

------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H

[-- Attachment #3: Type: text/plain, Size: 210 bytes --]

_______________________________________________
spi-devel-general mailing list
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

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

* Re: [RFC] generic iMX-spi driver
       [not found] ` <20090220144126.GA9203-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  2009-02-20 14:58   ` Wolfram Sang
@ 2009-02-20 15:41   ` Holger Schurig
       [not found]     ` <200902201641.21168.hs4233-x6+DxXLjN1AJvtFkdXX2Hg4jNU5vUVPG@public.gmane.org>
  1 sibling, 1 reply; 13+ messages in thread
From: Holger Schurig @ 2009-02-20 15:41 UTC (permalink / raw)
  To: linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

> +	int (*exit)(struct platform_device *pdev);

void (*exit)(struct platform_device *pdev);

> +struct spi_core_version {
> +	u32 rxdata;
> +	u32 txdata;
> +	u32 ctrl;
> +	u32 int_en;
> +	u32 status;
> +	u32 test;
> +	u32 period;
> +	u32 dma;
> +	u32 reset;
> +
> +	u32 int_te;
> +	u32 int_th;
> +	u32 int_ro;
> +	u32 int_te_en;
> +	u32 int_th_en;
> +	u32 int_ro_en;
> +	u32 xch;
> +
> +	u8 bitcount_shift;
> +	u8 sspol_shift;
> +	u8 ssctl_shift;
> +	u8 pha_shift;
> +	u8 pol_shift;
> +	u8 datarate_shift;
> +	u8 reset_val;
> +
> +	u32 max_divider;
> +	u32 max_bitcount;
> +	u32 default_ctrl;
> +	u32 (*calc_datarate)(struct driver_data *drv_data, u32
>           speed_hz, u32 *val); 
> +}; 

A number of u8's in the middle of a structure where later
32 bit long entries are comming?

Move that to the end or change it to 32 (I yet have to verify if
the compiler creates stupid or good code when accessing u8 out of
a struct, but I assume that on ARM the code is more-or-less stupid).


> +	/* Setup any GPIO active */
> +	if (platform_info->init)
> +		platform_info->init(pdev);

This function can fail, so you need to handle the error case.

------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H

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

* Re: [RFC] generic iMX-spi driver
  2009-02-20 14:41 [RFC] generic iMX-spi driver Wolfram Sang
       [not found] ` <20090220144126.GA9203-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2009-02-23  8:57 ` Paulius Zaleckas
       [not found]   ` <49A264DE.8080805-Ft0m5Q12RQ9xBelEqimL3w@public.gmane.org>
  1 sibling, 1 reply; 13+ messages in thread
From: Paulius Zaleckas @ 2009-02-23  8:57 UTC (permalink / raw)
  To: Wolfram Sang; +Cc: spi-devel-general, linux-arm

Wolfram Sang wrote:
> @@ -1646,6 +1706,8 @@ static int __exit spi_imx_remove(struct platform_device *pdev)
>  	struct driver_data *drv_data = platform_get_drvdata(pdev);
>  	int irq;
>  	int status = 0;
> +	struct spi_imx_master *platform_info =
> +			(struct spi_imx_master *)pdev->dev.platform_data;
>  
>  	if (!drv_data)
>  		return 0;
> @@ -1659,10 +1721,13 @@ static int __exit spi_imx_remove(struct platform_device *pdev)
>  		return status;
>  	}
>  
> +	if (platform_info->exit)
> +		platform_info->exit(pdev);

platform_info can be NULL here if when declaring platform_device platform data was not set.
In this case you will get crash here.
Should be if (platform_info && platform_info->exit)

> +
>  	/* Reset SPI */
> -	writel(SPI_RESET_START, drv_data->regs + SPI_RESET);
> -	writel(0, drv_data->regs + SPI_RESET);
> +	writel(drv_data->version->reset_val, drv_data->regs + drv_data->version->reset);
>  
> +#ifdef CONFIG_SPI_IMX_DMA
>  	/* Release DMA */
>  	if (drv_data->master_info->enable_dma) {
>  		RSSR(drv_data->rx_channel) = 0;
> @@ -1670,6 +1735,7 @@ static int __exit spi_imx_remove(struct platform_device *pdev)
>  		imx_dma_free(drv_data->tx_channel);
>  		imx_dma_free(drv_data->rx_channel);
>  	}
> +#endif /* DMA */
>  
>  	/* Release IRQ */
>  	irq = platform_get_irq(pdev, 0);
> @@ -1701,8 +1767,7 @@ static void spi_imx_shutdown(struct platform_device *pdev)
>  	struct driver_data *drv_data = platform_get_drvdata(pdev);
>  
>  	/* Reset SPI */
> -	writel(SPI_RESET_START, drv_data->regs + SPI_RESET);
> -	writel(0, drv_data->regs + SPI_RESET);
> +	writel(drv_data->version->reset_val, drv_data->regs + drv_data->version->reset);
>  
>  	dev_dbg(&pdev->dev, "shutdown succeded\n");
>  }
> @@ -1714,12 +1779,20 @@ static int spi_imx_suspend(struct platform_device *pdev, pm_message_t state)
>  	struct driver_data *drv_data = platform_get_drvdata(pdev);
>  	int status = 0;
>  
> +	struct spi_imx_master *platform_info =
> +			(struct spi_imx_master *)pdev->dev.platform_data;
> +
>  	status = stop_queue(drv_data);
>  	if (status != 0) {
>  		dev_warn(&pdev->dev, "suspend cannot stop queue\n");
>  		return status;
>  	}
>  
> +	if (platform_info->exit)
> +		platform_info->exit(pdev);

ditto

> +
> +	clk_disable(drv_data->clk);
> +
>  	dev_dbg(&pdev->dev, "suspended\n");
>  
>  	return 0;
> @@ -1730,6 +1803,14 @@ static int spi_imx_resume(struct platform_device *pdev)
>  	struct driver_data *drv_data = platform_get_drvdata(pdev);
>  	int status = 0;
>  
> +	struct spi_imx_master *platform_info =
> +			(struct spi_imx_master *)pdev->dev.platform_data;
> +
> +	clk_enable(drv_data->clk);
> +
> +	if (platform_info->init)
> +		platform_info->init(pdev);

ditto

> +
>  	/* Start the queue running */
>  	status = start_queue(drv_data);
>  	if (status != 0)


-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ:        http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette:  http://www.arm.linux.org.uk/mailinglists/etiquette.php

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

* Re: [RFC] generic iMX-spi driver
       [not found]   ` <49A264DE.8080805-Ft0m5Q12RQ9xBelEqimL3w@public.gmane.org>
@ 2009-02-26  9:58     ` Wolfram Sang
       [not found]       ` <20090226095825.GA3058-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  0 siblings, 1 reply; 13+ messages in thread
From: Wolfram Sang @ 2009-02-26  9:58 UTC (permalink / raw)
  To: Paulius Zaleckas
  Cc: Wolfram Sang, linux-arm,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f


[-- Attachment #1.1: Type: text/plain, Size: 660 bytes --]


> > @@ -1659,10 +1721,13 @@ static int __exit spi_imx_remove(struct platform_device *pdev)
> >  		return status;
> >  	}
> >  
> > +	if (platform_info->exit)
> > +		platform_info->exit(pdev);
> 
> platform_info can be NULL here if when declaring platform_device platform data was not set.
> In this case you will get crash here.
> Should be if (platform_info && platform_info->exit)

Well, that is the first thing the probe function checks :) It will fail
if there is no platform_data.

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 415 bytes --]

------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H

[-- Attachment #3: Type: text/plain, Size: 210 bytes --]

_______________________________________________
spi-devel-general mailing list
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

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

* Re: [RFC] generic iMX-spi driver
       [not found]       ` <20090226095825.GA3058-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2009-02-26 10:07         ` Paulius Zaleckas
  0 siblings, 0 replies; 13+ messages in thread
From: Paulius Zaleckas @ 2009-02-26 10:07 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Wolfram Sang, linux-arm,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

Wolfram Sang wrote:
>>> @@ -1659,10 +1721,13 @@ static int __exit spi_imx_remove(struct platform_device *pdev)
>>>  		return status;
>>>  	}
>>>  
>>> +	if (platform_info->exit)
>>> +		platform_info->exit(pdev);
>> platform_info can be NULL here if when declaring platform_device platform data was not set.
>> In this case you will get crash here.
>> Should be if (platform_info && platform_info->exit)
> 
> Well, that is the first thing the probe function checks :) It will fail
> if there is no platform_data. 

OK then. I missed that check :|

------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H

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

* Re: [RFC] generic iMX-spi driver
       [not found]     ` <200902201641.21168.hs4233-x6+DxXLjN1AJvtFkdXX2Hg4jNU5vUVPG@public.gmane.org>
@ 2009-02-26 10:38       ` Wolfram Sang
       [not found]         ` <20090226103844.GB3058-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  0 siblings, 1 reply; 13+ messages in thread
From: Wolfram Sang @ 2009-02-26 10:38 UTC (permalink / raw)
  To: Holger Schurig
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW


[-- Attachment #1.1: Type: text/plain, Size: 1983 bytes --]

On Fri, Feb 20, 2009 at 04:41:21PM +0100, Holger Schurig wrote:

> > +	int (*exit)(struct platform_device *pdev);
> 
> void (*exit)(struct platform_device *pdev);

Fixed (Hmm, quite some more candidates for this one in mach/)

> > +struct spi_core_version {
> > +	u32 rxdata;
> > +	u32 txdata;
> > +	u32 ctrl;
> > +	u32 int_en;
> > +	u32 status;
> > +	u32 test;
> > +	u32 period;
> > +	u32 dma;
> > +	u32 reset;
> > +
> > +	u32 int_te;
> > +	u32 int_th;
> > +	u32 int_ro;
> > +	u32 int_te_en;
> > +	u32 int_th_en;
> > +	u32 int_ro_en;
> > +	u32 xch;
> > +
> > +	u8 bitcount_shift;
> > +	u8 sspol_shift;
> > +	u8 ssctl_shift;
> > +	u8 pha_shift;
> > +	u8 pol_shift;
> > +	u8 datarate_shift;
> > +	u8 reset_val;
> > +
> > +	u32 max_divider;
> > +	u32 max_bitcount;
> > +	u32 default_ctrl;
> > +	u32 (*calc_datarate)(struct driver_data *drv_data, u32
> >           speed_hz, u32 *val); 
> > +}; 
> 
> A number of u8's in the middle of a structure where later
> 32 bit long entries are comming?
> 
> Move that to the end or change it to 32 (I yet have to verify if
> the compiler creates stupid or good code when accessing u8 out of
> a struct, but I assume that on ARM the code is more-or-less stupid).

Well, could be that I thought too much about size vs. performance issues
here. My idea was to put the variables needed in hot-paths to the front
of the struct.
All variables starting from the u8-block are just used in initialization
routines and so I tended to size-optimize here as we need at least six
of such structs.
I'm open for suggestions, though.

> > +	/* Setup any GPIO active */
> > +	if (platform_info->init)
> > +		platform_info->init(pdev);
> 
> This function can fail, so you need to handle the error case.

Fixed.

Thanks for your comments.

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 415 bytes --]

------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H

[-- Attachment #3: Type: text/plain, Size: 210 bytes --]

_______________________________________________
spi-devel-general mailing list
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

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

* Re: [RFC] generic iMX-spi driver
       [not found]         ` <20090226103844.GB3058-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2009-02-26 23:26           ` Russell King - ARM Linux
       [not found]             ` <20090226232639.GF5811-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
  0 siblings, 1 reply; 13+ messages in thread
From: Russell King - ARM Linux @ 2009-02-26 23:26 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Holger Schurig,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW

On Thu, Feb 26, 2009 at 11:38:44AM +0100, Wolfram Sang wrote:
> On Fri, Feb 20, 2009 at 04:41:21PM +0100, Holger Schurig wrote:
> > > +struct spi_core_version {
> > > +	u32 rxdata;
> > > +	u32 txdata;
> > > +	u32 ctrl;
> > > +	u32 int_en;
> > > +	u32 status;
> > > +	u32 test;
> > > +	u32 period;
> > > +	u32 dma;
> > > +	u32 reset;
> > > +
> > > +	u32 int_te;
> > > +	u32 int_th;
> > > +	u32 int_ro;
> > > +	u32 int_te_en;
> > > +	u32 int_th_en;
> > > +	u32 int_ro_en;
> > > +	u32 xch;
> > > +
> > > +	u8 bitcount_shift;
> > > +	u8 sspol_shift;
> > > +	u8 ssctl_shift;
> > > +	u8 pha_shift;
> > > +	u8 pol_shift;
> > > +	u8 datarate_shift;
> > > +	u8 reset_val;
> > > +
> > > +	u32 max_divider;
> > > +	u32 max_bitcount;
> > > +	u32 default_ctrl;
> > > +	u32 (*calc_datarate)(struct driver_data *drv_data, u32
> > >           speed_hz, u32 *val); 
> > > +}; 
> > 
> > A number of u8's in the middle of a structure where later
> > 32 bit long entries are comming?
> > 
> > Move that to the end or change it to 32 (I yet have to verify if
> > the compiler creates stupid or good code when accessing u8 out of
> > a struct, but I assume that on ARM the code is more-or-less stupid).
> 
> Well, could be that I thought too much about size vs. performance issues
> here. My idea was to put the variables needed in hot-paths to the front
> of the struct.

That is a good reason for ordering structs like this.  ARM does generate
good code for accessing bytes in structures - it does have a byte load
instruction.

What it does do though is want to naturally align structure members, so
it's a good idea to group u8's together up to the next members natural
boundary.  So:

struct {
	u32 hot_32_1;
	u8 hot_8_1;
	u8 hot_8_2;
	u32 hot_32_2;
	u32 cold_32_1;
	u8 cold_8_1;
	u8 cold_8_2;
	u32 cold_32_2;
};

would be a silly layout - you'd end up adding an additional four bytes for
no gain.  Instead:

struct {
	u32 hot_32_1;
	u8 hot_8_1;
	u8 hot_8_2;
	u8 cold_8_1;
	u8 cold_8_2;
	u32 hot_32_2;
	u32 cold_32_1;
	u32 cold_32_2;
};

would be optimal use of memory without breaking the proximty of the hot
members (since you've put the two cold bytes into the wastage bytes.)

------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H

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

* Re: [RFC] generic iMX-spi driver
       [not found]             ` <20090226232639.GF5811-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
@ 2009-02-27 10:38               ` Wolfram Sang
       [not found]                 ` <20090227103840.GC3481-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  0 siblings, 1 reply; 13+ messages in thread
From: Wolfram Sang @ 2009-02-27 10:38 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Holger Schurig,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW


[-- Attachment #1.1: Type: text/plain, Size: 1000 bytes --]

> What it does do though is want to naturally align structure members, so
> it's a good idea to group u8's together up to the next members natural
> boundary.  So:

All the hot-path variables are u32 as I don't want to do shifting there.
The u8-members are all cold-path, so I can use them as shift counters.
They happen to be 8 in V2, so that seems to fit, too (for now that is).
I know about aligning and will keep an eye on this.

One more thing I had in mind: As every access to a register now looks
like

 'regs + drv_data->version->$some_offset'

I also wondered if it would pay off to add the register base to the
offset already in the probe routine, so we then can reduce the access to
simply

'drv_data->version->$some_reg'

But this is for later, after the driver is stable, I think.

Regards,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 415 bytes --]

------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H

[-- Attachment #3: Type: text/plain, Size: 210 bytes --]

_______________________________________________
spi-devel-general mailing list
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

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

* Re: [RFC] generic iMX-spi driver
       [not found]                 ` <20090227103840.GC3481-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2009-03-02 20:58                   ` Russell King - ARM Linux
       [not found]                     ` <20090302205826.GG25699-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
  0 siblings, 1 reply; 13+ messages in thread
From: Russell King - ARM Linux @ 2009-03-02 20:58 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Holger Schurig,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW

On Fri, Feb 27, 2009 at 11:38:40AM +0100, Wolfram Sang wrote:
> > What it does do though is want to naturally align structure members, so
> > it's a good idea to group u8's together up to the next members natural
> > boundary.  So:
> 
> All the hot-path variables are u32 as I don't want to do shifting there.
> The u8-members are all cold-path, so I can use them as shift counters.

What shifting are you referring to?  ARM GCC doesn't load a word and then
shift to get at the byte it's interested in.  It uses the ARM byte load
instruction or byte store instruction which are just as fast as word
loads or stores.

> One more thing I had in mind: As every access to a register now looks
> like
> 
>  'regs + drv_data->version->$some_offset'
> 
> I also wondered if it would pay off to add the register base to the
> offset already in the probe routine, so we then can reduce the access to
> simply
> 
> 'drv_data->version->$some_reg'
> 
> But this is for later, after the driver is stable, I think.

The load instruction combines addition or subtraction:

	ldr	rd, [rn, rm]

optionally with a constant shift for 'rm', so the first version is
entirely possible for the compiler to use one instruction to access
[regs + offset] in one instruction.

------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H

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

* Re: [RFC] generic iMX-spi driver
       [not found]                     ` <20090302205826.GG25699-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
@ 2009-04-30 21:44                       ` Guennadi Liakhovetski
  2009-04-30 21:49                         ` Russell King - ARM Linux
       [not found]                         ` <Pine.LNX.4.64.0904302343470.9542-0199iw4Nj15frtckUFj5Ag@public.gmane.org>
  0 siblings, 2 replies; 13+ messages in thread
From: Guennadi Liakhovetski @ 2009-04-30 21:44 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Holger Schurig,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW

Hi,

what's the state of this patch? Is a new revision planned soon to go in 
for 2.6.31?

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

------------------------------------------------------------------------------
Register Now & Save for Velocity, the Web Performance & Operations 
Conference from O'Reilly Media. Velocity features a full day of 
expert-led, hands-on workshops and two days of sessions from industry 
leaders in dedicated Performance & Operations tracks. Use code vel09scf 
and Save an extra 15% before 5/3. http://p.sf.net/sfu/velocityconf

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

* Re: [RFC] generic iMX-spi driver
  2009-04-30 21:44                       ` Guennadi Liakhovetski
@ 2009-04-30 21:49                         ` Russell King - ARM Linux
       [not found]                         ` <Pine.LNX.4.64.0904302343470.9542-0199iw4Nj15frtckUFj5Ag@public.gmane.org>
  1 sibling, 0 replies; 13+ messages in thread
From: Russell King - ARM Linux @ 2009-04-30 21:49 UTC (permalink / raw)
  To: Guennadi Liakhovetski
  Cc: Wolfram Sang, Holger Schurig, linux-arm-kernel, spi-devel-general

On Thu, Apr 30, 2009 at 11:44:43PM +0200, Guennadi Liakhovetski wrote:
> what's the state of this patch? Is a new revision planned soon to go in 
> for 2.6.31?

No idea, as far as I can see after my last comments, it's dead.

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ:        http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette:  http://www.arm.linux.org.uk/mailinglists/etiquette.php

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

* Re: [RFC] generic iMX-spi driver
       [not found]                         ` <Pine.LNX.4.64.0904302343470.9542-0199iw4Nj15frtckUFj5Ag@public.gmane.org>
@ 2009-05-04 16:29                           ` Sascha Hauer
  0 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2009-05-04 16:29 UTC (permalink / raw)
  To: Guennadi Liakhovetski
  Cc: Holger Schurig,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Russell King - ARM Linux,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW

Hi Guennadi,

On Thu, Apr 30, 2009 at 11:44:43PM +0200, Guennadi Liakhovetski wrote:
> Hi,
> 
> what's the state of this patch? Is a new revision planned soon to go in 
> for 2.6.31?

I'm currently working on pimping the Freescale driver and so far it
looks much better and more flexible than the in Kernel driver. I'll post
a patch later this evening.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

------------------------------------------------------------------------------
Register Now & Save for Velocity, the Web Performance & Operations 
Conference from O'Reilly Media. Velocity features a full day of 
expert-led, hands-on workshops and two days of sessions from industry 
leaders in dedicated Performance & Operations tracks. Use code vel09scf 
and Save an extra 15% before 5/3. http://p.sf.net/sfu/velocityconf

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

end of thread, other threads:[~2009-05-04 16:29 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-02-20 14:41 [RFC] generic iMX-spi driver Wolfram Sang
     [not found] ` <20090220144126.GA9203-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-02-20 14:58   ` Wolfram Sang
2009-02-20 15:41   ` Holger Schurig
     [not found]     ` <200902201641.21168.hs4233-x6+DxXLjN1AJvtFkdXX2Hg4jNU5vUVPG@public.gmane.org>
2009-02-26 10:38       ` Wolfram Sang
     [not found]         ` <20090226103844.GB3058-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-02-26 23:26           ` Russell King - ARM Linux
     [not found]             ` <20090226232639.GF5811-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
2009-02-27 10:38               ` Wolfram Sang
     [not found]                 ` <20090227103840.GC3481-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-03-02 20:58                   ` Russell King - ARM Linux
     [not found]                     ` <20090302205826.GG25699-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
2009-04-30 21:44                       ` Guennadi Liakhovetski
2009-04-30 21:49                         ` Russell King - ARM Linux
     [not found]                         ` <Pine.LNX.4.64.0904302343470.9542-0199iw4Nj15frtckUFj5Ag@public.gmane.org>
2009-05-04 16:29                           ` Sascha Hauer
2009-02-23  8:57 ` Paulius Zaleckas
     [not found]   ` <49A264DE.8080805-Ft0m5Q12RQ9xBelEqimL3w@public.gmane.org>
2009-02-26  9:58     ` Wolfram Sang
     [not found]       ` <20090226095825.GA3058-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-02-26 10:07         ` Paulius Zaleckas

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