linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/7] refactor spi_mpc8xxx.c and add eSPI controller support
@ 2010-09-30  8:00 Mingkai Hu
  2010-09-30  8:00 ` [PATCH v3 1/7] spi/mpc8xxx: rename spi_mpc8xxx.c to spi_fsl_spi.c Mingkai Hu
  0 siblings, 1 reply; 23+ messages in thread
From: Mingkai Hu @ 2010-09-30  8:00 UTC (permalink / raw)
  To: linuxppc-dev, spi-devel-general, linux-mtd; +Cc: kumar.gala

This patchset refactor the file spi_mpc8xxx.c to abstract some common 
code as a lib used by the SPI/eSPI controller driver, move the SPI 
controller driver code to spi_fsl_spi.c, and add the eSPI controller 
support with spi_fsl_espi.c.

Tested on P4080DS and MPC8536DS board based on latest Linux tree.

v3 main changes:
 - Update to the latest kernel base.
 - Change the file spi_mpc8xxx.c to spi_fsl_fsl.c verbatim.
 - Add the SPI flash partition code to the m25p80 probe function.
 - Add a quirks for SPI master to handle the contrains of the controller.

[PATCH v3 1/7] spi/mpc8xxx: rename spi_mpc8xxx.c to spi_fsl_spi.c
[PATCH v3 2/7] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
[PATCH v3 3/7] eSPI: add eSPI controller support
[PATCH v3 4/7] powerpc/of: add eSPI controller dts bindings and DTS modification
[PATCH v3 5/7] mtd: m25p80: add support to parse the SPI flash's partitions
[PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
[PATCH v3 7/7] DTS: add fsl,spi-quirk-trans-len-limit property

Thanks,
Mingkai

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

* [PATCH v3 1/7] spi/mpc8xxx: rename spi_mpc8xxx.c to spi_fsl_spi.c
  2010-09-30  8:00 [PATCH v3 0/7] refactor spi_mpc8xxx.c and add eSPI controller support Mingkai Hu
@ 2010-09-30  8:00 ` Mingkai Hu
  2010-09-30  8:00   ` [PATCH v3 2/7] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Mingkai Hu
  0 siblings, 1 reply; 23+ messages in thread
From: Mingkai Hu @ 2010-09-30  8:00 UTC (permalink / raw)
  To: linuxppc-dev, spi-devel-general, linux-mtd; +Cc: kumar.gala, Mingkai Hu

This will pave the way to refactor out the common code which can be used
by the eSPI controller driver, and rename the SPI controller dirver to the
file spi_fsl_spi.c.

Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
---
v3:
 - Update to the latest Kernel base.
 - Rename from spi_mpc8xxx.c to spi_fsl_fsl.c verbatim.

 drivers/spi/Kconfig       |    9 +-
 drivers/spi/Makefile      |    2 +-
 drivers/spi/spi_fsl_spi.c | 1419 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/spi_mpc8xxx.c | 1419 ---------------------------------------------
 4 files changed, 1425 insertions(+), 1424 deletions(-)
 create mode 100644 drivers/spi/spi_fsl_spi.c
 delete mode 100644 drivers/spi/spi_mpc8xxx.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 91c2f4f..6af34c6 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -182,12 +182,13 @@ config SPI_MPC512x_PSC
 	  This enables using the Freescale MPC5121 Programmable Serial
 	  Controller in SPI master mode.
 
-config SPI_MPC8xxx
-	tristate "Freescale MPC8xxx SPI controller"
+config SPI_FSL_SPI
+	tristate "Freescale SPI controller"
 	depends on FSL_SOC
 	help
-	  This enables using the Freescale MPC8xxx SPI controllers in master
-	  mode.
+	  This enables using the Freescale SPI controllers in master mode.
+	  MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
+	  MPC8569 uses the controller in QE mode, MPC8610 in cpu mode.
 
 config SPI_OMAP_UWIRE
 	tristate "OMAP1 MicroWire"
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index e9cbd18..770817c 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -34,7 +34,7 @@ obj-$(CONFIG_SPI_PL022)			+= amba-pl022.o
 obj-$(CONFIG_SPI_MPC512x_PSC)		+= mpc512x_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx)		+= mpc52xx_spi.o
-obj-$(CONFIG_SPI_MPC8xxx)		+= spi_mpc8xxx.o
+obj-$(CONFIG_SPI_FSL_SPI)		+= spi_fsl_spi.o
 obj-$(CONFIG_SPI_PPC4xx)		+= spi_ppc4xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx_hw.o
diff --git a/drivers/spi/spi_fsl_spi.c b/drivers/spi/spi_fsl_spi.c
new file mode 100644
index 0000000..d31b57f
--- /dev/null
+++ b/drivers/spi/spi_fsl_spi.c
@@ -0,0 +1,1419 @@
+/*
+ * MPC8xxx SPI controller driver.
+ *
+ * Maintainer: Kumar Gala
+ *
+ * Copyright (C) 2006 Polycom, Inc.
+ *
+ * CPM SPI and QE buffer descriptors mode support:
+ * Copyright (c) 2009  MontaVista Software, Inc.
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.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.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+
+#include <sysdev/fsl_soc.h>
+#include <asm/cpm.h>
+#include <asm/qe.h>
+#include <asm/irq.h>
+
+/* CPM1 and CPM2 are mutually exclusive. */
+#ifdef CONFIG_CPM1
+#include <asm/cpm1.h>
+#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_CH_SPI, 0)
+#else
+#include <asm/cpm2.h>
+#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK, 0, 0)
+#endif
+
+/* SPI Controller registers */
+struct mpc8xxx_spi_reg {
+	u8 res1[0x20];
+	__be32 mode;
+	__be32 event;
+	__be32 mask;
+	__be32 command;
+	__be32 transmit;
+	__be32 receive;
+};
+
+/* SPI Controller mode register definitions */
+#define	SPMODE_LOOP		(1 << 30)
+#define	SPMODE_CI_INACTIVEHIGH	(1 << 29)
+#define	SPMODE_CP_BEGIN_EDGECLK	(1 << 28)
+#define	SPMODE_DIV16		(1 << 27)
+#define	SPMODE_REV		(1 << 26)
+#define	SPMODE_MS		(1 << 25)
+#define	SPMODE_ENABLE		(1 << 24)
+#define	SPMODE_LEN(x)		((x) << 20)
+#define	SPMODE_PM(x)		((x) << 16)
+#define	SPMODE_OP		(1 << 14)
+#define	SPMODE_CG(x)		((x) << 7)
+
+/*
+ * Default for SPI Mode:
+ * 	SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
+ */
+#define	SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
+			 SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
+
+/* SPIE register values */
+#define	SPIE_NE		0x00000200	/* Not empty */
+#define	SPIE_NF		0x00000100	/* Not full */
+
+/* SPIM register values */
+#define	SPIM_NE		0x00000200	/* Not empty */
+#define	SPIM_NF		0x00000100	/* Not full */
+
+#define	SPIE_TXB	0x00000200	/* Last char is written to tx fifo */
+#define	SPIE_RXB	0x00000100	/* Last char is written to rx buf */
+
+/* SPCOM register values */
+#define	SPCOM_STR	(1 << 23)	/* Start transmit */
+
+#define	SPI_PRAM_SIZE	0x100
+#define	SPI_MRBLR	((unsigned int)PAGE_SIZE)
+
+/* SPI Controller driver's private data. */
+struct mpc8xxx_spi {
+	struct device *dev;
+	struct mpc8xxx_spi_reg __iomem *base;
+
+	/* rx & tx bufs from the spi_transfer */
+	const void *tx;
+	void *rx;
+
+	int subblock;
+	struct spi_pram __iomem *pram;
+	struct cpm_buf_desc __iomem *tx_bd;
+	struct cpm_buf_desc __iomem *rx_bd;
+
+	struct spi_transfer *xfer_in_progress;
+
+	/* dma addresses for CPM transfers */
+	dma_addr_t tx_dma;
+	dma_addr_t rx_dma;
+	bool map_tx_dma;
+	bool map_rx_dma;
+
+	dma_addr_t dma_dummy_tx;
+	dma_addr_t dma_dummy_rx;
+
+	/* functions to deal with different sized buffers */
+	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
+	u32(*get_tx) (struct mpc8xxx_spi *);
+
+	unsigned int count;
+	unsigned int irq;
+
+	unsigned nsecs;		/* (clock cycle time)/2 */
+
+	u32 spibrg;		/* SPIBRG input clock */
+	u32 rx_shift;		/* RX data reg shift when in qe mode */
+	u32 tx_shift;		/* TX data reg shift when in qe mode */
+
+	unsigned int flags;
+
+	struct workqueue_struct *workqueue;
+	struct work_struct work;
+
+	struct list_head queue;
+	spinlock_t lock;
+
+	struct completion done;
+};
+
+static void *mpc8xxx_dummy_rx;
+static DEFINE_MUTEX(mpc8xxx_dummy_rx_lock);
+static int mpc8xxx_dummy_rx_refcnt;
+
+struct spi_mpc8xxx_cs {
+	/* functions to deal with different sized buffers */
+	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
+	u32 (*get_tx) (struct mpc8xxx_spi *);
+	u32 rx_shift;		/* RX data reg shift when in qe mode */
+	u32 tx_shift;		/* TX data reg shift when in qe mode */
+	u32 hw_mode;		/* Holds HW mode register settings */
+};
+
+static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
+{
+	out_be32(reg, val);
+}
+
+static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
+{
+	return in_be32(reg);
+}
+
+#define MPC83XX_SPI_RX_BUF(type) 					  \
+static									  \
+void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
+{									  \
+	type *rx = mpc8xxx_spi->rx;					  \
+	*rx++ = (type)(data >> mpc8xxx_spi->rx_shift);			  \
+	mpc8xxx_spi->rx = rx;						  \
+}
+
+#define MPC83XX_SPI_TX_BUF(type)				\
+static								\
+u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
+{								\
+	u32 data;						\
+	const type *tx = mpc8xxx_spi->tx;			\
+	if (!tx)						\
+		return 0;					\
+	data = *tx++ << mpc8xxx_spi->tx_shift;			\
+	mpc8xxx_spi->tx = tx;					\
+	return data;						\
+}
+
+MPC83XX_SPI_RX_BUF(u8)
+MPC83XX_SPI_RX_BUF(u16)
+MPC83XX_SPI_RX_BUF(u32)
+MPC83XX_SPI_TX_BUF(u8)
+MPC83XX_SPI_TX_BUF(u16)
+MPC83XX_SPI_TX_BUF(u32)
+
+static void mpc8xxx_spi_change_mode(struct spi_device *spi)
+{
+	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
+	struct spi_mpc8xxx_cs *cs = spi->controller_state;
+	__be32 __iomem *mode = &mspi->base->mode;
+	unsigned long flags;
+
+	if (cs->hw_mode == mpc8xxx_spi_read_reg(mode))
+		return;
+
+	/* Turn off IRQs locally to minimize time that SPI is disabled. */
+	local_irq_save(flags);
+
+	/* Turn off SPI unit prior changing mode */
+	mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE);
+
+	/* When in CPM mode, we need to reinit tx and rx. */
+	if (mspi->flags & SPI_CPM_MODE) {
+		if (mspi->flags & SPI_QE) {
+			qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock,
+				     QE_CR_PROTOCOL_UNSPECIFIED, 0);
+		} else {
+			cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
+			if (mspi->flags & SPI_CPM1) {
+				out_be16(&mspi->pram->rbptr,
+					 in_be16(&mspi->pram->rbase));
+				out_be16(&mspi->pram->tbptr,
+					 in_be16(&mspi->pram->tbase));
+			}
+		}
+	}
+	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
+	local_irq_restore(flags);
+}
+
+static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+	struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
+	bool pol = spi->mode & SPI_CS_HIGH;
+	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
+
+	if (value == BITBANG_CS_INACTIVE) {
+		if (pdata->cs_control)
+			pdata->cs_control(spi, !pol);
+	}
+
+	if (value == BITBANG_CS_ACTIVE) {
+		mpc8xxx_spi->rx_shift = cs->rx_shift;
+		mpc8xxx_spi->tx_shift = cs->tx_shift;
+		mpc8xxx_spi->get_rx = cs->get_rx;
+		mpc8xxx_spi->get_tx = cs->get_tx;
+
+		mpc8xxx_spi_change_mode(spi);
+
+		if (pdata->cs_control)
+			pdata->cs_control(spi, pol);
+	}
+}
+
+static int
+mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
+			   struct spi_device *spi,
+			   struct mpc8xxx_spi *mpc8xxx_spi,
+			   int bits_per_word)
+{
+	cs->rx_shift = 0;
+	cs->tx_shift = 0;
+	if (bits_per_word <= 8) {
+		cs->get_rx = mpc8xxx_spi_rx_buf_u8;
+		cs->get_tx = mpc8xxx_spi_tx_buf_u8;
+		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
+			cs->rx_shift = 16;
+			cs->tx_shift = 24;
+		}
+	} else if (bits_per_word <= 16) {
+		cs->get_rx = mpc8xxx_spi_rx_buf_u16;
+		cs->get_tx = mpc8xxx_spi_tx_buf_u16;
+		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
+			cs->rx_shift = 16;
+			cs->tx_shift = 16;
+		}
+	} else if (bits_per_word <= 32) {
+		cs->get_rx = mpc8xxx_spi_rx_buf_u32;
+		cs->get_tx = mpc8xxx_spi_tx_buf_u32;
+	} else
+		return -EINVAL;
+
+	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE &&
+	    spi->mode & SPI_LSB_FIRST) {
+		cs->tx_shift = 0;
+		if (bits_per_word <= 8)
+			cs->rx_shift = 8;
+		else
+			cs->rx_shift = 0;
+	}
+	mpc8xxx_spi->rx_shift = cs->rx_shift;
+	mpc8xxx_spi->tx_shift = cs->tx_shift;
+	mpc8xxx_spi->get_rx = cs->get_rx;
+	mpc8xxx_spi->get_tx = cs->get_tx;
+
+	return bits_per_word;
+}
+
+static int
+mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
+			  struct spi_device *spi,
+			  int bits_per_word)
+{
+	/* QE uses Little Endian for words > 8
+	 * so transform all words > 8 into 8 bits
+	 * Unfortnatly that doesn't work for LSB so
+	 * reject these for now */
+	/* Note: 32 bits word, LSB works iff
+	 * tfcr/rfcr is set to CPMFCR_GBL */
+	if (spi->mode & SPI_LSB_FIRST &&
+	    bits_per_word > 8)
+		return -EINVAL;
+	if (bits_per_word > 8)
+		return 8; /* pretend its 8 bits */
+	return bits_per_word;
+}
+
+static
+int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	int bits_per_word;
+	u8 pm;
+	u32 hz;
+	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
+
+	mpc8xxx_spi = spi_master_get_devdata(spi->master);
+
+	if (t) {
+		bits_per_word = t->bits_per_word;
+		hz = t->speed_hz;
+	} else {
+		bits_per_word = 0;
+		hz = 0;
+	}
+
+	/* spi_transfer level calls that work per-word */
+	if (!bits_per_word)
+		bits_per_word = spi->bits_per_word;
+
+	/* Make sure its a bit width we support [4..16, 32] */
+	if ((bits_per_word < 4)
+	    || ((bits_per_word > 16) && (bits_per_word != 32)))
+		return -EINVAL;
+
+	if (!hz)
+		hz = spi->max_speed_hz;
+
+	if (!(mpc8xxx_spi->flags & SPI_CPM_MODE))
+		bits_per_word = mspi_apply_cpu_mode_quirks(cs, spi,
+							   mpc8xxx_spi,
+							   bits_per_word);
+	else if (mpc8xxx_spi->flags & SPI_QE)
+		bits_per_word = mspi_apply_qe_mode_quirks(cs, spi,
+							  bits_per_word);
+
+	if (bits_per_word < 0)
+		return bits_per_word;
+
+	if (bits_per_word == 32)
+		bits_per_word = 0;
+	else
+		bits_per_word = bits_per_word - 1;
+
+	/* mask out bits we are going to set */
+	cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16
+				  | SPMODE_PM(0xF));
+
+	cs->hw_mode |= SPMODE_LEN(bits_per_word);
+
+	if ((mpc8xxx_spi->spibrg / hz) > 64) {
+		cs->hw_mode |= SPMODE_DIV16;
+		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
+
+		WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
+			  "Will use %d Hz instead.\n", dev_name(&spi->dev),
+			  hz, mpc8xxx_spi->spibrg / 1024);
+		if (pm > 16)
+			pm = 16;
+	} else
+		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
+	if (pm)
+		pm--;
+
+	cs->hw_mode |= SPMODE_PM(pm);
+
+	mpc8xxx_spi_change_mode(spi);
+	return 0;
+}
+
+static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
+{
+	struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd;
+	struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
+	unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
+	unsigned int xfer_ofs;
+
+	xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
+
+	out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
+	out_be16(&rx_bd->cbd_datlen, 0);
+	out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
+
+	out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
+	out_be16(&tx_bd->cbd_datlen, xfer_len);
+	out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
+				 BD_SC_LAST);
+
+	/* start transfer */
+	mpc8xxx_spi_write_reg(&mspi->base->command, SPCOM_STR);
+}
+
+static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
+				struct spi_transfer *t, bool is_dma_mapped)
+{
+	struct device *dev = mspi->dev;
+
+	if (is_dma_mapped) {
+		mspi->map_tx_dma = 0;
+		mspi->map_rx_dma = 0;
+	} else {
+		mspi->map_tx_dma = 1;
+		mspi->map_rx_dma = 1;
+	}
+
+	if (!t->tx_buf) {
+		mspi->tx_dma = mspi->dma_dummy_tx;
+		mspi->map_tx_dma = 0;
+	}
+
+	if (!t->rx_buf) {
+		mspi->rx_dma = mspi->dma_dummy_rx;
+		mspi->map_rx_dma = 0;
+	}
+
+	if (mspi->map_tx_dma) {
+		void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */
+
+		mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len,
+					      DMA_TO_DEVICE);
+		if (dma_mapping_error(dev, mspi->tx_dma)) {
+			dev_err(dev, "unable to map tx dma\n");
+			return -ENOMEM;
+		}
+	} else if (t->tx_buf) {
+		mspi->tx_dma = t->tx_dma;
+	}
+
+	if (mspi->map_rx_dma) {
+		mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len,
+					      DMA_FROM_DEVICE);
+		if (dma_mapping_error(dev, mspi->rx_dma)) {
+			dev_err(dev, "unable to map rx dma\n");
+			goto err_rx_dma;
+		}
+	} else if (t->rx_buf) {
+		mspi->rx_dma = t->rx_dma;
+	}
+
+	/* enable rx ints */
+	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIE_RXB);
+
+	mspi->xfer_in_progress = t;
+	mspi->count = t->len;
+
+	/* start CPM transfers */
+	mpc8xxx_spi_cpm_bufs_start(mspi);
+
+	return 0;
+
+err_rx_dma:
+	if (mspi->map_tx_dma)
+		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
+	return -ENOMEM;
+}
+
+static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
+{
+	struct device *dev = mspi->dev;
+	struct spi_transfer *t = mspi->xfer_in_progress;
+
+	if (mspi->map_tx_dma)
+		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
+	if (mspi->map_rx_dma)
+		dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
+	mspi->xfer_in_progress = NULL;
+}
+
+static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
+				struct spi_transfer *t, unsigned int len)
+{
+	u32 word;
+
+	mspi->count = len;
+
+	/* enable rx ints */
+	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIM_NE);
+
+	/* transmit word */
+	word = mspi->get_tx(mspi);
+	mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
+
+	return 0;
+}
+
+static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
+			    bool is_dma_mapped)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+	unsigned int len = t->len;
+	u8 bits_per_word;
+	int ret;
+
+	bits_per_word = spi->bits_per_word;
+	if (t->bits_per_word)
+		bits_per_word = t->bits_per_word;
+
+	if (bits_per_word > 8) {
+		/* invalid length? */
+		if (len & 1)
+			return -EINVAL;
+		len /= 2;
+	}
+	if (bits_per_word > 16) {
+		/* invalid length? */
+		if (len & 1)
+			return -EINVAL;
+		len /= 2;
+	}
+
+	mpc8xxx_spi->tx = t->tx_buf;
+	mpc8xxx_spi->rx = t->rx_buf;
+
+	INIT_COMPLETION(mpc8xxx_spi->done);
+
+	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
+		ret = mpc8xxx_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
+	else
+		ret = mpc8xxx_spi_cpu_bufs(mpc8xxx_spi, t, len);
+	if (ret)
+		return ret;
+
+	wait_for_completion(&mpc8xxx_spi->done);
+
+	/* disable rx ints */
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
+
+	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
+		mpc8xxx_spi_cpm_bufs_complete(mpc8xxx_spi);
+
+	return mpc8xxx_spi->count;
+}
+
+static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
+{
+	struct spi_device *spi = m->spi;
+	struct spi_transfer *t;
+	unsigned int cs_change;
+	const int nsecs = 50;
+	int status;
+
+	cs_change = 1;
+	status = 0;
+	list_for_each_entry(t, &m->transfers, transfer_list) {
+		if (t->bits_per_word || t->speed_hz) {
+			/* Don't allow changes if CS is active */
+			status = -EINVAL;
+
+			if (cs_change)
+				status = mpc8xxx_spi_setup_transfer(spi, t);
+			if (status < 0)
+				break;
+		}
+
+		if (cs_change) {
+			mpc8xxx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
+			ndelay(nsecs);
+		}
+		cs_change = t->cs_change;
+		if (t->len)
+			status = mpc8xxx_spi_bufs(spi, t, m->is_dma_mapped);
+		if (status) {
+			status = -EMSGSIZE;
+			break;
+		}
+		m->actual_length += t->len;
+
+		if (t->delay_usecs)
+			udelay(t->delay_usecs);
+
+		if (cs_change) {
+			ndelay(nsecs);
+			mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+			ndelay(nsecs);
+		}
+	}
+
+	m->status = status;
+	m->complete(m->context);
+
+	if (status || !cs_change) {
+		ndelay(nsecs);
+		mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+	}
+
+	mpc8xxx_spi_setup_transfer(spi, NULL);
+}
+
+static void mpc8xxx_spi_work(struct work_struct *work)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
+						       work);
+
+	spin_lock_irq(&mpc8xxx_spi->lock);
+	while (!list_empty(&mpc8xxx_spi->queue)) {
+		struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
+						   struct spi_message, queue);
+
+		list_del_init(&m->queue);
+		spin_unlock_irq(&mpc8xxx_spi->lock);
+
+		mpc8xxx_spi_do_one_msg(m);
+
+		spin_lock_irq(&mpc8xxx_spi->lock);
+	}
+	spin_unlock_irq(&mpc8xxx_spi->lock);
+}
+
+static int mpc8xxx_spi_setup(struct spi_device *spi)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	int retval;
+	u32 hw_mode;
+	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
+
+	if (!spi->max_speed_hz)
+		return -EINVAL;
+
+	if (!cs) {
+		cs = kzalloc(sizeof *cs, GFP_KERNEL);
+		if (!cs)
+			return -ENOMEM;
+		spi->controller_state = cs;
+	}
+	mpc8xxx_spi = spi_master_get_devdata(spi->master);
+
+	hw_mode = cs->hw_mode; /* Save original settings */
+	cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
+	/* mask out bits we are going to set */
+	cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
+			 | SPMODE_REV | SPMODE_LOOP);
+
+	if (spi->mode & SPI_CPHA)
+		cs->hw_mode |= SPMODE_CP_BEGIN_EDGECLK;
+	if (spi->mode & SPI_CPOL)
+		cs->hw_mode |= SPMODE_CI_INACTIVEHIGH;
+	if (!(spi->mode & SPI_LSB_FIRST))
+		cs->hw_mode |= SPMODE_REV;
+	if (spi->mode & SPI_LOOP)
+		cs->hw_mode |= SPMODE_LOOP;
+
+	retval = mpc8xxx_spi_setup_transfer(spi, NULL);
+	if (retval < 0) {
+		cs->hw_mode = hw_mode; /* Restore settings */
+		return retval;
+	}
+	return 0;
+}
+
+static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
+{
+	u16 len;
+
+	dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
+		in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
+
+	len = in_be16(&mspi->rx_bd->cbd_datlen);
+	if (len > mspi->count) {
+		WARN_ON(1);
+		len = mspi->count;
+	}
+
+	/* Clear the events */
+	mpc8xxx_spi_write_reg(&mspi->base->event, events);
+
+	mspi->count -= len;
+	if (mspi->count)
+		mpc8xxx_spi_cpm_bufs_start(mspi);
+	else
+		complete(&mspi->done);
+}
+
+static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
+{
+	/* We need handle RX first */
+	if (events & SPIE_NE) {
+		u32 rx_data = mpc8xxx_spi_read_reg(&mspi->base->receive);
+
+		if (mspi->rx)
+			mspi->get_rx(rx_data, mspi);
+	}
+
+	if ((events & SPIE_NF) == 0)
+		/* spin until TX is done */
+		while (((events =
+			mpc8xxx_spi_read_reg(&mspi->base->event)) &
+						SPIE_NF) == 0)
+			cpu_relax();
+
+	/* Clear the events */
+	mpc8xxx_spi_write_reg(&mspi->base->event, events);
+
+	mspi->count -= 1;
+	if (mspi->count) {
+		u32 word = mspi->get_tx(mspi);
+
+		mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
+	} else {
+		complete(&mspi->done);
+	}
+}
+
+static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
+{
+	struct mpc8xxx_spi *mspi = context_data;
+	irqreturn_t ret = IRQ_NONE;
+	u32 events;
+
+	/* Get interrupt events(tx/rx) */
+	events = mpc8xxx_spi_read_reg(&mspi->base->event);
+	if (events)
+		ret = IRQ_HANDLED;
+
+	dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);
+
+	if (mspi->flags & SPI_CPM_MODE)
+		mpc8xxx_spi_cpm_irq(mspi, events);
+	else
+		mpc8xxx_spi_cpu_irq(mspi, events);
+
+	return ret;
+}
+
+static int mpc8xxx_spi_transfer(struct spi_device *spi,
+				struct spi_message *m)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+	unsigned long flags;
+
+	m->actual_length = 0;
+	m->status = -EINPROGRESS;
+
+	spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
+	list_add_tail(&m->queue, &mpc8xxx_spi->queue);
+	queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
+	spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
+
+	return 0;
+}
+
+
+static void mpc8xxx_spi_cleanup(struct spi_device *spi)
+{
+	kfree(spi->controller_state);
+}
+
+static void *mpc8xxx_spi_alloc_dummy_rx(void)
+{
+	mutex_lock(&mpc8xxx_dummy_rx_lock);
+
+	if (!mpc8xxx_dummy_rx)
+		mpc8xxx_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
+	if (mpc8xxx_dummy_rx)
+		mpc8xxx_dummy_rx_refcnt++;
+
+	mutex_unlock(&mpc8xxx_dummy_rx_lock);
+
+	return mpc8xxx_dummy_rx;
+}
+
+static void mpc8xxx_spi_free_dummy_rx(void)
+{
+	mutex_lock(&mpc8xxx_dummy_rx_lock);
+
+	switch (mpc8xxx_dummy_rx_refcnt) {
+	case 0:
+		WARN_ON(1);
+		break;
+	case 1:
+		kfree(mpc8xxx_dummy_rx);
+		mpc8xxx_dummy_rx = NULL;
+		/* fall through */
+	default:
+		mpc8xxx_dummy_rx_refcnt--;
+		break;
+	}
+
+	mutex_unlock(&mpc8xxx_dummy_rx_lock);
+}
+
+static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
+{
+	struct device *dev = mspi->dev;
+	struct device_node *np = dev->of_node;
+	const u32 *iprop;
+	int size;
+	unsigned long spi_base_ofs;
+	unsigned long pram_ofs = -ENOMEM;
+
+	/* Can't use of_address_to_resource(), QE muram isn't at 0. */
+	iprop = of_get_property(np, "reg", &size);
+
+	/* QE with a fixed pram location? */
+	if (mspi->flags & SPI_QE && iprop && size == sizeof(*iprop) * 4)
+		return cpm_muram_alloc_fixed(iprop[2], SPI_PRAM_SIZE);
+
+	/* QE but with a dynamic pram location? */
+	if (mspi->flags & SPI_QE) {
+		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
+		qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, mspi->subblock,
+				QE_CR_PROTOCOL_UNSPECIFIED, pram_ofs);
+		return pram_ofs;
+	}
+
+	/* CPM1 and CPM2 pram must be at a fixed addr. */
+	if (!iprop || size != sizeof(*iprop) * 4)
+		return -ENOMEM;
+
+	spi_base_ofs = cpm_muram_alloc_fixed(iprop[2], 2);
+	if (IS_ERR_VALUE(spi_base_ofs))
+		return -ENOMEM;
+
+	if (mspi->flags & SPI_CPM2) {
+		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
+		if (!IS_ERR_VALUE(pram_ofs)) {
+			u16 __iomem *spi_base = cpm_muram_addr(spi_base_ofs);
+
+			out_be16(spi_base, pram_ofs);
+		}
+	} else {
+		struct spi_pram __iomem *pram = cpm_muram_addr(spi_base_ofs);
+		u16 rpbase = in_be16(&pram->rpbase);
+
+		/* Microcode relocation patch applied? */
+		if (rpbase)
+			pram_ofs = rpbase;
+		else
+			return spi_base_ofs;
+	}
+
+	cpm_muram_free(spi_base_ofs);
+	return pram_ofs;
+}
+
+static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
+{
+	struct device *dev = mspi->dev;
+	struct device_node *np = dev->of_node;
+	const u32 *iprop;
+	int size;
+	unsigned long pram_ofs;
+	unsigned long bds_ofs;
+
+	if (!(mspi->flags & SPI_CPM_MODE))
+		return 0;
+
+	if (!mpc8xxx_spi_alloc_dummy_rx())
+		return -ENOMEM;
+
+	if (mspi->flags & SPI_QE) {
+		iprop = of_get_property(np, "cell-index", &size);
+		if (iprop && size == sizeof(*iprop))
+			mspi->subblock = *iprop;
+
+		switch (mspi->subblock) {
+		default:
+			dev_warn(dev, "cell-index unspecified, assuming SPI1");
+			/* fall through */
+		case 0:
+			mspi->subblock = QE_CR_SUBBLOCK_SPI1;
+			break;
+		case 1:
+			mspi->subblock = QE_CR_SUBBLOCK_SPI2;
+			break;
+		}
+	}
+
+	pram_ofs = mpc8xxx_spi_cpm_get_pram(mspi);
+	if (IS_ERR_VALUE(pram_ofs)) {
+		dev_err(dev, "can't allocate spi parameter ram\n");
+		goto err_pram;
+	}
+
+	bds_ofs = cpm_muram_alloc(sizeof(*mspi->tx_bd) +
+				  sizeof(*mspi->rx_bd), 8);
+	if (IS_ERR_VALUE(bds_ofs)) {
+		dev_err(dev, "can't allocate bds\n");
+		goto err_bds;
+	}
+
+	mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE,
+					    DMA_TO_DEVICE);
+	if (dma_mapping_error(dev, mspi->dma_dummy_tx)) {
+		dev_err(dev, "unable to map dummy tx buffer\n");
+		goto err_dummy_tx;
+	}
+
+	mspi->dma_dummy_rx = dma_map_single(dev, mpc8xxx_dummy_rx, SPI_MRBLR,
+					    DMA_FROM_DEVICE);
+	if (dma_mapping_error(dev, mspi->dma_dummy_rx)) {
+		dev_err(dev, "unable to map dummy rx buffer\n");
+		goto err_dummy_rx;
+	}
+
+	mspi->pram = cpm_muram_addr(pram_ofs);
+
+	mspi->tx_bd = cpm_muram_addr(bds_ofs);
+	mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
+
+	/* Initialize parameter ram. */
+	out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd));
+	out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd));
+	out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL);
+	out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL);
+	out_be16(&mspi->pram->mrblr, SPI_MRBLR);
+	out_be32(&mspi->pram->rstate, 0);
+	out_be32(&mspi->pram->rdp, 0);
+	out_be16(&mspi->pram->rbptr, 0);
+	out_be16(&mspi->pram->rbc, 0);
+	out_be32(&mspi->pram->rxtmp, 0);
+	out_be32(&mspi->pram->tstate, 0);
+	out_be32(&mspi->pram->tdp, 0);
+	out_be16(&mspi->pram->tbptr, 0);
+	out_be16(&mspi->pram->tbc, 0);
+	out_be32(&mspi->pram->txtmp, 0);
+
+	return 0;
+
+err_dummy_rx:
+	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
+err_dummy_tx:
+	cpm_muram_free(bds_ofs);
+err_bds:
+	cpm_muram_free(pram_ofs);
+err_pram:
+	mpc8xxx_spi_free_dummy_rx();
+	return -ENOMEM;
+}
+
+static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi)
+{
+	struct device *dev = mspi->dev;
+
+	dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
+	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
+	cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
+	cpm_muram_free(cpm_muram_offset(mspi->pram));
+	mpc8xxx_spi_free_dummy_rx();
+}
+
+static const char *mpc8xxx_spi_strmode(unsigned int flags)
+{
+	if (flags & SPI_QE_CPU_MODE) {
+		return "QE CPU";
+	} else if (flags & SPI_CPM_MODE) {
+		if (flags & SPI_QE)
+			return "QE";
+		else if (flags & SPI_CPM2)
+			return "CPM2";
+		else
+			return "CPM1";
+	}
+	return "CPU";
+}
+
+static struct spi_master * __devinit
+mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
+{
+	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct spi_master *master;
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	u32 regval;
+	int ret = 0;
+
+	master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
+	if (master == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	dev_set_drvdata(dev, master);
+
+	/* the spi->mode bits understood by this driver: */
+	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
+			| SPI_LSB_FIRST | SPI_LOOP;
+
+	master->setup = mpc8xxx_spi_setup;
+	master->transfer = mpc8xxx_spi_transfer;
+	master->cleanup = mpc8xxx_spi_cleanup;
+	master->dev.of_node = dev->of_node;
+
+	mpc8xxx_spi = spi_master_get_devdata(master);
+	mpc8xxx_spi->dev = dev;
+	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
+	mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
+	mpc8xxx_spi->flags = pdata->flags;
+	mpc8xxx_spi->spibrg = pdata->sysclk;
+
+	ret = mpc8xxx_spi_cpm_init(mpc8xxx_spi);
+	if (ret)
+		goto err_cpm_init;
+
+	mpc8xxx_spi->rx_shift = 0;
+	mpc8xxx_spi->tx_shift = 0;
+	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
+		mpc8xxx_spi->rx_shift = 16;
+		mpc8xxx_spi->tx_shift = 24;
+	}
+
+	init_completion(&mpc8xxx_spi->done);
+
+	mpc8xxx_spi->base = ioremap(mem->start, resource_size(mem));
+	if (mpc8xxx_spi->base == NULL) {
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	mpc8xxx_spi->irq = irq;
+
+	/* Register for SPI Interrupt */
+	ret = request_irq(mpc8xxx_spi->irq, mpc8xxx_spi_irq,
+			  0, "mpc8xxx_spi", mpc8xxx_spi);
+
+	if (ret != 0)
+		goto unmap_io;
+
+	master->bus_num = pdata->bus_num;
+	master->num_chipselect = pdata->max_chipselect;
+
+	/* SPI controller initializations */
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0);
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0);
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff);
+
+	/* Enable SPI interface */
+	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
+	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
+		regval |= SPMODE_OP;
+
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
+	spin_lock_init(&mpc8xxx_spi->lock);
+	init_completion(&mpc8xxx_spi->done);
+	INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
+	INIT_LIST_HEAD(&mpc8xxx_spi->queue);
+
+	mpc8xxx_spi->workqueue = create_singlethread_workqueue(
+		dev_name(master->dev.parent));
+	if (mpc8xxx_spi->workqueue == NULL) {
+		ret = -EBUSY;
+		goto free_irq;
+	}
+
+	ret = spi_register_master(master);
+	if (ret < 0)
+		goto unreg_master;
+
+	dev_info(dev, "at 0x%p (irq = %d), %s mode\n", mpc8xxx_spi->base,
+		 mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
+
+	return master;
+
+unreg_master:
+	destroy_workqueue(mpc8xxx_spi->workqueue);
+free_irq:
+	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
+unmap_io:
+	iounmap(mpc8xxx_spi->base);
+err_ioremap:
+	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
+err_cpm_init:
+	spi_master_put(master);
+err:
+	return ERR_PTR(ret);
+}
+
+static int __devexit mpc8xxx_spi_remove(struct device *dev)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	struct spi_master *master;
+
+	master = dev_get_drvdata(dev);
+	mpc8xxx_spi = spi_master_get_devdata(master);
+
+	flush_workqueue(mpc8xxx_spi->workqueue);
+	destroy_workqueue(mpc8xxx_spi->workqueue);
+	spi_unregister_master(master);
+
+	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
+	iounmap(mpc8xxx_spi->base);
+	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
+
+	return 0;
+}
+
+struct mpc8xxx_spi_probe_info {
+	struct fsl_spi_platform_data pdata;
+	int *gpios;
+	bool *alow_flags;
+};
+
+static struct mpc8xxx_spi_probe_info *
+to_of_pinfo(struct fsl_spi_platform_data *pdata)
+{
+	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
+}
+
+static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
+{
+	struct device *dev = spi->dev.parent;
+	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
+	u16 cs = spi->chip_select;
+	int gpio = pinfo->gpios[cs];
+	bool alow = pinfo->alow_flags[cs];
+
+	gpio_set_value(gpio, on ^ alow);
+}
+
+static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+	unsigned int ngpios;
+	int i = 0;
+	int ret;
+
+	ngpios = of_gpio_count(np);
+	if (!ngpios) {
+		/*
+		 * SPI w/o chip-select line. One SPI device is still permitted
+		 * though.
+		 */
+		pdata->max_chipselect = 1;
+		return 0;
+	}
+
+	pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
+	if (!pinfo->gpios)
+		return -ENOMEM;
+	memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
+
+	pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
+				    GFP_KERNEL);
+	if (!pinfo->alow_flags) {
+		ret = -ENOMEM;
+		goto err_alloc_flags;
+	}
+
+	for (; i < ngpios; i++) {
+		int gpio;
+		enum of_gpio_flags flags;
+
+		gpio = of_get_gpio_flags(np, i, &flags);
+		if (!gpio_is_valid(gpio)) {
+			dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
+			ret = gpio;
+			goto err_loop;
+		}
+
+		ret = gpio_request(gpio, dev_name(dev));
+		if (ret) {
+			dev_err(dev, "can't request gpio #%d: %d\n", i, ret);
+			goto err_loop;
+		}
+
+		pinfo->gpios[i] = gpio;
+		pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW;
+
+		ret = gpio_direction_output(pinfo->gpios[i],
+					    pinfo->alow_flags[i]);
+		if (ret) {
+			dev_err(dev, "can't set output direction for gpio "
+				"#%d: %d\n", i, ret);
+			goto err_loop;
+		}
+	}
+
+	pdata->max_chipselect = ngpios;
+	pdata->cs_control = mpc8xxx_spi_cs_control;
+
+	return 0;
+
+err_loop:
+	while (i >= 0) {
+		if (gpio_is_valid(pinfo->gpios[i]))
+			gpio_free(pinfo->gpios[i]);
+		i--;
+	}
+
+	kfree(pinfo->alow_flags);
+	pinfo->alow_flags = NULL;
+err_alloc_flags:
+	kfree(pinfo->gpios);
+	pinfo->gpios = NULL;
+	return ret;
+}
+
+static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
+{
+	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+	int i;
+
+	if (!pinfo->gpios)
+		return 0;
+
+	for (i = 0; i < pdata->max_chipselect; i++) {
+		if (gpio_is_valid(pinfo->gpios[i]))
+			gpio_free(pinfo->gpios[i]);
+	}
+
+	kfree(pinfo->gpios);
+	kfree(pinfo->alow_flags);
+	return 0;
+}
+
+static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
+					  const struct of_device_id *ofid)
+{
+	struct device *dev = &ofdev->dev;
+	struct device_node *np = ofdev->dev.of_node;
+	struct mpc8xxx_spi_probe_info *pinfo;
+	struct fsl_spi_platform_data *pdata;
+	struct spi_master *master;
+	struct resource mem;
+	struct resource irq;
+	const void *prop;
+	int ret = -ENOMEM;
+
+	pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+	if (!pinfo)
+		return -ENOMEM;
+
+	pdata = &pinfo->pdata;
+	dev->platform_data = pdata;
+
+	/* Allocate bus num dynamically. */
+	pdata->bus_num = -1;
+
+	/* SPI controller is either clocked from QE or SoC clock. */
+	pdata->sysclk = get_brgfreq();
+	if (pdata->sysclk == -1) {
+		pdata->sysclk = fsl_get_sys_freq();
+		if (pdata->sysclk == -1) {
+			ret = -ENODEV;
+			goto err_clk;
+		}
+	}
+
+	prop = of_get_property(np, "mode", NULL);
+	if (prop && !strcmp(prop, "cpu-qe"))
+		pdata->flags = SPI_QE_CPU_MODE;
+	else if (prop && !strcmp(prop, "qe"))
+		pdata->flags = SPI_CPM_MODE | SPI_QE;
+	else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
+		pdata->flags = SPI_CPM_MODE | SPI_CPM2;
+	else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
+		pdata->flags = SPI_CPM_MODE | SPI_CPM1;
+
+	ret = of_mpc8xxx_spi_get_chipselects(dev);
+	if (ret)
+		goto err;
+
+	ret = of_address_to_resource(np, 0, &mem);
+	if (ret)
+		goto err;
+
+	ret = of_irq_to_resource(np, 0, &irq);
+	if (!ret) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	master = mpc8xxx_spi_probe(dev, &mem, irq.start);
+	if (IS_ERR(master)) {
+		ret = PTR_ERR(master);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	of_mpc8xxx_spi_free_chipselects(dev);
+err_clk:
+	kfree(pinfo);
+	return ret;
+}
+
+static int __devexit of_mpc8xxx_spi_remove(struct platform_device *ofdev)
+{
+	int ret;
+
+	ret = mpc8xxx_spi_remove(&ofdev->dev);
+	if (ret)
+		return ret;
+	of_mpc8xxx_spi_free_chipselects(&ofdev->dev);
+	return 0;
+}
+
+static const struct of_device_id of_mpc8xxx_spi_match[] = {
+	{ .compatible = "fsl,spi" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_mpc8xxx_spi_match);
+
+static struct of_platform_driver of_mpc8xxx_spi_driver = {
+	.driver = {
+		.name = "mpc8xxx_spi",
+		.owner = THIS_MODULE,
+		.of_match_table = of_mpc8xxx_spi_match,
+	},
+	.probe		= of_mpc8xxx_spi_probe,
+	.remove		= __devexit_p(of_mpc8xxx_spi_remove),
+};
+
+#ifdef CONFIG_MPC832x_RDB
+/*
+ * 				XXX XXX XXX
+ * This is "legacy" platform driver, was used by the MPC8323E-RDB boards
+ * only. The driver should go away soon, since newer MPC8323E-RDB's device
+ * tree can work with OpenFirmware driver. But for now we support old trees
+ * as well.
+ */
+static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
+{
+	struct resource *mem;
+	int irq;
+	struct spi_master *master;
+
+	if (!pdev->dev.platform_data)
+		return -EINVAL;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem)
+		return -EINVAL;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0)
+		return -EINVAL;
+
+	master = mpc8xxx_spi_probe(&pdev->dev, mem, irq);
+	if (IS_ERR(master))
+		return PTR_ERR(master);
+	return 0;
+}
+
+static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
+{
+	return mpc8xxx_spi_remove(&pdev->dev);
+}
+
+MODULE_ALIAS("platform:mpc8xxx_spi");
+static struct platform_driver mpc8xxx_spi_driver = {
+	.probe = plat_mpc8xxx_spi_probe,
+	.remove = __devexit_p(plat_mpc8xxx_spi_remove),
+	.driver = {
+		.name = "mpc8xxx_spi",
+		.owner = THIS_MODULE,
+	},
+};
+
+static bool legacy_driver_failed;
+
+static void __init legacy_driver_register(void)
+{
+	legacy_driver_failed = platform_driver_register(&mpc8xxx_spi_driver);
+}
+
+static void __exit legacy_driver_unregister(void)
+{
+	if (legacy_driver_failed)
+		return;
+	platform_driver_unregister(&mpc8xxx_spi_driver);
+}
+#else
+static void __init legacy_driver_register(void) {}
+static void __exit legacy_driver_unregister(void) {}
+#endif /* CONFIG_MPC832x_RDB */
+
+static int __init mpc8xxx_spi_init(void)
+{
+	legacy_driver_register();
+	return of_register_platform_driver(&of_mpc8xxx_spi_driver);
+}
+
+static void __exit mpc8xxx_spi_exit(void)
+{
+	of_unregister_platform_driver(&of_mpc8xxx_spi_driver);
+	legacy_driver_unregister();
+}
+
+module_init(mpc8xxx_spi_init);
+module_exit(mpc8xxx_spi_exit);
+
+MODULE_AUTHOR("Kumar Gala");
+MODULE_DESCRIPTION("Simple MPC8xxx SPI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c
deleted file mode 100644
index d31b57f..0000000
--- a/drivers/spi/spi_mpc8xxx.c
+++ /dev/null
@@ -1,1419 +0,0 @@
-/*
- * MPC8xxx SPI controller driver.
- *
- * Maintainer: Kumar Gala
- *
- * Copyright (C) 2006 Polycom, Inc.
- *
- * CPM SPI and QE buffer descriptors mode support:
- * Copyright (c) 2009  MontaVista Software, Inc.
- * Author: Anton Vorontsov <avorontsov@ru.mvista.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.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/bug.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
-#include <linux/platform_device.h>
-#include <linux/fsl_devices.h>
-#include <linux/dma-mapping.h>
-#include <linux/mm.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/slab.h>
-
-#include <sysdev/fsl_soc.h>
-#include <asm/cpm.h>
-#include <asm/qe.h>
-#include <asm/irq.h>
-
-/* CPM1 and CPM2 are mutually exclusive. */
-#ifdef CONFIG_CPM1
-#include <asm/cpm1.h>
-#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_CH_SPI, 0)
-#else
-#include <asm/cpm2.h>
-#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK, 0, 0)
-#endif
-
-/* SPI Controller registers */
-struct mpc8xxx_spi_reg {
-	u8 res1[0x20];
-	__be32 mode;
-	__be32 event;
-	__be32 mask;
-	__be32 command;
-	__be32 transmit;
-	__be32 receive;
-};
-
-/* SPI Controller mode register definitions */
-#define	SPMODE_LOOP		(1 << 30)
-#define	SPMODE_CI_INACTIVEHIGH	(1 << 29)
-#define	SPMODE_CP_BEGIN_EDGECLK	(1 << 28)
-#define	SPMODE_DIV16		(1 << 27)
-#define	SPMODE_REV		(1 << 26)
-#define	SPMODE_MS		(1 << 25)
-#define	SPMODE_ENABLE		(1 << 24)
-#define	SPMODE_LEN(x)		((x) << 20)
-#define	SPMODE_PM(x)		((x) << 16)
-#define	SPMODE_OP		(1 << 14)
-#define	SPMODE_CG(x)		((x) << 7)
-
-/*
- * Default for SPI Mode:
- * 	SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
- */
-#define	SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
-			 SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
-
-/* SPIE register values */
-#define	SPIE_NE		0x00000200	/* Not empty */
-#define	SPIE_NF		0x00000100	/* Not full */
-
-/* SPIM register values */
-#define	SPIM_NE		0x00000200	/* Not empty */
-#define	SPIM_NF		0x00000100	/* Not full */
-
-#define	SPIE_TXB	0x00000200	/* Last char is written to tx fifo */
-#define	SPIE_RXB	0x00000100	/* Last char is written to rx buf */
-
-/* SPCOM register values */
-#define	SPCOM_STR	(1 << 23)	/* Start transmit */
-
-#define	SPI_PRAM_SIZE	0x100
-#define	SPI_MRBLR	((unsigned int)PAGE_SIZE)
-
-/* SPI Controller driver's private data. */
-struct mpc8xxx_spi {
-	struct device *dev;
-	struct mpc8xxx_spi_reg __iomem *base;
-
-	/* rx & tx bufs from the spi_transfer */
-	const void *tx;
-	void *rx;
-
-	int subblock;
-	struct spi_pram __iomem *pram;
-	struct cpm_buf_desc __iomem *tx_bd;
-	struct cpm_buf_desc __iomem *rx_bd;
-
-	struct spi_transfer *xfer_in_progress;
-
-	/* dma addresses for CPM transfers */
-	dma_addr_t tx_dma;
-	dma_addr_t rx_dma;
-	bool map_tx_dma;
-	bool map_rx_dma;
-
-	dma_addr_t dma_dummy_tx;
-	dma_addr_t dma_dummy_rx;
-
-	/* functions to deal with different sized buffers */
-	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
-	u32(*get_tx) (struct mpc8xxx_spi *);
-
-	unsigned int count;
-	unsigned int irq;
-
-	unsigned nsecs;		/* (clock cycle time)/2 */
-
-	u32 spibrg;		/* SPIBRG input clock */
-	u32 rx_shift;		/* RX data reg shift when in qe mode */
-	u32 tx_shift;		/* TX data reg shift when in qe mode */
-
-	unsigned int flags;
-
-	struct workqueue_struct *workqueue;
-	struct work_struct work;
-
-	struct list_head queue;
-	spinlock_t lock;
-
-	struct completion done;
-};
-
-static void *mpc8xxx_dummy_rx;
-static DEFINE_MUTEX(mpc8xxx_dummy_rx_lock);
-static int mpc8xxx_dummy_rx_refcnt;
-
-struct spi_mpc8xxx_cs {
-	/* functions to deal with different sized buffers */
-	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
-	u32 (*get_tx) (struct mpc8xxx_spi *);
-	u32 rx_shift;		/* RX data reg shift when in qe mode */
-	u32 tx_shift;		/* TX data reg shift when in qe mode */
-	u32 hw_mode;		/* Holds HW mode register settings */
-};
-
-static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
-{
-	out_be32(reg, val);
-}
-
-static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
-{
-	return in_be32(reg);
-}
-
-#define MPC83XX_SPI_RX_BUF(type) 					  \
-static									  \
-void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
-{									  \
-	type *rx = mpc8xxx_spi->rx;					  \
-	*rx++ = (type)(data >> mpc8xxx_spi->rx_shift);			  \
-	mpc8xxx_spi->rx = rx;						  \
-}
-
-#define MPC83XX_SPI_TX_BUF(type)				\
-static								\
-u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
-{								\
-	u32 data;						\
-	const type *tx = mpc8xxx_spi->tx;			\
-	if (!tx)						\
-		return 0;					\
-	data = *tx++ << mpc8xxx_spi->tx_shift;			\
-	mpc8xxx_spi->tx = tx;					\
-	return data;						\
-}
-
-MPC83XX_SPI_RX_BUF(u8)
-MPC83XX_SPI_RX_BUF(u16)
-MPC83XX_SPI_RX_BUF(u32)
-MPC83XX_SPI_TX_BUF(u8)
-MPC83XX_SPI_TX_BUF(u16)
-MPC83XX_SPI_TX_BUF(u32)
-
-static void mpc8xxx_spi_change_mode(struct spi_device *spi)
-{
-	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
-	struct spi_mpc8xxx_cs *cs = spi->controller_state;
-	__be32 __iomem *mode = &mspi->base->mode;
-	unsigned long flags;
-
-	if (cs->hw_mode == mpc8xxx_spi_read_reg(mode))
-		return;
-
-	/* Turn off IRQs locally to minimize time that SPI is disabled. */
-	local_irq_save(flags);
-
-	/* Turn off SPI unit prior changing mode */
-	mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE);
-
-	/* When in CPM mode, we need to reinit tx and rx. */
-	if (mspi->flags & SPI_CPM_MODE) {
-		if (mspi->flags & SPI_QE) {
-			qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock,
-				     QE_CR_PROTOCOL_UNSPECIFIED, 0);
-		} else {
-			cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
-			if (mspi->flags & SPI_CPM1) {
-				out_be16(&mspi->pram->rbptr,
-					 in_be16(&mspi->pram->rbase));
-				out_be16(&mspi->pram->tbptr,
-					 in_be16(&mspi->pram->tbase));
-			}
-		}
-	}
-	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
-	local_irq_restore(flags);
-}
-
-static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
-	struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
-	bool pol = spi->mode & SPI_CS_HIGH;
-	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
-
-	if (value == BITBANG_CS_INACTIVE) {
-		if (pdata->cs_control)
-			pdata->cs_control(spi, !pol);
-	}
-
-	if (value == BITBANG_CS_ACTIVE) {
-		mpc8xxx_spi->rx_shift = cs->rx_shift;
-		mpc8xxx_spi->tx_shift = cs->tx_shift;
-		mpc8xxx_spi->get_rx = cs->get_rx;
-		mpc8xxx_spi->get_tx = cs->get_tx;
-
-		mpc8xxx_spi_change_mode(spi);
-
-		if (pdata->cs_control)
-			pdata->cs_control(spi, pol);
-	}
-}
-
-static int
-mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
-			   struct spi_device *spi,
-			   struct mpc8xxx_spi *mpc8xxx_spi,
-			   int bits_per_word)
-{
-	cs->rx_shift = 0;
-	cs->tx_shift = 0;
-	if (bits_per_word <= 8) {
-		cs->get_rx = mpc8xxx_spi_rx_buf_u8;
-		cs->get_tx = mpc8xxx_spi_tx_buf_u8;
-		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
-			cs->rx_shift = 16;
-			cs->tx_shift = 24;
-		}
-	} else if (bits_per_word <= 16) {
-		cs->get_rx = mpc8xxx_spi_rx_buf_u16;
-		cs->get_tx = mpc8xxx_spi_tx_buf_u16;
-		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
-			cs->rx_shift = 16;
-			cs->tx_shift = 16;
-		}
-	} else if (bits_per_word <= 32) {
-		cs->get_rx = mpc8xxx_spi_rx_buf_u32;
-		cs->get_tx = mpc8xxx_spi_tx_buf_u32;
-	} else
-		return -EINVAL;
-
-	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE &&
-	    spi->mode & SPI_LSB_FIRST) {
-		cs->tx_shift = 0;
-		if (bits_per_word <= 8)
-			cs->rx_shift = 8;
-		else
-			cs->rx_shift = 0;
-	}
-	mpc8xxx_spi->rx_shift = cs->rx_shift;
-	mpc8xxx_spi->tx_shift = cs->tx_shift;
-	mpc8xxx_spi->get_rx = cs->get_rx;
-	mpc8xxx_spi->get_tx = cs->get_tx;
-
-	return bits_per_word;
-}
-
-static int
-mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
-			  struct spi_device *spi,
-			  int bits_per_word)
-{
-	/* QE uses Little Endian for words > 8
-	 * so transform all words > 8 into 8 bits
-	 * Unfortnatly that doesn't work for LSB so
-	 * reject these for now */
-	/* Note: 32 bits word, LSB works iff
-	 * tfcr/rfcr is set to CPMFCR_GBL */
-	if (spi->mode & SPI_LSB_FIRST &&
-	    bits_per_word > 8)
-		return -EINVAL;
-	if (bits_per_word > 8)
-		return 8; /* pretend its 8 bits */
-	return bits_per_word;
-}
-
-static
-int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi;
-	int bits_per_word;
-	u8 pm;
-	u32 hz;
-	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
-
-	mpc8xxx_spi = spi_master_get_devdata(spi->master);
-
-	if (t) {
-		bits_per_word = t->bits_per_word;
-		hz = t->speed_hz;
-	} else {
-		bits_per_word = 0;
-		hz = 0;
-	}
-
-	/* spi_transfer level calls that work per-word */
-	if (!bits_per_word)
-		bits_per_word = spi->bits_per_word;
-
-	/* Make sure its a bit width we support [4..16, 32] */
-	if ((bits_per_word < 4)
-	    || ((bits_per_word > 16) && (bits_per_word != 32)))
-		return -EINVAL;
-
-	if (!hz)
-		hz = spi->max_speed_hz;
-
-	if (!(mpc8xxx_spi->flags & SPI_CPM_MODE))
-		bits_per_word = mspi_apply_cpu_mode_quirks(cs, spi,
-							   mpc8xxx_spi,
-							   bits_per_word);
-	else if (mpc8xxx_spi->flags & SPI_QE)
-		bits_per_word = mspi_apply_qe_mode_quirks(cs, spi,
-							  bits_per_word);
-
-	if (bits_per_word < 0)
-		return bits_per_word;
-
-	if (bits_per_word == 32)
-		bits_per_word = 0;
-	else
-		bits_per_word = bits_per_word - 1;
-
-	/* mask out bits we are going to set */
-	cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16
-				  | SPMODE_PM(0xF));
-
-	cs->hw_mode |= SPMODE_LEN(bits_per_word);
-
-	if ((mpc8xxx_spi->spibrg / hz) > 64) {
-		cs->hw_mode |= SPMODE_DIV16;
-		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
-
-		WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
-			  "Will use %d Hz instead.\n", dev_name(&spi->dev),
-			  hz, mpc8xxx_spi->spibrg / 1024);
-		if (pm > 16)
-			pm = 16;
-	} else
-		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
-	if (pm)
-		pm--;
-
-	cs->hw_mode |= SPMODE_PM(pm);
-
-	mpc8xxx_spi_change_mode(spi);
-	return 0;
-}
-
-static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
-{
-	struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd;
-	struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
-	unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
-	unsigned int xfer_ofs;
-
-	xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
-
-	out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
-	out_be16(&rx_bd->cbd_datlen, 0);
-	out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
-
-	out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
-	out_be16(&tx_bd->cbd_datlen, xfer_len);
-	out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
-				 BD_SC_LAST);
-
-	/* start transfer */
-	mpc8xxx_spi_write_reg(&mspi->base->command, SPCOM_STR);
-}
-
-static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
-				struct spi_transfer *t, bool is_dma_mapped)
-{
-	struct device *dev = mspi->dev;
-
-	if (is_dma_mapped) {
-		mspi->map_tx_dma = 0;
-		mspi->map_rx_dma = 0;
-	} else {
-		mspi->map_tx_dma = 1;
-		mspi->map_rx_dma = 1;
-	}
-
-	if (!t->tx_buf) {
-		mspi->tx_dma = mspi->dma_dummy_tx;
-		mspi->map_tx_dma = 0;
-	}
-
-	if (!t->rx_buf) {
-		mspi->rx_dma = mspi->dma_dummy_rx;
-		mspi->map_rx_dma = 0;
-	}
-
-	if (mspi->map_tx_dma) {
-		void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */
-
-		mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len,
-					      DMA_TO_DEVICE);
-		if (dma_mapping_error(dev, mspi->tx_dma)) {
-			dev_err(dev, "unable to map tx dma\n");
-			return -ENOMEM;
-		}
-	} else if (t->tx_buf) {
-		mspi->tx_dma = t->tx_dma;
-	}
-
-	if (mspi->map_rx_dma) {
-		mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len,
-					      DMA_FROM_DEVICE);
-		if (dma_mapping_error(dev, mspi->rx_dma)) {
-			dev_err(dev, "unable to map rx dma\n");
-			goto err_rx_dma;
-		}
-	} else if (t->rx_buf) {
-		mspi->rx_dma = t->rx_dma;
-	}
-
-	/* enable rx ints */
-	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIE_RXB);
-
-	mspi->xfer_in_progress = t;
-	mspi->count = t->len;
-
-	/* start CPM transfers */
-	mpc8xxx_spi_cpm_bufs_start(mspi);
-
-	return 0;
-
-err_rx_dma:
-	if (mspi->map_tx_dma)
-		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
-	return -ENOMEM;
-}
-
-static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
-{
-	struct device *dev = mspi->dev;
-	struct spi_transfer *t = mspi->xfer_in_progress;
-
-	if (mspi->map_tx_dma)
-		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
-	if (mspi->map_rx_dma)
-		dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
-	mspi->xfer_in_progress = NULL;
-}
-
-static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
-				struct spi_transfer *t, unsigned int len)
-{
-	u32 word;
-
-	mspi->count = len;
-
-	/* enable rx ints */
-	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIM_NE);
-
-	/* transmit word */
-	word = mspi->get_tx(mspi);
-	mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
-
-	return 0;
-}
-
-static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
-			    bool is_dma_mapped)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
-	unsigned int len = t->len;
-	u8 bits_per_word;
-	int ret;
-
-	bits_per_word = spi->bits_per_word;
-	if (t->bits_per_word)
-		bits_per_word = t->bits_per_word;
-
-	if (bits_per_word > 8) {
-		/* invalid length? */
-		if (len & 1)
-			return -EINVAL;
-		len /= 2;
-	}
-	if (bits_per_word > 16) {
-		/* invalid length? */
-		if (len & 1)
-			return -EINVAL;
-		len /= 2;
-	}
-
-	mpc8xxx_spi->tx = t->tx_buf;
-	mpc8xxx_spi->rx = t->rx_buf;
-
-	INIT_COMPLETION(mpc8xxx_spi->done);
-
-	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
-		ret = mpc8xxx_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
-	else
-		ret = mpc8xxx_spi_cpu_bufs(mpc8xxx_spi, t, len);
-	if (ret)
-		return ret;
-
-	wait_for_completion(&mpc8xxx_spi->done);
-
-	/* disable rx ints */
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
-
-	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
-		mpc8xxx_spi_cpm_bufs_complete(mpc8xxx_spi);
-
-	return mpc8xxx_spi->count;
-}
-
-static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
-{
-	struct spi_device *spi = m->spi;
-	struct spi_transfer *t;
-	unsigned int cs_change;
-	const int nsecs = 50;
-	int status;
-
-	cs_change = 1;
-	status = 0;
-	list_for_each_entry(t, &m->transfers, transfer_list) {
-		if (t->bits_per_word || t->speed_hz) {
-			/* Don't allow changes if CS is active */
-			status = -EINVAL;
-
-			if (cs_change)
-				status = mpc8xxx_spi_setup_transfer(spi, t);
-			if (status < 0)
-				break;
-		}
-
-		if (cs_change) {
-			mpc8xxx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
-			ndelay(nsecs);
-		}
-		cs_change = t->cs_change;
-		if (t->len)
-			status = mpc8xxx_spi_bufs(spi, t, m->is_dma_mapped);
-		if (status) {
-			status = -EMSGSIZE;
-			break;
-		}
-		m->actual_length += t->len;
-
-		if (t->delay_usecs)
-			udelay(t->delay_usecs);
-
-		if (cs_change) {
-			ndelay(nsecs);
-			mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
-			ndelay(nsecs);
-		}
-	}
-
-	m->status = status;
-	m->complete(m->context);
-
-	if (status || !cs_change) {
-		ndelay(nsecs);
-		mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
-	}
-
-	mpc8xxx_spi_setup_transfer(spi, NULL);
-}
-
-static void mpc8xxx_spi_work(struct work_struct *work)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
-						       work);
-
-	spin_lock_irq(&mpc8xxx_spi->lock);
-	while (!list_empty(&mpc8xxx_spi->queue)) {
-		struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
-						   struct spi_message, queue);
-
-		list_del_init(&m->queue);
-		spin_unlock_irq(&mpc8xxx_spi->lock);
-
-		mpc8xxx_spi_do_one_msg(m);
-
-		spin_lock_irq(&mpc8xxx_spi->lock);
-	}
-	spin_unlock_irq(&mpc8xxx_spi->lock);
-}
-
-static int mpc8xxx_spi_setup(struct spi_device *spi)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi;
-	int retval;
-	u32 hw_mode;
-	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
-
-	if (!spi->max_speed_hz)
-		return -EINVAL;
-
-	if (!cs) {
-		cs = kzalloc(sizeof *cs, GFP_KERNEL);
-		if (!cs)
-			return -ENOMEM;
-		spi->controller_state = cs;
-	}
-	mpc8xxx_spi = spi_master_get_devdata(spi->master);
-
-	hw_mode = cs->hw_mode; /* Save original settings */
-	cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
-	/* mask out bits we are going to set */
-	cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
-			 | SPMODE_REV | SPMODE_LOOP);
-
-	if (spi->mode & SPI_CPHA)
-		cs->hw_mode |= SPMODE_CP_BEGIN_EDGECLK;
-	if (spi->mode & SPI_CPOL)
-		cs->hw_mode |= SPMODE_CI_INACTIVEHIGH;
-	if (!(spi->mode & SPI_LSB_FIRST))
-		cs->hw_mode |= SPMODE_REV;
-	if (spi->mode & SPI_LOOP)
-		cs->hw_mode |= SPMODE_LOOP;
-
-	retval = mpc8xxx_spi_setup_transfer(spi, NULL);
-	if (retval < 0) {
-		cs->hw_mode = hw_mode; /* Restore settings */
-		return retval;
-	}
-	return 0;
-}
-
-static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
-{
-	u16 len;
-
-	dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
-		in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
-
-	len = in_be16(&mspi->rx_bd->cbd_datlen);
-	if (len > mspi->count) {
-		WARN_ON(1);
-		len = mspi->count;
-	}
-
-	/* Clear the events */
-	mpc8xxx_spi_write_reg(&mspi->base->event, events);
-
-	mspi->count -= len;
-	if (mspi->count)
-		mpc8xxx_spi_cpm_bufs_start(mspi);
-	else
-		complete(&mspi->done);
-}
-
-static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
-{
-	/* We need handle RX first */
-	if (events & SPIE_NE) {
-		u32 rx_data = mpc8xxx_spi_read_reg(&mspi->base->receive);
-
-		if (mspi->rx)
-			mspi->get_rx(rx_data, mspi);
-	}
-
-	if ((events & SPIE_NF) == 0)
-		/* spin until TX is done */
-		while (((events =
-			mpc8xxx_spi_read_reg(&mspi->base->event)) &
-						SPIE_NF) == 0)
-			cpu_relax();
-
-	/* Clear the events */
-	mpc8xxx_spi_write_reg(&mspi->base->event, events);
-
-	mspi->count -= 1;
-	if (mspi->count) {
-		u32 word = mspi->get_tx(mspi);
-
-		mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
-	} else {
-		complete(&mspi->done);
-	}
-}
-
-static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
-{
-	struct mpc8xxx_spi *mspi = context_data;
-	irqreturn_t ret = IRQ_NONE;
-	u32 events;
-
-	/* Get interrupt events(tx/rx) */
-	events = mpc8xxx_spi_read_reg(&mspi->base->event);
-	if (events)
-		ret = IRQ_HANDLED;
-
-	dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);
-
-	if (mspi->flags & SPI_CPM_MODE)
-		mpc8xxx_spi_cpm_irq(mspi, events);
-	else
-		mpc8xxx_spi_cpu_irq(mspi, events);
-
-	return ret;
-}
-
-static int mpc8xxx_spi_transfer(struct spi_device *spi,
-				struct spi_message *m)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
-	unsigned long flags;
-
-	m->actual_length = 0;
-	m->status = -EINPROGRESS;
-
-	spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
-	list_add_tail(&m->queue, &mpc8xxx_spi->queue);
-	queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
-	spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
-
-	return 0;
-}
-
-
-static void mpc8xxx_spi_cleanup(struct spi_device *spi)
-{
-	kfree(spi->controller_state);
-}
-
-static void *mpc8xxx_spi_alloc_dummy_rx(void)
-{
-	mutex_lock(&mpc8xxx_dummy_rx_lock);
-
-	if (!mpc8xxx_dummy_rx)
-		mpc8xxx_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
-	if (mpc8xxx_dummy_rx)
-		mpc8xxx_dummy_rx_refcnt++;
-
-	mutex_unlock(&mpc8xxx_dummy_rx_lock);
-
-	return mpc8xxx_dummy_rx;
-}
-
-static void mpc8xxx_spi_free_dummy_rx(void)
-{
-	mutex_lock(&mpc8xxx_dummy_rx_lock);
-
-	switch (mpc8xxx_dummy_rx_refcnt) {
-	case 0:
-		WARN_ON(1);
-		break;
-	case 1:
-		kfree(mpc8xxx_dummy_rx);
-		mpc8xxx_dummy_rx = NULL;
-		/* fall through */
-	default:
-		mpc8xxx_dummy_rx_refcnt--;
-		break;
-	}
-
-	mutex_unlock(&mpc8xxx_dummy_rx_lock);
-}
-
-static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
-{
-	struct device *dev = mspi->dev;
-	struct device_node *np = dev->of_node;
-	const u32 *iprop;
-	int size;
-	unsigned long spi_base_ofs;
-	unsigned long pram_ofs = -ENOMEM;
-
-	/* Can't use of_address_to_resource(), QE muram isn't at 0. */
-	iprop = of_get_property(np, "reg", &size);
-
-	/* QE with a fixed pram location? */
-	if (mspi->flags & SPI_QE && iprop && size == sizeof(*iprop) * 4)
-		return cpm_muram_alloc_fixed(iprop[2], SPI_PRAM_SIZE);
-
-	/* QE but with a dynamic pram location? */
-	if (mspi->flags & SPI_QE) {
-		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
-		qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, mspi->subblock,
-				QE_CR_PROTOCOL_UNSPECIFIED, pram_ofs);
-		return pram_ofs;
-	}
-
-	/* CPM1 and CPM2 pram must be at a fixed addr. */
-	if (!iprop || size != sizeof(*iprop) * 4)
-		return -ENOMEM;
-
-	spi_base_ofs = cpm_muram_alloc_fixed(iprop[2], 2);
-	if (IS_ERR_VALUE(spi_base_ofs))
-		return -ENOMEM;
-
-	if (mspi->flags & SPI_CPM2) {
-		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
-		if (!IS_ERR_VALUE(pram_ofs)) {
-			u16 __iomem *spi_base = cpm_muram_addr(spi_base_ofs);
-
-			out_be16(spi_base, pram_ofs);
-		}
-	} else {
-		struct spi_pram __iomem *pram = cpm_muram_addr(spi_base_ofs);
-		u16 rpbase = in_be16(&pram->rpbase);
-
-		/* Microcode relocation patch applied? */
-		if (rpbase)
-			pram_ofs = rpbase;
-		else
-			return spi_base_ofs;
-	}
-
-	cpm_muram_free(spi_base_ofs);
-	return pram_ofs;
-}
-
-static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
-{
-	struct device *dev = mspi->dev;
-	struct device_node *np = dev->of_node;
-	const u32 *iprop;
-	int size;
-	unsigned long pram_ofs;
-	unsigned long bds_ofs;
-
-	if (!(mspi->flags & SPI_CPM_MODE))
-		return 0;
-
-	if (!mpc8xxx_spi_alloc_dummy_rx())
-		return -ENOMEM;
-
-	if (mspi->flags & SPI_QE) {
-		iprop = of_get_property(np, "cell-index", &size);
-		if (iprop && size == sizeof(*iprop))
-			mspi->subblock = *iprop;
-
-		switch (mspi->subblock) {
-		default:
-			dev_warn(dev, "cell-index unspecified, assuming SPI1");
-			/* fall through */
-		case 0:
-			mspi->subblock = QE_CR_SUBBLOCK_SPI1;
-			break;
-		case 1:
-			mspi->subblock = QE_CR_SUBBLOCK_SPI2;
-			break;
-		}
-	}
-
-	pram_ofs = mpc8xxx_spi_cpm_get_pram(mspi);
-	if (IS_ERR_VALUE(pram_ofs)) {
-		dev_err(dev, "can't allocate spi parameter ram\n");
-		goto err_pram;
-	}
-
-	bds_ofs = cpm_muram_alloc(sizeof(*mspi->tx_bd) +
-				  sizeof(*mspi->rx_bd), 8);
-	if (IS_ERR_VALUE(bds_ofs)) {
-		dev_err(dev, "can't allocate bds\n");
-		goto err_bds;
-	}
-
-	mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE,
-					    DMA_TO_DEVICE);
-	if (dma_mapping_error(dev, mspi->dma_dummy_tx)) {
-		dev_err(dev, "unable to map dummy tx buffer\n");
-		goto err_dummy_tx;
-	}
-
-	mspi->dma_dummy_rx = dma_map_single(dev, mpc8xxx_dummy_rx, SPI_MRBLR,
-					    DMA_FROM_DEVICE);
-	if (dma_mapping_error(dev, mspi->dma_dummy_rx)) {
-		dev_err(dev, "unable to map dummy rx buffer\n");
-		goto err_dummy_rx;
-	}
-
-	mspi->pram = cpm_muram_addr(pram_ofs);
-
-	mspi->tx_bd = cpm_muram_addr(bds_ofs);
-	mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
-
-	/* Initialize parameter ram. */
-	out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd));
-	out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd));
-	out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL);
-	out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL);
-	out_be16(&mspi->pram->mrblr, SPI_MRBLR);
-	out_be32(&mspi->pram->rstate, 0);
-	out_be32(&mspi->pram->rdp, 0);
-	out_be16(&mspi->pram->rbptr, 0);
-	out_be16(&mspi->pram->rbc, 0);
-	out_be32(&mspi->pram->rxtmp, 0);
-	out_be32(&mspi->pram->tstate, 0);
-	out_be32(&mspi->pram->tdp, 0);
-	out_be16(&mspi->pram->tbptr, 0);
-	out_be16(&mspi->pram->tbc, 0);
-	out_be32(&mspi->pram->txtmp, 0);
-
-	return 0;
-
-err_dummy_rx:
-	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
-err_dummy_tx:
-	cpm_muram_free(bds_ofs);
-err_bds:
-	cpm_muram_free(pram_ofs);
-err_pram:
-	mpc8xxx_spi_free_dummy_rx();
-	return -ENOMEM;
-}
-
-static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi)
-{
-	struct device *dev = mspi->dev;
-
-	dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
-	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
-	cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
-	cpm_muram_free(cpm_muram_offset(mspi->pram));
-	mpc8xxx_spi_free_dummy_rx();
-}
-
-static const char *mpc8xxx_spi_strmode(unsigned int flags)
-{
-	if (flags & SPI_QE_CPU_MODE) {
-		return "QE CPU";
-	} else if (flags & SPI_CPM_MODE) {
-		if (flags & SPI_QE)
-			return "QE";
-		else if (flags & SPI_CPM2)
-			return "CPM2";
-		else
-			return "CPM1";
-	}
-	return "CPU";
-}
-
-static struct spi_master * __devinit
-mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
-{
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
-	struct spi_master *master;
-	struct mpc8xxx_spi *mpc8xxx_spi;
-	u32 regval;
-	int ret = 0;
-
-	master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
-	if (master == NULL) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	dev_set_drvdata(dev, master);
-
-	/* the spi->mode bits understood by this driver: */
-	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
-			| SPI_LSB_FIRST | SPI_LOOP;
-
-	master->setup = mpc8xxx_spi_setup;
-	master->transfer = mpc8xxx_spi_transfer;
-	master->cleanup = mpc8xxx_spi_cleanup;
-	master->dev.of_node = dev->of_node;
-
-	mpc8xxx_spi = spi_master_get_devdata(master);
-	mpc8xxx_spi->dev = dev;
-	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
-	mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
-	mpc8xxx_spi->flags = pdata->flags;
-	mpc8xxx_spi->spibrg = pdata->sysclk;
-
-	ret = mpc8xxx_spi_cpm_init(mpc8xxx_spi);
-	if (ret)
-		goto err_cpm_init;
-
-	mpc8xxx_spi->rx_shift = 0;
-	mpc8xxx_spi->tx_shift = 0;
-	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
-		mpc8xxx_spi->rx_shift = 16;
-		mpc8xxx_spi->tx_shift = 24;
-	}
-
-	init_completion(&mpc8xxx_spi->done);
-
-	mpc8xxx_spi->base = ioremap(mem->start, resource_size(mem));
-	if (mpc8xxx_spi->base == NULL) {
-		ret = -ENOMEM;
-		goto err_ioremap;
-	}
-
-	mpc8xxx_spi->irq = irq;
-
-	/* Register for SPI Interrupt */
-	ret = request_irq(mpc8xxx_spi->irq, mpc8xxx_spi_irq,
-			  0, "mpc8xxx_spi", mpc8xxx_spi);
-
-	if (ret != 0)
-		goto unmap_io;
-
-	master->bus_num = pdata->bus_num;
-	master->num_chipselect = pdata->max_chipselect;
-
-	/* SPI controller initializations */
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0);
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0);
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff);
-
-	/* Enable SPI interface */
-	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
-	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
-		regval |= SPMODE_OP;
-
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
-	spin_lock_init(&mpc8xxx_spi->lock);
-	init_completion(&mpc8xxx_spi->done);
-	INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
-	INIT_LIST_HEAD(&mpc8xxx_spi->queue);
-
-	mpc8xxx_spi->workqueue = create_singlethread_workqueue(
-		dev_name(master->dev.parent));
-	if (mpc8xxx_spi->workqueue == NULL) {
-		ret = -EBUSY;
-		goto free_irq;
-	}
-
-	ret = spi_register_master(master);
-	if (ret < 0)
-		goto unreg_master;
-
-	dev_info(dev, "at 0x%p (irq = %d), %s mode\n", mpc8xxx_spi->base,
-		 mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
-
-	return master;
-
-unreg_master:
-	destroy_workqueue(mpc8xxx_spi->workqueue);
-free_irq:
-	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
-unmap_io:
-	iounmap(mpc8xxx_spi->base);
-err_ioremap:
-	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
-err_cpm_init:
-	spi_master_put(master);
-err:
-	return ERR_PTR(ret);
-}
-
-static int __devexit mpc8xxx_spi_remove(struct device *dev)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi;
-	struct spi_master *master;
-
-	master = dev_get_drvdata(dev);
-	mpc8xxx_spi = spi_master_get_devdata(master);
-
-	flush_workqueue(mpc8xxx_spi->workqueue);
-	destroy_workqueue(mpc8xxx_spi->workqueue);
-	spi_unregister_master(master);
-
-	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
-	iounmap(mpc8xxx_spi->base);
-	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
-
-	return 0;
-}
-
-struct mpc8xxx_spi_probe_info {
-	struct fsl_spi_platform_data pdata;
-	int *gpios;
-	bool *alow_flags;
-};
-
-static struct mpc8xxx_spi_probe_info *
-to_of_pinfo(struct fsl_spi_platform_data *pdata)
-{
-	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
-}
-
-static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
-{
-	struct device *dev = spi->dev.parent;
-	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
-	u16 cs = spi->chip_select;
-	int gpio = pinfo->gpios[cs];
-	bool alow = pinfo->alow_flags[cs];
-
-	gpio_set_value(gpio, on ^ alow);
-}
-
-static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
-{
-	struct device_node *np = dev->of_node;
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
-	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
-	unsigned int ngpios;
-	int i = 0;
-	int ret;
-
-	ngpios = of_gpio_count(np);
-	if (!ngpios) {
-		/*
-		 * SPI w/o chip-select line. One SPI device is still permitted
-		 * though.
-		 */
-		pdata->max_chipselect = 1;
-		return 0;
-	}
-
-	pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
-	if (!pinfo->gpios)
-		return -ENOMEM;
-	memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
-
-	pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
-				    GFP_KERNEL);
-	if (!pinfo->alow_flags) {
-		ret = -ENOMEM;
-		goto err_alloc_flags;
-	}
-
-	for (; i < ngpios; i++) {
-		int gpio;
-		enum of_gpio_flags flags;
-
-		gpio = of_get_gpio_flags(np, i, &flags);
-		if (!gpio_is_valid(gpio)) {
-			dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
-			ret = gpio;
-			goto err_loop;
-		}
-
-		ret = gpio_request(gpio, dev_name(dev));
-		if (ret) {
-			dev_err(dev, "can't request gpio #%d: %d\n", i, ret);
-			goto err_loop;
-		}
-
-		pinfo->gpios[i] = gpio;
-		pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW;
-
-		ret = gpio_direction_output(pinfo->gpios[i],
-					    pinfo->alow_flags[i]);
-		if (ret) {
-			dev_err(dev, "can't set output direction for gpio "
-				"#%d: %d\n", i, ret);
-			goto err_loop;
-		}
-	}
-
-	pdata->max_chipselect = ngpios;
-	pdata->cs_control = mpc8xxx_spi_cs_control;
-
-	return 0;
-
-err_loop:
-	while (i >= 0) {
-		if (gpio_is_valid(pinfo->gpios[i]))
-			gpio_free(pinfo->gpios[i]);
-		i--;
-	}
-
-	kfree(pinfo->alow_flags);
-	pinfo->alow_flags = NULL;
-err_alloc_flags:
-	kfree(pinfo->gpios);
-	pinfo->gpios = NULL;
-	return ret;
-}
-
-static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
-{
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
-	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
-	int i;
-
-	if (!pinfo->gpios)
-		return 0;
-
-	for (i = 0; i < pdata->max_chipselect; i++) {
-		if (gpio_is_valid(pinfo->gpios[i]))
-			gpio_free(pinfo->gpios[i]);
-	}
-
-	kfree(pinfo->gpios);
-	kfree(pinfo->alow_flags);
-	return 0;
-}
-
-static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
-					  const struct of_device_id *ofid)
-{
-	struct device *dev = &ofdev->dev;
-	struct device_node *np = ofdev->dev.of_node;
-	struct mpc8xxx_spi_probe_info *pinfo;
-	struct fsl_spi_platform_data *pdata;
-	struct spi_master *master;
-	struct resource mem;
-	struct resource irq;
-	const void *prop;
-	int ret = -ENOMEM;
-
-	pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
-	if (!pinfo)
-		return -ENOMEM;
-
-	pdata = &pinfo->pdata;
-	dev->platform_data = pdata;
-
-	/* Allocate bus num dynamically. */
-	pdata->bus_num = -1;
-
-	/* SPI controller is either clocked from QE or SoC clock. */
-	pdata->sysclk = get_brgfreq();
-	if (pdata->sysclk == -1) {
-		pdata->sysclk = fsl_get_sys_freq();
-		if (pdata->sysclk == -1) {
-			ret = -ENODEV;
-			goto err_clk;
-		}
-	}
-
-	prop = of_get_property(np, "mode", NULL);
-	if (prop && !strcmp(prop, "cpu-qe"))
-		pdata->flags = SPI_QE_CPU_MODE;
-	else if (prop && !strcmp(prop, "qe"))
-		pdata->flags = SPI_CPM_MODE | SPI_QE;
-	else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
-		pdata->flags = SPI_CPM_MODE | SPI_CPM2;
-	else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
-		pdata->flags = SPI_CPM_MODE | SPI_CPM1;
-
-	ret = of_mpc8xxx_spi_get_chipselects(dev);
-	if (ret)
-		goto err;
-
-	ret = of_address_to_resource(np, 0, &mem);
-	if (ret)
-		goto err;
-
-	ret = of_irq_to_resource(np, 0, &irq);
-	if (!ret) {
-		ret = -EINVAL;
-		goto err;
-	}
-
-	master = mpc8xxx_spi_probe(dev, &mem, irq.start);
-	if (IS_ERR(master)) {
-		ret = PTR_ERR(master);
-		goto err;
-	}
-
-	return 0;
-
-err:
-	of_mpc8xxx_spi_free_chipselects(dev);
-err_clk:
-	kfree(pinfo);
-	return ret;
-}
-
-static int __devexit of_mpc8xxx_spi_remove(struct platform_device *ofdev)
-{
-	int ret;
-
-	ret = mpc8xxx_spi_remove(&ofdev->dev);
-	if (ret)
-		return ret;
-	of_mpc8xxx_spi_free_chipselects(&ofdev->dev);
-	return 0;
-}
-
-static const struct of_device_id of_mpc8xxx_spi_match[] = {
-	{ .compatible = "fsl,spi" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, of_mpc8xxx_spi_match);
-
-static struct of_platform_driver of_mpc8xxx_spi_driver = {
-	.driver = {
-		.name = "mpc8xxx_spi",
-		.owner = THIS_MODULE,
-		.of_match_table = of_mpc8xxx_spi_match,
-	},
-	.probe		= of_mpc8xxx_spi_probe,
-	.remove		= __devexit_p(of_mpc8xxx_spi_remove),
-};
-
-#ifdef CONFIG_MPC832x_RDB
-/*
- * 				XXX XXX XXX
- * This is "legacy" platform driver, was used by the MPC8323E-RDB boards
- * only. The driver should go away soon, since newer MPC8323E-RDB's device
- * tree can work with OpenFirmware driver. But for now we support old trees
- * as well.
- */
-static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
-{
-	struct resource *mem;
-	int irq;
-	struct spi_master *master;
-
-	if (!pdev->dev.platform_data)
-		return -EINVAL;
-
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem)
-		return -EINVAL;
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0)
-		return -EINVAL;
-
-	master = mpc8xxx_spi_probe(&pdev->dev, mem, irq);
-	if (IS_ERR(master))
-		return PTR_ERR(master);
-	return 0;
-}
-
-static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
-{
-	return mpc8xxx_spi_remove(&pdev->dev);
-}
-
-MODULE_ALIAS("platform:mpc8xxx_spi");
-static struct platform_driver mpc8xxx_spi_driver = {
-	.probe = plat_mpc8xxx_spi_probe,
-	.remove = __devexit_p(plat_mpc8xxx_spi_remove),
-	.driver = {
-		.name = "mpc8xxx_spi",
-		.owner = THIS_MODULE,
-	},
-};
-
-static bool legacy_driver_failed;
-
-static void __init legacy_driver_register(void)
-{
-	legacy_driver_failed = platform_driver_register(&mpc8xxx_spi_driver);
-}
-
-static void __exit legacy_driver_unregister(void)
-{
-	if (legacy_driver_failed)
-		return;
-	platform_driver_unregister(&mpc8xxx_spi_driver);
-}
-#else
-static void __init legacy_driver_register(void) {}
-static void __exit legacy_driver_unregister(void) {}
-#endif /* CONFIG_MPC832x_RDB */
-
-static int __init mpc8xxx_spi_init(void)
-{
-	legacy_driver_register();
-	return of_register_platform_driver(&of_mpc8xxx_spi_driver);
-}
-
-static void __exit mpc8xxx_spi_exit(void)
-{
-	of_unregister_platform_driver(&of_mpc8xxx_spi_driver);
-	legacy_driver_unregister();
-}
-
-module_init(mpc8xxx_spi_init);
-module_exit(mpc8xxx_spi_exit);
-
-MODULE_AUTHOR("Kumar Gala");
-MODULE_DESCRIPTION("Simple MPC8xxx SPI Driver");
-MODULE_LICENSE("GPL");
-- 
1.6.4

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

* [PATCH v3 2/7] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
  2010-09-30  8:00 ` [PATCH v3 1/7] spi/mpc8xxx: rename spi_mpc8xxx.c to spi_fsl_spi.c Mingkai Hu
@ 2010-09-30  8:00   ` Mingkai Hu
  2010-09-30  8:00     ` [PATCH v3 3/7] eSPI: add eSPI controller support Mingkai Hu
  2010-10-01 11:22     ` [PATCH v3 2/7] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Anton Vorontsov
  0 siblings, 2 replies; 23+ messages in thread
From: Mingkai Hu @ 2010-09-30  8:00 UTC (permalink / raw)
  To: linuxppc-dev, spi-devel-general, linux-mtd; +Cc: kumar.gala, Mingkai Hu

Refactor the common code in file spi_fsl_spi.c to spi_fsl_lib.c used
by SPI/eSPI controller driver as a library, and leave the QE/CPM SPI
controller code in the SPI controller driver spi_fsl_spi.c.

Because the register map of the SPI controller and eSPI controller
is so different, also leave the code operated the register to the
driver code, not the common code.

Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
---

v3:
 - Update to the latest kernel base.
 - Add a void *reg_base to compatible for SPI and eSPI register base.

 drivers/spi/Kconfig       |    5 +
 drivers/spi/Makefile      |    1 +
 drivers/spi/spi_fsl_lib.c |  237 +++++++++++++++++++
 drivers/spi/spi_fsl_lib.h |  119 ++++++++++
 drivers/spi/spi_fsl_spi.c |  552 +++++++++++++--------------------------------
 5 files changed, 522 insertions(+), 392 deletions(-)
 create mode 100644 drivers/spi/spi_fsl_lib.c
 create mode 100644 drivers/spi/spi_fsl_lib.h

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 6af34c6..79ad06f 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -182,9 +182,14 @@ config SPI_MPC512x_PSC
 	  This enables using the Freescale MPC5121 Programmable Serial
 	  Controller in SPI master mode.
 
+config SPI_FSL_LIB
+	tristate
+	depends on FSL_SOC
+
 config SPI_FSL_SPI
 	tristate "Freescale SPI controller"
 	depends on FSL_SOC
+	select SPI_FSL_LIB
 	help
 	  This enables using the Freescale SPI controllers in master mode.
 	  MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 770817c..7974c21 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_SPI_PL022)			+= amba-pl022.o
 obj-$(CONFIG_SPI_MPC512x_PSC)		+= mpc512x_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx)		+= mpc52xx_spi.o
+obj-$(CONFIG_SPI_FSL_LIB)		+= spi_fsl_lib.o
 obj-$(CONFIG_SPI_FSL_SPI)		+= spi_fsl_spi.o
 obj-$(CONFIG_SPI_PPC4xx)		+= spi_ppc4xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
diff --git a/drivers/spi/spi_fsl_lib.c b/drivers/spi/spi_fsl_lib.c
new file mode 100644
index 0000000..5cd741f
--- /dev/null
+++ b/drivers/spi/spi_fsl_lib.c
@@ -0,0 +1,237 @@
+/*
+ * Freescale SPI/eSPI controller driver library.
+ *
+ * Maintainer: Kumar Gala
+ *
+ * Copyright (C) 2006 Polycom, Inc.
+ *
+ * CPM SPI and QE buffer descriptors mode support:
+ * Copyright (c) 2009  MontaVista Software, Inc.
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/fsl_devices.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/of_platform.h>
+#include <linux/of_spi.h>
+#include <sysdev/fsl_soc.h>
+
+#include "spi_fsl_lib.h"
+
+#define MPC8XXX_SPI_RX_BUF(type) 					  \
+void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
+{									  \
+	type *rx = mpc8xxx_spi->rx;					  \
+	*rx++ = (type)(data >> mpc8xxx_spi->rx_shift);			  \
+	mpc8xxx_spi->rx = rx;						  \
+}
+
+#define MPC8XXX_SPI_TX_BUF(type)				\
+u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
+{								\
+	u32 data;						\
+	const type *tx = mpc8xxx_spi->tx;			\
+	if (!tx)						\
+		return 0;					\
+	data = *tx++ << mpc8xxx_spi->tx_shift;			\
+	mpc8xxx_spi->tx = tx;					\
+	return data;						\
+}
+
+MPC8XXX_SPI_RX_BUF(u8)
+MPC8XXX_SPI_RX_BUF(u16)
+MPC8XXX_SPI_RX_BUF(u32)
+MPC8XXX_SPI_TX_BUF(u8)
+MPC8XXX_SPI_TX_BUF(u16)
+MPC8XXX_SPI_TX_BUF(u32)
+
+struct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata)
+{
+	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
+}
+
+void mpc8xxx_spi_work(struct work_struct *work)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
+						       work);
+
+	spin_lock_irq(&mpc8xxx_spi->lock);
+	while (!list_empty(&mpc8xxx_spi->queue)) {
+		struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
+						   struct spi_message, queue);
+
+		list_del_init(&m->queue);
+		spin_unlock_irq(&mpc8xxx_spi->lock);
+
+		if (mpc8xxx_spi->spi_do_one_msg)
+			mpc8xxx_spi->spi_do_one_msg(m);
+
+		spin_lock_irq(&mpc8xxx_spi->lock);
+	}
+	spin_unlock_irq(&mpc8xxx_spi->lock);
+}
+
+int mpc8xxx_spi_transfer(struct spi_device *spi,
+				struct spi_message *m)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+	unsigned long flags;
+
+	m->actual_length = 0;
+	m->status = -EINPROGRESS;
+
+	spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
+	list_add_tail(&m->queue, &mpc8xxx_spi->queue);
+	queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
+	spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
+
+	return 0;
+}
+
+void mpc8xxx_spi_cleanup(struct spi_device *spi)
+{
+	kfree(spi->controller_state);
+}
+
+const char *mpc8xxx_spi_strmode(unsigned int flags)
+{
+	if (flags & SPI_QE_CPU_MODE) {
+		return "QE CPU";
+	} else if (flags & SPI_CPM_MODE) {
+		if (flags & SPI_QE)
+			return "QE";
+		else if (flags & SPI_CPM2)
+			return "CPM2";
+		else
+			return "CPM1";
+	}
+	return "CPU";
+}
+
+int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
+			unsigned int irq)
+{
+	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct spi_master *master;
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	int ret = 0;
+
+	master = dev_get_drvdata(dev);
+
+	/* the spi->mode bits understood by this driver: */
+	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
+			| SPI_LSB_FIRST | SPI_LOOP;
+
+	master->transfer = mpc8xxx_spi_transfer;
+	master->cleanup = mpc8xxx_spi_cleanup;
+	master->dev.of_node = dev->of_node;
+
+	mpc8xxx_spi = spi_master_get_devdata(master);
+	mpc8xxx_spi->dev = dev;
+	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
+	mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
+	mpc8xxx_spi->flags = pdata->flags;
+	mpc8xxx_spi->spibrg = pdata->sysclk;
+	mpc8xxx_spi->irq = irq;
+
+	mpc8xxx_spi->rx_shift = 0;
+	mpc8xxx_spi->tx_shift = 0;
+
+	init_completion(&mpc8xxx_spi->done);
+
+	master->bus_num = pdata->bus_num;
+	master->num_chipselect = pdata->max_chipselect;
+
+	spin_lock_init(&mpc8xxx_spi->lock);
+	init_completion(&mpc8xxx_spi->done);
+	INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
+	INIT_LIST_HEAD(&mpc8xxx_spi->queue);
+
+	mpc8xxx_spi->workqueue = create_singlethread_workqueue(
+		dev_name(master->dev.parent));
+	if (mpc8xxx_spi->workqueue == NULL) {
+		ret = -EBUSY;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+}
+
+int __devexit mpc8xxx_spi_remove(struct device *dev)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	struct spi_master *master;
+
+	master = dev_get_drvdata(dev);
+	mpc8xxx_spi = spi_master_get_devdata(master);
+
+	flush_workqueue(mpc8xxx_spi->workqueue);
+	destroy_workqueue(mpc8xxx_spi->workqueue);
+	spi_unregister_master(master);
+
+	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
+
+	if (mpc8xxx_spi->spi_remove)
+		mpc8xxx_spi->spi_remove(mpc8xxx_spi);
+
+	return 0;
+}
+
+int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
+					const struct of_device_id *ofid)
+{
+	struct device *dev = &ofdev->dev;
+	struct device_node *np = ofdev->dev.of_node;
+	struct mpc8xxx_spi_probe_info *pinfo;
+	struct fsl_spi_platform_data *pdata;
+	const void *prop;
+	int ret = -ENOMEM;
+
+	pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+	if (!pinfo)
+		return -ENOMEM;
+
+	pdata = &pinfo->pdata;
+	dev->platform_data = pdata;
+
+	/* Allocate bus num dynamically. */
+	pdata->bus_num = -1;
+
+	/* SPI controller is either clocked from QE or SoC clock. */
+	pdata->sysclk = get_brgfreq();
+	if (pdata->sysclk == -1) {
+		pdata->sysclk = fsl_get_sys_freq();
+		if (pdata->sysclk == -1) {
+			ret = -ENODEV;
+			goto err;
+		}
+	}
+
+	prop = of_get_property(np, "mode", NULL);
+	if (prop && !strcmp(prop, "cpu-qe"))
+		pdata->flags = SPI_QE_CPU_MODE;
+	else if (prop && !strcmp(prop, "qe"))
+		pdata->flags = SPI_CPM_MODE | SPI_QE;
+	else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
+		pdata->flags = SPI_CPM_MODE | SPI_CPM2;
+	else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
+		pdata->flags = SPI_CPM_MODE | SPI_CPM1;
+
+	return 0;
+
+err:
+	kfree(pinfo);
+	return ret;
+}
diff --git a/drivers/spi/spi_fsl_lib.h b/drivers/spi/spi_fsl_lib.h
new file mode 100644
index 0000000..6ae8949
--- /dev/null
+++ b/drivers/spi/spi_fsl_lib.h
@@ -0,0 +1,119 @@
+/*
+ * Freescale SPI/eSPI controller driver library.
+ *
+ * Maintainer: Kumar Gala
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2006 Polycom, Inc.
+ *
+ * CPM SPI and QE buffer descriptors mode support:
+ * Copyright (c) 2009  MontaVista Software, Inc.
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.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.
+ */
+#ifndef __SPI_FSL_LIB_H__
+#define __SPI_FSL_LIB_H__
+
+/* SPI/eSPI Controller driver's private data. */
+struct mpc8xxx_spi {
+	struct device *dev;
+	void *reg_base;
+
+	/* rx & tx bufs from the spi_transfer */
+	const void *tx;
+	void *rx;
+
+	int subblock;
+	struct spi_pram __iomem *pram;
+	struct cpm_buf_desc __iomem *tx_bd;
+	struct cpm_buf_desc __iomem *rx_bd;
+
+	struct spi_transfer *xfer_in_progress;
+
+	/* dma addresses for CPM transfers */
+	dma_addr_t tx_dma;
+	dma_addr_t rx_dma;
+	bool map_tx_dma;
+	bool map_rx_dma;
+
+	dma_addr_t dma_dummy_tx;
+	dma_addr_t dma_dummy_rx;
+
+	/* functions to deal with different sized buffers */
+	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
+	u32(*get_tx) (struct mpc8xxx_spi *);
+
+	/* hooks for different controller driver */
+	void (*spi_do_one_msg) (struct spi_message *m);
+	void (*spi_remove) (struct mpc8xxx_spi *mspi);
+
+	unsigned int count;
+	unsigned int irq;
+
+	unsigned nsecs;		/* (clock cycle time)/2 */
+
+	u32 spibrg;		/* SPIBRG input clock */
+	u32 rx_shift;		/* RX data reg shift when in qe mode */
+	u32 tx_shift;		/* TX data reg shift when in qe mode */
+
+	unsigned int flags;
+
+	struct workqueue_struct *workqueue;
+	struct work_struct work;
+
+	struct list_head queue;
+	spinlock_t lock;
+
+	struct completion done;
+};
+
+struct spi_mpc8xxx_cs {
+	/* functions to deal with different sized buffers */
+	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
+	u32 (*get_tx) (struct mpc8xxx_spi *);
+	u32 rx_shift;		/* RX data reg shift when in qe mode */
+	u32 tx_shift;		/* TX data reg shift when in qe mode */
+	u32 hw_mode;		/* Holds HW mode register settings */
+};
+
+static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
+{
+	out_be32(reg, val);
+}
+
+static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
+{
+	return in_be32(reg);
+}
+
+struct mpc8xxx_spi_probe_info {
+	struct fsl_spi_platform_data pdata;
+	int *gpios;
+	bool *alow_flags;
+};
+
+extern u32 mpc8xxx_spi_tx_buf_u8(struct mpc8xxx_spi *mpc8xxx_spi);
+extern u32 mpc8xxx_spi_tx_buf_u16(struct mpc8xxx_spi *mpc8xxx_spi);
+extern u32 mpc8xxx_spi_tx_buf_u32(struct mpc8xxx_spi *mpc8xxx_spi);
+extern void mpc8xxx_spi_rx_buf_u8(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
+extern void mpc8xxx_spi_rx_buf_u16(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
+extern void mpc8xxx_spi_rx_buf_u32(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
+
+extern struct mpc8xxx_spi_probe_info *to_of_pinfo(
+		struct fsl_spi_platform_data *pdata);
+extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi,
+		struct spi_transfer *t, unsigned int len);
+extern int mpc8xxx_spi_transfer(struct spi_device *spi, struct spi_message *m);
+extern void mpc8xxx_spi_cleanup(struct spi_device *spi);
+extern const char *mpc8xxx_spi_strmode(unsigned int flags);
+extern int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
+		unsigned int irq);
+extern int mpc8xxx_spi_remove(struct device *dev);
+extern int of_mpc8xxx_spi_probe(struct platform_device *ofdev,
+				const struct of_device_id *ofid);
+
+#endif /* __SPI_FSL_LIB_H__ */
diff --git a/drivers/spi/spi_fsl_spi.c b/drivers/spi/spi_fsl_spi.c
index d31b57f..c662e7e 100644
--- a/drivers/spi/spi_fsl_spi.c
+++ b/drivers/spi/spi_fsl_spi.c
@@ -1,9 +1,10 @@
 /*
- * MPC8xxx SPI controller driver.
+ * Freescale SPI controller driver.
  *
  * Maintainer: Kumar Gala
  *
  * Copyright (C) 2006 Polycom, Inc.
+ * Copyright 2010 Freescale Semiconductor, Inc.
  *
  * CPM SPI and QE buffer descriptors mode support:
  * Copyright (c) 2009  MontaVista Software, Inc.
@@ -15,18 +16,11 @@
  * option) any later version.
  */
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/bug.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/completion.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
-#include <linux/device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/platform_device.h>
@@ -38,12 +32,12 @@
 #include <linux/of_platform.h>
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
-#include <linux/slab.h>
 
 #include <sysdev/fsl_soc.h>
 #include <asm/cpm.h>
 #include <asm/qe.h>
-#include <asm/irq.h>
+
+#include "spi_fsl_lib.h"
 
 /* CPM1 and CPM2 are mutually exclusive. */
 #ifdef CONFIG_CPM1
@@ -55,7 +49,7 @@
 #endif
 
 /* SPI Controller registers */
-struct mpc8xxx_spi_reg {
+struct fsl_spi_reg {
 	u8 res1[0x20];
 	__be32 mode;
 	__be32 event;
@@ -80,7 +74,7 @@ struct mpc8xxx_spi_reg {
 
 /*
  * Default for SPI Mode:
- * 	SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
+ *	SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
  */
 #define	SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
 			 SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
@@ -102,112 +96,16 @@ struct mpc8xxx_spi_reg {
 #define	SPI_PRAM_SIZE	0x100
 #define	SPI_MRBLR	((unsigned int)PAGE_SIZE)
 
-/* SPI Controller driver's private data. */
-struct mpc8xxx_spi {
-	struct device *dev;
-	struct mpc8xxx_spi_reg __iomem *base;
-
-	/* rx & tx bufs from the spi_transfer */
-	const void *tx;
-	void *rx;
-
-	int subblock;
-	struct spi_pram __iomem *pram;
-	struct cpm_buf_desc __iomem *tx_bd;
-	struct cpm_buf_desc __iomem *rx_bd;
-
-	struct spi_transfer *xfer_in_progress;
-
-	/* dma addresses for CPM transfers */
-	dma_addr_t tx_dma;
-	dma_addr_t rx_dma;
-	bool map_tx_dma;
-	bool map_rx_dma;
-
-	dma_addr_t dma_dummy_tx;
-	dma_addr_t dma_dummy_rx;
-
-	/* functions to deal with different sized buffers */
-	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
-	u32(*get_tx) (struct mpc8xxx_spi *);
-
-	unsigned int count;
-	unsigned int irq;
-
-	unsigned nsecs;		/* (clock cycle time)/2 */
-
-	u32 spibrg;		/* SPIBRG input clock */
-	u32 rx_shift;		/* RX data reg shift when in qe mode */
-	u32 tx_shift;		/* TX data reg shift when in qe mode */
-
-	unsigned int flags;
-
-	struct workqueue_struct *workqueue;
-	struct work_struct work;
-
-	struct list_head queue;
-	spinlock_t lock;
-
-	struct completion done;
-};
-
-static void *mpc8xxx_dummy_rx;
-static DEFINE_MUTEX(mpc8xxx_dummy_rx_lock);
-static int mpc8xxx_dummy_rx_refcnt;
-
-struct spi_mpc8xxx_cs {
-	/* functions to deal with different sized buffers */
-	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
-	u32 (*get_tx) (struct mpc8xxx_spi *);
-	u32 rx_shift;		/* RX data reg shift when in qe mode */
-	u32 tx_shift;		/* TX data reg shift when in qe mode */
-	u32 hw_mode;		/* Holds HW mode register settings */
-};
-
-static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
-{
-	out_be32(reg, val);
-}
-
-static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
-{
-	return in_be32(reg);
-}
-
-#define MPC83XX_SPI_RX_BUF(type) 					  \
-static									  \
-void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
-{									  \
-	type *rx = mpc8xxx_spi->rx;					  \
-	*rx++ = (type)(data >> mpc8xxx_spi->rx_shift);			  \
-	mpc8xxx_spi->rx = rx;						  \
-}
-
-#define MPC83XX_SPI_TX_BUF(type)				\
-static								\
-u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
-{								\
-	u32 data;						\
-	const type *tx = mpc8xxx_spi->tx;			\
-	if (!tx)						\
-		return 0;					\
-	data = *tx++ << mpc8xxx_spi->tx_shift;			\
-	mpc8xxx_spi->tx = tx;					\
-	return data;						\
-}
+static void *fsl_dummy_rx;
+static DEFINE_MUTEX(fsl_dummy_rx_lock);
+static int fsl_dummy_rx_refcnt;
 
-MPC83XX_SPI_RX_BUF(u8)
-MPC83XX_SPI_RX_BUF(u16)
-MPC83XX_SPI_RX_BUF(u32)
-MPC83XX_SPI_TX_BUF(u8)
-MPC83XX_SPI_TX_BUF(u16)
-MPC83XX_SPI_TX_BUF(u32)
-
-static void mpc8xxx_spi_change_mode(struct spi_device *spi)
+static void fsl_spi_change_mode(struct spi_device *spi)
 {
 	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
 	struct spi_mpc8xxx_cs *cs = spi->controller_state;
-	__be32 __iomem *mode = &mspi->base->mode;
+	struct fsl_spi_reg *reg_base = (struct fsl_spi_reg *)mspi->reg_base;
+	__be32 __iomem *mode = &reg_base->mode;
 	unsigned long flags;
 
 	if (cs->hw_mode == mpc8xxx_spi_read_reg(mode))
@@ -238,7 +136,7 @@ static void mpc8xxx_spi_change_mode(struct spi_device *spi)
 	local_irq_restore(flags);
 }
 
-static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
+static void fsl_spi_chipselect(struct spi_device *spi, int value)
 {
 	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
 	struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
@@ -256,18 +154,17 @@ static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
 		mpc8xxx_spi->get_rx = cs->get_rx;
 		mpc8xxx_spi->get_tx = cs->get_tx;
 
-		mpc8xxx_spi_change_mode(spi);
+		fsl_spi_change_mode(spi);
 
 		if (pdata->cs_control)
 			pdata->cs_control(spi, pol);
 	}
 }
 
-static int
-mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
-			   struct spi_device *spi,
-			   struct mpc8xxx_spi *mpc8xxx_spi,
-			   int bits_per_word)
+static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
+				struct spi_device *spi,
+				struct mpc8xxx_spi *mpc8xxx_spi,
+				int bits_per_word)
 {
 	cs->rx_shift = 0;
 	cs->tx_shift = 0;
@@ -307,10 +204,9 @@ mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
 	return bits_per_word;
 }
 
-static int
-mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
-			  struct spi_device *spi,
-			  int bits_per_word)
+static int mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
+				struct spi_device *spi,
+				int bits_per_word)
 {
 	/* QE uses Little Endian for words > 8
 	 * so transform all words > 8 into 8 bits
@@ -326,13 +222,13 @@ mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
 	return bits_per_word;
 }
 
-static
-int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+static int fsl_spi_setup_transfer(struct spi_device *spi,
+					struct spi_transfer *t)
 {
 	struct mpc8xxx_spi *mpc8xxx_spi;
-	int bits_per_word;
+	int bits_per_word = 0;
 	u8 pm;
-	u32 hz;
+	u32 hz = 0;
 	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
 
 	mpc8xxx_spi = spi_master_get_devdata(spi->master);
@@ -340,9 +236,6 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
 	if (t) {
 		bits_per_word = t->bits_per_word;
 		hz = t->speed_hz;
-	} else {
-		bits_per_word = 0;
-		hz = 0;
 	}
 
 	/* spi_transfer level calls that work per-word */
@@ -388,23 +281,25 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
 			  hz, mpc8xxx_spi->spibrg / 1024);
 		if (pm > 16)
 			pm = 16;
-	} else
+	} else {
 		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
+	}
 	if (pm)
 		pm--;
 
 	cs->hw_mode |= SPMODE_PM(pm);
 
-	mpc8xxx_spi_change_mode(spi);
+	fsl_spi_change_mode(spi);
 	return 0;
 }
 
-static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
+static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
 {
 	struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd;
 	struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
 	unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
 	unsigned int xfer_ofs;
+	struct fsl_spi_reg *reg_base = (struct fsl_spi_reg *)mspi->reg_base;
 
 	xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
 
@@ -418,13 +313,14 @@ static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
 				 BD_SC_LAST);
 
 	/* start transfer */
-	mpc8xxx_spi_write_reg(&mspi->base->command, SPCOM_STR);
+	mpc8xxx_spi_write_reg(&reg_base->command, SPCOM_STR);
 }
 
-static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
+static int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
 				struct spi_transfer *t, bool is_dma_mapped)
 {
 	struct device *dev = mspi->dev;
+	struct fsl_spi_reg *reg_base = (struct fsl_spi_reg *)mspi->reg_base;
 
 	if (is_dma_mapped) {
 		mspi->map_tx_dma = 0;
@@ -469,13 +365,13 @@ static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
 	}
 
 	/* enable rx ints */
-	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIE_RXB);
+	mpc8xxx_spi_write_reg(&reg_base->mask, SPIE_RXB);
 
 	mspi->xfer_in_progress = t;
 	mspi->count = t->len;
 
 	/* start CPM transfers */
-	mpc8xxx_spi_cpm_bufs_start(mspi);
+	fsl_spi_cpm_bufs_start(mspi);
 
 	return 0;
 
@@ -485,7 +381,7 @@ err_rx_dma:
 	return -ENOMEM;
 }
 
-static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
+static void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
 {
 	struct device *dev = mspi->dev;
 	struct spi_transfer *t = mspi->xfer_in_progress;
@@ -497,31 +393,34 @@ static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
 	mspi->xfer_in_progress = NULL;
 }
 
-static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
+static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
 				struct spi_transfer *t, unsigned int len)
 {
 	u32 word;
+	struct fsl_spi_reg *reg_base = (struct fsl_spi_reg *)mspi->reg_base;
 
 	mspi->count = len;
 
 	/* enable rx ints */
-	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIM_NE);
+	mpc8xxx_spi_write_reg(&reg_base->mask, SPIM_NE);
 
 	/* transmit word */
 	word = mspi->get_tx(mspi);
-	mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
+	mpc8xxx_spi_write_reg(&reg_base->transmit, word);
 
 	return 0;
 }
 
-static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
+static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
 			    bool is_dma_mapped)
 {
 	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+	struct fsl_spi_reg *reg_base;
 	unsigned int len = t->len;
 	u8 bits_per_word;
 	int ret;
 
+	reg_base = (struct fsl_spi_reg *)&mpc8xxx_spi->reg_base;
 	bits_per_word = spi->bits_per_word;
 	if (t->bits_per_word)
 		bits_per_word = t->bits_per_word;
@@ -545,24 +444,24 @@ static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
 	INIT_COMPLETION(mpc8xxx_spi->done);
 
 	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
-		ret = mpc8xxx_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
+		ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
 	else
-		ret = mpc8xxx_spi_cpu_bufs(mpc8xxx_spi, t, len);
+		ret = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len);
 	if (ret)
 		return ret;
 
 	wait_for_completion(&mpc8xxx_spi->done);
 
 	/* disable rx ints */
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
+	mpc8xxx_spi_write_reg(&reg_base->mask, 0);
 
 	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
-		mpc8xxx_spi_cpm_bufs_complete(mpc8xxx_spi);
+		fsl_spi_cpm_bufs_complete(mpc8xxx_spi);
 
 	return mpc8xxx_spi->count;
 }
 
-static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
+static void fsl_spi_do_one_msg(struct spi_message *m)
 {
 	struct spi_device *spi = m->spi;
 	struct spi_transfer *t;
@@ -578,18 +477,18 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
 			status = -EINVAL;
 
 			if (cs_change)
-				status = mpc8xxx_spi_setup_transfer(spi, t);
+				status = fsl_spi_setup_transfer(spi, t);
 			if (status < 0)
 				break;
 		}
 
 		if (cs_change) {
-			mpc8xxx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
+			fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE);
 			ndelay(nsecs);
 		}
 		cs_change = t->cs_change;
 		if (t->len)
-			status = mpc8xxx_spi_bufs(spi, t, m->is_dma_mapped);
+			status = fsl_spi_bufs(spi, t, m->is_dma_mapped);
 		if (status) {
 			status = -EMSGSIZE;
 			break;
@@ -601,7 +500,7 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
 
 		if (cs_change) {
 			ndelay(nsecs);
-			mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+			fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
 			ndelay(nsecs);
 		}
 	}
@@ -611,35 +510,16 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
 
 	if (status || !cs_change) {
 		ndelay(nsecs);
-		mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+		fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
 	}
 
-	mpc8xxx_spi_setup_transfer(spi, NULL);
-}
-
-static void mpc8xxx_spi_work(struct work_struct *work)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
-						       work);
-
-	spin_lock_irq(&mpc8xxx_spi->lock);
-	while (!list_empty(&mpc8xxx_spi->queue)) {
-		struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
-						   struct spi_message, queue);
-
-		list_del_init(&m->queue);
-		spin_unlock_irq(&mpc8xxx_spi->lock);
-
-		mpc8xxx_spi_do_one_msg(m);
-
-		spin_lock_irq(&mpc8xxx_spi->lock);
-	}
-	spin_unlock_irq(&mpc8xxx_spi->lock);
+	fsl_spi_setup_transfer(spi, NULL);
 }
 
-static int mpc8xxx_spi_setup(struct spi_device *spi)
+static int fsl_spi_setup(struct spi_device *spi)
 {
 	struct mpc8xxx_spi *mpc8xxx_spi;
+	struct fsl_spi_reg *reg_base;
 	int retval;
 	u32 hw_mode;
 	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
@@ -655,8 +535,10 @@ static int mpc8xxx_spi_setup(struct spi_device *spi)
 	}
 	mpc8xxx_spi = spi_master_get_devdata(spi->master);
 
+	reg_base = (struct fsl_spi_reg *)&mpc8xxx_spi->reg_base;
+
 	hw_mode = cs->hw_mode; /* Save original settings */
-	cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
+	cs->hw_mode = mpc8xxx_spi_read_reg(&reg_base->mode);
 	/* mask out bits we are going to set */
 	cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
 			 | SPMODE_REV | SPMODE_LOOP);
@@ -670,7 +552,7 @@ static int mpc8xxx_spi_setup(struct spi_device *spi)
 	if (spi->mode & SPI_LOOP)
 		cs->hw_mode |= SPMODE_LOOP;
 
-	retval = mpc8xxx_spi_setup_transfer(spi, NULL);
+	retval = fsl_spi_setup_transfer(spi, NULL);
 	if (retval < 0) {
 		cs->hw_mode = hw_mode; /* Restore settings */
 		return retval;
@@ -678,9 +560,10 @@ static int mpc8xxx_spi_setup(struct spi_device *spi)
 	return 0;
 }
 
-static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
+static void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
 {
 	u16 len;
+	struct fsl_spi_reg *reg_base = (struct fsl_spi_reg *)mspi->reg_base;
 
 	dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
 		in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
@@ -692,20 +575,22 @@ static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
 	}
 
 	/* Clear the events */
-	mpc8xxx_spi_write_reg(&mspi->base->event, events);
+	mpc8xxx_spi_write_reg(&reg_base->event, events);
 
 	mspi->count -= len;
 	if (mspi->count)
-		mpc8xxx_spi_cpm_bufs_start(mspi);
+		fsl_spi_cpm_bufs_start(mspi);
 	else
 		complete(&mspi->done);
 }
 
-static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
+static void fsl_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
 {
+	struct fsl_spi_reg *reg_base = (struct fsl_spi_reg *)mspi->reg_base;
+
 	/* We need handle RX first */
 	if (events & SPIE_NE) {
-		u32 rx_data = mpc8xxx_spi_read_reg(&mspi->base->receive);
+		u32 rx_data = mpc8xxx_spi_read_reg(&reg_base->receive);
 
 		if (mspi->rx)
 			mspi->get_rx(rx_data, mspi);
@@ -714,102 +599,80 @@ static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
 	if ((events & SPIE_NF) == 0)
 		/* spin until TX is done */
 		while (((events =
-			mpc8xxx_spi_read_reg(&mspi->base->event)) &
+			mpc8xxx_spi_read_reg(&reg_base->event)) &
 						SPIE_NF) == 0)
 			cpu_relax();
 
 	/* Clear the events */
-	mpc8xxx_spi_write_reg(&mspi->base->event, events);
+	mpc8xxx_spi_write_reg(&reg_base->event, events);
 
 	mspi->count -= 1;
 	if (mspi->count) {
 		u32 word = mspi->get_tx(mspi);
 
-		mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
+		mpc8xxx_spi_write_reg(&reg_base->transmit, word);
 	} else {
 		complete(&mspi->done);
 	}
 }
 
-static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
+static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
 {
 	struct mpc8xxx_spi *mspi = context_data;
 	irqreturn_t ret = IRQ_NONE;
 	u32 events;
+	struct fsl_spi_reg *reg_base = (struct fsl_spi_reg *)mspi->reg_base;
 
 	/* Get interrupt events(tx/rx) */
-	events = mpc8xxx_spi_read_reg(&mspi->base->event);
+	events = mpc8xxx_spi_read_reg(&reg_base->event);
 	if (events)
 		ret = IRQ_HANDLED;
 
 	dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);
 
 	if (mspi->flags & SPI_CPM_MODE)
-		mpc8xxx_spi_cpm_irq(mspi, events);
+		fsl_spi_cpm_irq(mspi, events);
 	else
-		mpc8xxx_spi_cpu_irq(mspi, events);
+		fsl_spi_cpu_irq(mspi, events);
 
 	return ret;
 }
 
-static int mpc8xxx_spi_transfer(struct spi_device *spi,
-				struct spi_message *m)
+static void *fsl_spi_alloc_dummy_rx(void)
 {
-	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
-	unsigned long flags;
+	mutex_lock(&fsl_dummy_rx_lock);
 
-	m->actual_length = 0;
-	m->status = -EINPROGRESS;
+	if (!fsl_dummy_rx)
+		fsl_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
+	if (fsl_dummy_rx)
+		fsl_dummy_rx_refcnt++;
 
-	spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
-	list_add_tail(&m->queue, &mpc8xxx_spi->queue);
-	queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
-	spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
+	mutex_unlock(&fsl_dummy_rx_lock);
 
-	return 0;
+	return fsl_dummy_rx;
 }
 
-
-static void mpc8xxx_spi_cleanup(struct spi_device *spi)
+static void fsl_spi_free_dummy_rx(void)
 {
-	kfree(spi->controller_state);
-}
+	mutex_lock(&fsl_dummy_rx_lock);
 
-static void *mpc8xxx_spi_alloc_dummy_rx(void)
-{
-	mutex_lock(&mpc8xxx_dummy_rx_lock);
-
-	if (!mpc8xxx_dummy_rx)
-		mpc8xxx_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
-	if (mpc8xxx_dummy_rx)
-		mpc8xxx_dummy_rx_refcnt++;
-
-	mutex_unlock(&mpc8xxx_dummy_rx_lock);
-
-	return mpc8xxx_dummy_rx;
-}
-
-static void mpc8xxx_spi_free_dummy_rx(void)
-{
-	mutex_lock(&mpc8xxx_dummy_rx_lock);
-
-	switch (mpc8xxx_dummy_rx_refcnt) {
+	switch (fsl_dummy_rx_refcnt) {
 	case 0:
 		WARN_ON(1);
 		break;
 	case 1:
-		kfree(mpc8xxx_dummy_rx);
-		mpc8xxx_dummy_rx = NULL;
+		kfree(fsl_dummy_rx);
+		fsl_dummy_rx = NULL;
 		/* fall through */
 	default:
-		mpc8xxx_dummy_rx_refcnt--;
+		fsl_dummy_rx_refcnt--;
 		break;
 	}
 
-	mutex_unlock(&mpc8xxx_dummy_rx_lock);
+	mutex_unlock(&fsl_dummy_rx_lock);
 }
 
-static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
+static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
 {
 	struct device *dev = mspi->dev;
 	struct device_node *np = dev->of_node;
@@ -863,7 +726,7 @@ static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
 	return pram_ofs;
 }
 
-static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
+static int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
 {
 	struct device *dev = mspi->dev;
 	struct device_node *np = dev->of_node;
@@ -875,7 +738,7 @@ static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
 	if (!(mspi->flags & SPI_CPM_MODE))
 		return 0;
 
-	if (!mpc8xxx_spi_alloc_dummy_rx())
+	if (!fsl_spi_alloc_dummy_rx())
 		return -ENOMEM;
 
 	if (mspi->flags & SPI_QE) {
@@ -896,7 +759,7 @@ static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
 		}
 	}
 
-	pram_ofs = mpc8xxx_spi_cpm_get_pram(mspi);
+	pram_ofs = fsl_spi_cpm_get_pram(mspi);
 	if (IS_ERR_VALUE(pram_ofs)) {
 		dev_err(dev, "can't allocate spi parameter ram\n");
 		goto err_pram;
@@ -916,7 +779,7 @@ static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
 		goto err_dummy_tx;
 	}
 
-	mspi->dma_dummy_rx = dma_map_single(dev, mpc8xxx_dummy_rx, SPI_MRBLR,
+	mspi->dma_dummy_rx = dma_map_single(dev, fsl_dummy_rx, SPI_MRBLR,
 					    DMA_FROM_DEVICE);
 	if (dma_mapping_error(dev, mspi->dma_dummy_rx)) {
 		dev_err(dev, "unable to map dummy rx buffer\n");
@@ -954,11 +817,11 @@ err_dummy_tx:
 err_bds:
 	cpm_muram_free(pram_ofs);
 err_pram:
-	mpc8xxx_spi_free_dummy_rx();
+	fsl_spi_free_dummy_rx();
 	return -ENOMEM;
 }
 
-static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi)
+static void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
 {
 	struct device *dev = mspi->dev;
 
@@ -966,30 +829,22 @@ static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi)
 	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
 	cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
 	cpm_muram_free(cpm_muram_offset(mspi->pram));
-	mpc8xxx_spi_free_dummy_rx();
+	fsl_spi_free_dummy_rx();
 }
 
-static const char *mpc8xxx_spi_strmode(unsigned int flags)
+static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
 {
-	if (flags & SPI_QE_CPU_MODE) {
-		return "QE CPU";
-	} else if (flags & SPI_CPM_MODE) {
-		if (flags & SPI_QE)
-			return "QE";
-		else if (flags & SPI_CPM2)
-			return "CPM2";
-		else
-			return "CPM1";
-	}
-	return "CPU";
+	iounmap(mspi->reg_base);
+	fsl_spi_cpm_free(mspi);
 }
 
-static struct spi_master * __devinit
-mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
+static struct spi_master * __devinit fsl_spi_probe(struct device *dev,
+		struct resource *mem, unsigned int irq)
 {
 	struct fsl_spi_platform_data *pdata = dev->platform_data;
 	struct spi_master *master;
 	struct mpc8xxx_spi *mpc8xxx_spi;
+	struct fsl_spi_reg *reg_base;
 	u32 regval;
 	int ret = 0;
 
@@ -1001,132 +856,77 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
 
 	dev_set_drvdata(dev, master);
 
-	/* the spi->mode bits understood by this driver: */
-	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
-			| SPI_LSB_FIRST | SPI_LOOP;
+	ret = mpc8xxx_spi_probe(dev, mem, irq);
+	if (ret)
+		goto err_probe;
 
-	master->setup = mpc8xxx_spi_setup;
-	master->transfer = mpc8xxx_spi_transfer;
-	master->cleanup = mpc8xxx_spi_cleanup;
-	master->dev.of_node = dev->of_node;
+	master->setup = fsl_spi_setup;
 
 	mpc8xxx_spi = spi_master_get_devdata(master);
-	mpc8xxx_spi->dev = dev;
-	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
-	mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
-	mpc8xxx_spi->flags = pdata->flags;
-	mpc8xxx_spi->spibrg = pdata->sysclk;
+	mpc8xxx_spi->spi_do_one_msg = fsl_spi_do_one_msg;
+	mpc8xxx_spi->spi_remove = fsl_spi_remove;
+
 
-	ret = mpc8xxx_spi_cpm_init(mpc8xxx_spi);
+	ret = fsl_spi_cpm_init(mpc8xxx_spi);
 	if (ret)
 		goto err_cpm_init;
 
-	mpc8xxx_spi->rx_shift = 0;
-	mpc8xxx_spi->tx_shift = 0;
 	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
 		mpc8xxx_spi->rx_shift = 16;
 		mpc8xxx_spi->tx_shift = 24;
 	}
 
-	init_completion(&mpc8xxx_spi->done);
-
-	mpc8xxx_spi->base = ioremap(mem->start, resource_size(mem));
-	if (mpc8xxx_spi->base == NULL) {
+	mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
+	if (mpc8xxx_spi->reg_base == NULL) {
 		ret = -ENOMEM;
 		goto err_ioremap;
 	}
 
-	mpc8xxx_spi->irq = irq;
-
 	/* Register for SPI Interrupt */
-	ret = request_irq(mpc8xxx_spi->irq, mpc8xxx_spi_irq,
-			  0, "mpc8xxx_spi", mpc8xxx_spi);
+	ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq,
+			  0, "fsl_spi", mpc8xxx_spi);
 
 	if (ret != 0)
-		goto unmap_io;
+		goto free_irq;
 
-	master->bus_num = pdata->bus_num;
-	master->num_chipselect = pdata->max_chipselect;
+	reg_base = (struct fsl_spi_reg *)mpc8xxx_spi->reg_base;
 
 	/* SPI controller initializations */
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0);
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0);
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff);
+	mpc8xxx_spi_write_reg(&reg_base->mode, 0);
+	mpc8xxx_spi_write_reg(&reg_base->mask, 0);
+	mpc8xxx_spi_write_reg(&reg_base->command, 0);
+	mpc8xxx_spi_write_reg(&reg_base->event, 0xffffffff);
 
 	/* Enable SPI interface */
 	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
 	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
 		regval |= SPMODE_OP;
 
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
-	spin_lock_init(&mpc8xxx_spi->lock);
-	init_completion(&mpc8xxx_spi->done);
-	INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
-	INIT_LIST_HEAD(&mpc8xxx_spi->queue);
-
-	mpc8xxx_spi->workqueue = create_singlethread_workqueue(
-		dev_name(master->dev.parent));
-	if (mpc8xxx_spi->workqueue == NULL) {
-		ret = -EBUSY;
-		goto free_irq;
-	}
+	mpc8xxx_spi_write_reg(&reg_base->mode, regval);
 
 	ret = spi_register_master(master);
 	if (ret < 0)
 		goto unreg_master;
 
-	dev_info(dev, "at 0x%p (irq = %d), %s mode\n", mpc8xxx_spi->base,
+	dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base,
 		 mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
 
 	return master;
 
 unreg_master:
-	destroy_workqueue(mpc8xxx_spi->workqueue);
-free_irq:
 	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
-unmap_io:
-	iounmap(mpc8xxx_spi->base);
+free_irq:
+	iounmap(mpc8xxx_spi->reg_base);
 err_ioremap:
-	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
+	fsl_spi_cpm_free(mpc8xxx_spi);
 err_cpm_init:
+err_probe:
 	spi_master_put(master);
 err:
 	return ERR_PTR(ret);
 }
 
-static int __devexit mpc8xxx_spi_remove(struct device *dev)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi;
-	struct spi_master *master;
-
-	master = dev_get_drvdata(dev);
-	mpc8xxx_spi = spi_master_get_devdata(master);
-
-	flush_workqueue(mpc8xxx_spi->workqueue);
-	destroy_workqueue(mpc8xxx_spi->workqueue);
-	spi_unregister_master(master);
-
-	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
-	iounmap(mpc8xxx_spi->base);
-	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
-
-	return 0;
-}
-
-struct mpc8xxx_spi_probe_info {
-	struct fsl_spi_platform_data pdata;
-	int *gpios;
-	bool *alow_flags;
-};
-
-static struct mpc8xxx_spi_probe_info *
-to_of_pinfo(struct fsl_spi_platform_data *pdata)
-{
-	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
-}
-
-static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
+static void fsl_spi_cs_control(struct spi_device *spi, bool on)
 {
 	struct device *dev = spi->dev.parent;
 	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
@@ -1137,7 +937,7 @@ static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
 	gpio_set_value(gpio, on ^ alow);
 }
 
-static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
+static int of_fsl_spi_get_chipselects(struct device *dev)
 {
 	struct device_node *np = dev->of_node;
 	struct fsl_spi_platform_data *pdata = dev->platform_data;
@@ -1198,7 +998,7 @@ static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
 	}
 
 	pdata->max_chipselect = ngpios;
-	pdata->cs_control = mpc8xxx_spi_cs_control;
+	pdata->cs_control = fsl_spi_cs_control;
 
 	return 0;
 
@@ -1217,7 +1017,7 @@ err_alloc_flags:
 	return ret;
 }
 
-static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
+static int of_fsl_spi_free_chipselects(struct device *dev)
 {
 	struct fsl_spi_platform_data *pdata = dev->platform_data;
 	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
@@ -1236,50 +1036,21 @@ static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
 	return 0;
 }
 
-static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
-					  const struct of_device_id *ofid)
+static int __devinit of_fsl_spi_probe(struct platform_device *ofdev,
+					const struct of_device_id *ofid)
 {
 	struct device *dev = &ofdev->dev;
 	struct device_node *np = ofdev->dev.of_node;
-	struct mpc8xxx_spi_probe_info *pinfo;
-	struct fsl_spi_platform_data *pdata;
 	struct spi_master *master;
 	struct resource mem;
 	struct resource irq;
-	const void *prop;
 	int ret = -ENOMEM;
 
-	pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
-	if (!pinfo)
-		return -ENOMEM;
-
-	pdata = &pinfo->pdata;
-	dev->platform_data = pdata;
-
-	/* Allocate bus num dynamically. */
-	pdata->bus_num = -1;
-
-	/* SPI controller is either clocked from QE or SoC clock. */
-	pdata->sysclk = get_brgfreq();
-	if (pdata->sysclk == -1) {
-		pdata->sysclk = fsl_get_sys_freq();
-		if (pdata->sysclk == -1) {
-			ret = -ENODEV;
-			goto err_clk;
-		}
-	}
+	ret = of_mpc8xxx_spi_probe(ofdev, ofid);
+	if (ret)
+		return ret;
 
-	prop = of_get_property(np, "mode", NULL);
-	if (prop && !strcmp(prop, "cpu-qe"))
-		pdata->flags = SPI_QE_CPU_MODE;
-	else if (prop && !strcmp(prop, "qe"))
-		pdata->flags = SPI_CPM_MODE | SPI_QE;
-	else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
-		pdata->flags = SPI_CPM_MODE | SPI_CPM2;
-	else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
-		pdata->flags = SPI_CPM_MODE | SPI_CPM1;
-
-	ret = of_mpc8xxx_spi_get_chipselects(dev);
+	ret = of_fsl_spi_get_chipselects(dev);
 	if (ret)
 		goto err;
 
@@ -1293,7 +1064,7 @@ static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
 		goto err;
 	}
 
-	master = mpc8xxx_spi_probe(dev, &mem, irq.start);
+	master = fsl_spi_probe(dev, &mem, irq.start);
 	if (IS_ERR(master)) {
 		ret = PTR_ERR(master);
 		goto err;
@@ -1302,42 +1073,40 @@ static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
 	return 0;
 
 err:
-	of_mpc8xxx_spi_free_chipselects(dev);
-err_clk:
-	kfree(pinfo);
+	of_fsl_spi_free_chipselects(dev);
 	return ret;
 }
 
-static int __devexit of_mpc8xxx_spi_remove(struct platform_device *ofdev)
+static int __devexit of_fsl_spi_remove(struct platform_device *ofdev)
 {
 	int ret;
 
 	ret = mpc8xxx_spi_remove(&ofdev->dev);
 	if (ret)
 		return ret;
-	of_mpc8xxx_spi_free_chipselects(&ofdev->dev);
+	of_fsl_spi_free_chipselects(&ofdev->dev);
 	return 0;
 }
 
-static const struct of_device_id of_mpc8xxx_spi_match[] = {
+static const struct of_device_id of_fsl_spi_match[] = {
 	{ .compatible = "fsl,spi" },
-	{},
+	{}
 };
-MODULE_DEVICE_TABLE(of, of_mpc8xxx_spi_match);
+MODULE_DEVICE_TABLE(of, of_fsl_spi_match);
 
-static struct of_platform_driver of_mpc8xxx_spi_driver = {
+static struct of_platform_driver of_fsl_spi_driver = {
 	.driver = {
-		.name = "mpc8xxx_spi",
+		.name = "fsl_spi",
 		.owner = THIS_MODULE,
-		.of_match_table = of_mpc8xxx_spi_match,
+		.of_match_table = of_fsl_spi_match,
 	},
-	.probe		= of_mpc8xxx_spi_probe,
-	.remove		= __devexit_p(of_mpc8xxx_spi_remove),
+	.probe		= of_fsl_spi_probe,
+	.remove		= __devexit_p(of_fsl_spi_remove),
 };
 
 #ifdef CONFIG_MPC832x_RDB
 /*
- * 				XXX XXX XXX
+ * XXX XXX XXX
  * This is "legacy" platform driver, was used by the MPC8323E-RDB boards
  * only. The driver should go away soon, since newer MPC8323E-RDB's device
  * tree can work with OpenFirmware driver. But for now we support old trees
@@ -1360,7 +1129,7 @@ static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
 	if (irq <= 0)
 		return -EINVAL;
 
-	master = mpc8xxx_spi_probe(&pdev->dev, mem, irq);
+	master = fsl_spi_probe(&pdev->dev, mem, irq);
 	if (IS_ERR(master))
 		return PTR_ERR(master);
 	return 0;
@@ -1399,21 +1168,20 @@ static void __init legacy_driver_register(void) {}
 static void __exit legacy_driver_unregister(void) {}
 #endif /* CONFIG_MPC832x_RDB */
 
-static int __init mpc8xxx_spi_init(void)
+static int __init fsl_spi_init(void)
 {
 	legacy_driver_register();
-	return of_register_platform_driver(&of_mpc8xxx_spi_driver);
+	return of_register_platform_driver(&of_fsl_spi_driver);
 }
+module_init(fsl_spi_init);
 
-static void __exit mpc8xxx_spi_exit(void)
+static void __exit fsl_spi_exit(void)
 {
-	of_unregister_platform_driver(&of_mpc8xxx_spi_driver);
+	of_unregister_platform_driver(&of_fsl_spi_driver);
 	legacy_driver_unregister();
 }
-
-module_init(mpc8xxx_spi_init);
-module_exit(mpc8xxx_spi_exit);
+module_exit(fsl_spi_exit);
 
 MODULE_AUTHOR("Kumar Gala");
-MODULE_DESCRIPTION("Simple MPC8xxx SPI Driver");
+MODULE_DESCRIPTION("Simple Freescale SPI Driver");
 MODULE_LICENSE("GPL");
-- 
1.6.4

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

* [PATCH v3 3/7] eSPI: add eSPI controller support
  2010-09-30  8:00   ` [PATCH v3 2/7] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Mingkai Hu
@ 2010-09-30  8:00     ` Mingkai Hu
  2010-09-30  8:00       ` [PATCH v3 4/7] powerpc/of: add eSPI controller dts bindings and DTS modification Mingkai Hu
  2010-10-01 11:22       ` [PATCH v3 3/7] eSPI: add eSPI controller support Anton Vorontsov
  2010-10-01 11:22     ` [PATCH v3 2/7] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Anton Vorontsov
  1 sibling, 2 replies; 23+ messages in thread
From: Mingkai Hu @ 2010-09-30  8:00 UTC (permalink / raw)
  To: linuxppc-dev, spi-devel-general, linux-mtd; +Cc: kumar.gala, Mingkai Hu

Add eSPI controller support based on the library code spi_fsl_lib.c.

The eSPI controller is newer controller 85xx/Pxxx devices supported.
There're some differences comparing to the SPI controller:

1. Has different register map and different bit definition
   So leave the code operated the register to the driver code, not
   the common code.

2. Support 4 dedicated chip selects
   The software can't controll the chip selects directly, The SPCOM[CS]
   field is used to select which chip selects is used, and the
   SPCOM[TRANLEN] field is set to tell the controller how long the CS
   signal need to be asserted. So the driver doesn't need the chipselect
   related function when transfering data, just set corresponding register
   fields to controll the chipseclect.

3. Different Transmit/Receive FIFO access register behavior
   For SPI controller, the Tx/Rx FIFO access register can hold only
   one character regardless of the character length, but for eSPI
   controller, the register can hold 4 or 2 characters according to
   the character lengths. Access the Tx/Rx FIFO access register of the
   eSPI controller will shift out/in 4/2 characters one time. For SPI
   subsystem, the command and data are put into different transfers, so
   we need to combine all the transfers to one transfer in order to pass
   the transfer to eSPI controller.

Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
---
v3:
 - Update to the latest kernel base.

 drivers/spi/Kconfig        |    9 +
 drivers/spi/Makefile       |    1 +
 drivers/spi/spi_fsl_espi.c |  642 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/spi_fsl_lib.h  |    1 +
 4 files changed, 653 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/spi_fsl_espi.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 79ad06f..f6888af 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -195,6 +195,15 @@ config SPI_FSL_SPI
 	  MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
 	  MPC8569 uses the controller in QE mode, MPC8610 in cpu mode.
 
+config SPI_FSL_ESPI
+	tristate "Freescale eSPI controller"
+	depends on FSL_SOC
+	select SPI_FSL_LIB
+	help
+	  This enables using the Freescale eSPI controllers in master mode.
+	  From MPC8536, 85xx platform uses the controller, and all P10xx,
+	  P20xx, P30xx,P40xx, P50xx uses this controller.
+
 config SPI_OMAP_UWIRE
 	tristate "OMAP1 MicroWire"
 	depends on ARCH_OMAP1
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 7974c21..833d17e 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_SPI_MPC512x_PSC)		+= mpc512x_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx)		+= mpc52xx_spi.o
 obj-$(CONFIG_SPI_FSL_LIB)		+= spi_fsl_lib.o
+obj-$(CONFIG_SPI_FSL_ESPI)		+= spi_fsl_espi.o
 obj-$(CONFIG_SPI_FSL_SPI)		+= spi_fsl_spi.o
 obj-$(CONFIG_SPI_PPC4xx)		+= spi_ppc4xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
diff --git a/drivers/spi/spi_fsl_espi.c b/drivers/spi/spi_fsl_espi.c
new file mode 100644
index 0000000..be98148
--- /dev/null
+++ b/drivers/spi/spi_fsl_espi.c
@@ -0,0 +1,642 @@
+/*
+ * Freescale eSPI controller driver.
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_spi.h>
+#include <sysdev/fsl_soc.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+
+#include "spi_fsl_lib.h"
+
+/* eSPI Controller registers */
+struct fsl_espi_reg {
+	__be32 mode;		/* 0x000 - eSPI mode register */
+	__be32 event;		/* 0x004 - eSPI event register */
+	__be32 mask;		/* 0x008 - eSPI mask register */
+	__be32 command;		/* 0x00c - eSPI command register */
+	__be32 transmit;	/* 0x010 - eSPI transmit FIFO access register*/
+	__be32 receive;		/* 0x014 - eSPI receive FIFO access register*/
+	u8 res[8];		/* 0x018 - 0x01c reserved */
+	__be32 csmode[4];	/* 0x020 - 0x02c eSPI cs mode register */
+};
+
+/* eSPI Controller mode register definitions */
+#define SPMODE_ENABLE		(1 << 31)
+#define SPMODE_LOOP		(1 << 30)
+#define SPMODE_TXTHR(x)		((x) << 8)
+#define SPMODE_RXTHR(x)		((x) << 0)
+
+/* eSPI Controller CS mode register definitions */
+#define CSMODE_CI_INACTIVEHIGH	(1 << 31)
+#define CSMODE_CP_BEGIN_EDGECLK	(1 << 30)
+#define CSMODE_REV		(1 << 29)
+#define CSMODE_DIV16		(1 << 28)
+#define CSMODE_PM(x)		((x) << 24)
+#define CSMODE_POL_1		(1 << 20)
+#define CSMODE_LEN(x)		((x) << 16)
+#define CSMODE_BEF(x)		((x) << 12)
+#define CSMODE_AFT(x)		((x) << 8)
+#define CSMODE_CG(x)		((x) << 3)
+
+/* Default mode/csmode for eSPI controller */
+#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3))
+#define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \
+		| CSMODE_AFT(0) | CSMODE_CG(1))
+
+/* SPIE register values */
+#define	SPIE_NE		0x00000200	/* Not empty */
+#define	SPIE_NF		0x00000100	/* Not full */
+
+/* SPIM register values */
+#define	SPIM_NE		0x00000200	/* Not empty */
+#define	SPIM_NF		0x00000100	/* Not full */
+#define SPIE_RXCNT(reg)     ((reg >> 24) & 0x3F)
+#define SPIE_TXCNT(reg)     ((reg >> 16) & 0x3F)
+
+/* SPCOM register values */
+#define SPCOM_CS(x)		((x) << 30)
+#define SPCOM_TRANLEN(x)	((x) << 0)
+#define	SPCOM_TRANLEN_MAX	0xFFFF	/* Max transaction length */
+
+static void fsl_espi_change_mode(struct spi_device *spi)
+{
+	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
+	struct spi_mpc8xxx_cs *cs = spi->controller_state;
+	struct fsl_espi_reg *reg_base = (struct fsl_espi_reg *)mspi->reg_base;
+	__be32 __iomem *mode;
+	__be32 __iomem *espi_mode = NULL;
+	u32 tmp;
+	unsigned long flags;
+
+	espi_mode = &reg_base->mode;
+	mode = &reg_base->csmode[spi->chip_select];
+
+	/* Turn off IRQs locally to minimize time that SPI is disabled. */
+	local_irq_save(flags);
+
+	/* Turn off SPI unit prior changing mode */
+	tmp = mpc8xxx_spi_read_reg(espi_mode);
+	mpc8xxx_spi_write_reg(espi_mode, tmp & ~SPMODE_ENABLE);
+	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
+	mpc8xxx_spi_write_reg(espi_mode, tmp);
+
+	local_irq_restore(flags);
+}
+
+static u32 fsl_espi_tx_buf_lsb(struct mpc8xxx_spi *mpc8xxx_spi)
+{
+	u32 data;
+	u16 data_h, data_l;
+
+	const u32 *tx = mpc8xxx_spi->tx;
+	if (!tx)
+		return 0;
+
+	data = *tx++ << mpc8xxx_spi->tx_shift;
+	data_l = data & 0xffff;
+	data_h = (data >> 16) & 0xffff;
+	swab16s(&data_l);
+	swab16s(&data_h);
+	data = data_h | data_l;
+
+	mpc8xxx_spi->tx = tx;
+	return data;
+}
+
+static int fsl_espi_setup_transfer(struct spi_device *spi,
+					struct spi_transfer *t)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	int bits_per_word = 0;
+	u8 pm;
+	u32 hz = 0;
+	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
+
+	mpc8xxx_spi = spi_master_get_devdata(spi->master);
+
+	if (t) {
+		bits_per_word = t->bits_per_word;
+		hz = t->speed_hz;
+	}
+
+	/* spi_transfer level calls that work per-word */
+	if (!bits_per_word)
+		bits_per_word = spi->bits_per_word;
+
+	/* Make sure its a bit width we support [4..16] */
+	if ((bits_per_word < 4) || (bits_per_word > 16))
+		return -EINVAL;
+
+	if (!hz)
+		hz = spi->max_speed_hz;
+
+	cs->rx_shift = 0;
+	cs->tx_shift = 0;
+	cs->get_rx = mpc8xxx_spi_rx_buf_u32;
+	cs->get_tx = mpc8xxx_spi_tx_buf_u32;
+	if (bits_per_word <= 8) {
+		cs->rx_shift = 8 - bits_per_word;
+	} else if (bits_per_word <= 16) {
+		cs->rx_shift = 16 - bits_per_word;
+		if (spi->mode & SPI_LSB_FIRST)
+			cs->get_tx = fsl_espi_tx_buf_lsb;
+	} else
+		return -EINVAL;
+
+	mpc8xxx_spi->rx_shift = cs->rx_shift;
+	mpc8xxx_spi->tx_shift = cs->tx_shift;
+	mpc8xxx_spi->get_rx = cs->get_rx;
+	mpc8xxx_spi->get_tx = cs->get_tx;
+
+	bits_per_word = bits_per_word - 1;
+
+	/* mask out bits we are going to set */
+	cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16
+				  | CSMODE_PM(0xF));
+
+	cs->hw_mode |= CSMODE_LEN(bits_per_word);
+
+	if ((mpc8xxx_spi->spibrg / hz) > 64) {
+		cs->hw_mode |= CSMODE_DIV16;
+		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
+
+		WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
+			  "Will use %d Hz instead.\n", dev_name(&spi->dev),
+			  hz, mpc8xxx_spi->spibrg / 1024);
+		if (pm > 16)
+			pm = 16;
+	} else {
+		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
+	}
+	if (pm)
+		pm--;
+
+	cs->hw_mode |= CSMODE_PM(pm);
+
+	fsl_espi_change_mode(spi);
+	return 0;
+}
+
+int fsl_espi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t,
+		unsigned int len)
+{
+	u32 word;
+	struct fsl_espi_reg *reg_base = (struct fsl_espi_reg *)mspi->reg_base;
+
+	mspi->count = len;
+
+	/* enable rx ints */
+	mpc8xxx_spi_write_reg(&reg_base->mask, SPIM_NE);
+
+	/* transmit word */
+	word = mspi->get_tx(mspi);
+	mpc8xxx_spi_write_reg(&reg_base->transmit, word);
+
+	return 0;
+}
+
+static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t,
+			    bool is_dma_mapped)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+	struct fsl_espi_reg *reg_base;
+	unsigned int len = t->len;
+	u8 bits_per_word;
+	int ret;
+
+	reg_base = (struct fsl_espi_reg *)mpc8xxx_spi->reg_base;
+
+	bits_per_word = spi->bits_per_word;
+	if (t->bits_per_word)
+		bits_per_word = t->bits_per_word;
+
+	mpc8xxx_spi->len = t->len;
+	len = roundup(len, 4) / 4;
+
+	mpc8xxx_spi->tx = t->tx_buf;
+	mpc8xxx_spi->rx = t->rx_buf;
+
+	INIT_COMPLETION(mpc8xxx_spi->done);
+
+	/* Set SPCOM[CS] and SPCOM[TRANLEN] field */
+	if ((t->len - 1) > SPCOM_TRANLEN_MAX) {
+		dev_err(mpc8xxx_spi->dev, "Transaction length (%d)"
+				" beyond the SPCOM[TRANLEN] field\n", t->len);
+		return -EINVAL;
+	}
+	mpc8xxx_spi_write_reg(&reg_base->command,
+		(SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
+
+	ret = fsl_espi_cpu_bufs(mpc8xxx_spi, t, len);
+	if (ret)
+		return ret;
+
+	wait_for_completion(&mpc8xxx_spi->done);
+
+	/* disable rx ints */
+	mpc8xxx_spi_write_reg(&reg_base->mask, 0);
+
+	return mpc8xxx_spi->count;
+}
+
+static void fsl_espi_do_one_msg(struct spi_message *m)
+{
+	struct spi_device *spi = m->spi;
+	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
+	struct spi_message message;
+	struct spi_transfer *t, *first, trans;
+	u8 *local_buf, *rx_buf = NULL;
+	unsigned int n_tx = 0;
+	unsigned int n_rx = 0;
+	int status = 0;
+	int i = 0;
+
+	spi_message_init(&message);
+	memset(&trans, 0, sizeof(trans));
+
+	first = list_first_entry(&m->transfers, struct spi_transfer,
+			transfer_list);
+	list_for_each_entry(t, &m->transfers, transfer_list) {
+		if ((first->bits_per_word != t->bits_per_word) ||
+			(first->speed_hz != t->speed_hz)) {
+			status = -EINVAL;
+			dev_err(mspi->dev, "bits_per_word/speed_hz should be"
+					" same for the same SPI transfer\n");
+			return;
+		}
+
+		trans.speed_hz = t->speed_hz;
+		trans.bits_per_word = t->bits_per_word;
+		trans.delay_usecs = max(first->delay_usecs, t->delay_usecs);
+
+		if (t->tx_buf)
+			n_tx += t->len;
+
+		if (t->rx_buf) {
+			n_rx += t->len;
+			rx_buf = t->rx_buf;
+		}
+	}
+
+	local_buf = kzalloc(n_tx * 2 + roundup(n_rx + n_tx, 4), GFP_KERNEL);
+	if (!local_buf) {
+		status = -ENOMEM;
+		return;
+	}
+
+	list_for_each_entry(t, &m->transfers, transfer_list) {
+		if (t->tx_buf) {
+			memcpy(local_buf + i, t->tx_buf, t->len);
+			i += t->len;
+		}
+	}
+
+	trans.len = n_tx + n_rx;
+	trans.tx_buf = local_buf;
+	trans.rx_buf = local_buf + n_tx;
+	spi_message_add_tail(&trans, &message);
+
+	list_for_each_entry(t, &message.transfers, transfer_list) {
+		if (t->bits_per_word || t->speed_hz) {
+			status = -EINVAL;
+
+			status = fsl_espi_setup_transfer(spi, t);
+			if (status < 0)
+				break;
+		}
+
+		if (t->len)
+			status = fsl_espi_bufs(spi, t, 0);
+		if (status) {
+			status = -EMSGSIZE;
+			break;
+		}
+		m->actual_length += t->len;
+
+		if (rx_buf)
+			memcpy(rx_buf, t->rx_buf + n_tx, n_rx);
+
+		if (t->delay_usecs)
+			udelay(t->delay_usecs);
+	}
+
+	m->status = status;
+	m->complete(m->context);
+
+	fsl_espi_setup_transfer(spi, NULL);
+	kfree(local_buf);
+}
+
+static int fsl_espi_setup(struct spi_device *spi)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	struct fsl_espi_reg *reg_base;
+	int retval;
+	u32 hw_mode;
+	u32 loop_mode;
+	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
+
+	if (!spi->max_speed_hz)
+		return -EINVAL;
+
+	if (!cs) {
+		cs = kzalloc(sizeof *cs, GFP_KERNEL);
+		if (!cs)
+			return -ENOMEM;
+		spi->controller_state = cs;
+	}
+
+	mpc8xxx_spi = spi_master_get_devdata(spi->master);
+	reg_base = (struct fsl_espi_reg *)mpc8xxx_spi->reg_base;
+
+	hw_mode = cs->hw_mode; /* Save orginal settings */
+	cs->hw_mode = mpc8xxx_spi_read_reg(
+			&reg_base->csmode[spi->chip_select]);
+	/* mask out bits we are going to set */
+	cs->hw_mode &= ~(CSMODE_CP_BEGIN_EDGECLK | CSMODE_CI_INACTIVEHIGH
+			 | CSMODE_REV);
+
+	if (spi->mode & SPI_CPHA)
+		cs->hw_mode |= CSMODE_CP_BEGIN_EDGECLK;
+	if (spi->mode & SPI_CPOL)
+		cs->hw_mode |= CSMODE_CI_INACTIVEHIGH;
+	if (!(spi->mode & SPI_LSB_FIRST))
+		cs->hw_mode |= CSMODE_REV;
+
+	/* Handle the loop mode */
+	loop_mode = mpc8xxx_spi_read_reg(&reg_base->mode);
+	loop_mode &= ~SPMODE_LOOP;
+	if (spi->mode & SPI_LOOP)
+		loop_mode |= SPMODE_LOOP;
+	mpc8xxx_spi_write_reg(&reg_base->mode, loop_mode);
+
+	retval = fsl_espi_setup_transfer(spi, NULL);
+	if (retval < 0) {
+		cs->hw_mode = hw_mode; /* Restore settings */
+		return retval;
+	}
+	return 0;
+}
+
+static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
+{
+	struct fsl_espi_reg *reg_base = (struct fsl_espi_reg *)mspi->reg_base;
+
+	/* We need handle RX first */
+	if (events & SPIE_NE) {
+		u32 rx_data;
+
+		/* Spin until RX is done */
+		while (SPIE_RXCNT(events) < min(4, mspi->len)) {
+			cpu_relax();
+			events = mpc8xxx_spi_read_reg(&reg_base->event);
+		}
+		mspi->len -= 4;
+
+		rx_data = mpc8xxx_spi_read_reg(&reg_base->receive);
+
+		if (mspi->rx)
+			mspi->get_rx(rx_data, mspi);
+	}
+
+	if ((events & SPIE_NF) == 0)
+		/* spin until TX is done */
+		while (((events = mpc8xxx_spi_read_reg(&reg_base->event))
+					& SPIE_NF) == 0)
+			cpu_relax();
+
+	/* Clear the events */
+	mpc8xxx_spi_write_reg(&reg_base->event, events);
+
+	mspi->count -= 1;
+	if (mspi->count) {
+		u32 word = mspi->get_tx(mspi);
+
+		mpc8xxx_spi_write_reg(&reg_base->transmit, word);
+	} else {
+		complete(&mspi->done);
+	}
+}
+
+static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
+{
+	struct mpc8xxx_spi *mspi = context_data;
+	struct fsl_espi_reg *reg_base = (struct fsl_espi_reg *)mspi->reg_base;
+	irqreturn_t ret = IRQ_NONE;
+	u32 events;
+
+	/* Get interrupt events(tx/rx) */
+	events = mpc8xxx_spi_read_reg(&reg_base->event);
+	if (events)
+		ret = IRQ_HANDLED;
+
+	dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);
+
+	fsl_espi_cpu_irq(mspi, events);
+
+	return ret;
+}
+
+static void fsl_espi_remove(struct mpc8xxx_spi *mspi)
+{
+	iounmap(mspi->reg_base);
+}
+
+static struct spi_master * __devinit fsl_espi_probe(struct device *dev,
+		struct resource *mem, unsigned int irq)
+{
+	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct spi_master *master;
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	struct fsl_espi_reg *reg_base;
+	u32 regval;
+	int i, ret = 0;
+
+	master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
+	if (master == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	dev_set_drvdata(dev, master);
+
+	ret = mpc8xxx_spi_probe(dev, mem, irq);
+	if (ret)
+		goto err_probe;
+
+	master->setup = fsl_espi_setup;
+
+	mpc8xxx_spi = spi_master_get_devdata(master);
+	mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg;
+	mpc8xxx_spi->spi_remove = fsl_espi_remove;
+
+	mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
+	if (mpc8xxx_spi->reg_base == NULL) {
+		ret = -ENOMEM;
+		goto err_probe;
+	}
+
+	reg_base = (struct fsl_espi_reg *)mpc8xxx_spi->reg_base;
+
+	/* Register for SPI Interrupt */
+	ret = request_irq(mpc8xxx_spi->irq, fsl_espi_irq,
+			  0, "fsl_espi", mpc8xxx_spi);
+
+	if (ret != 0)
+		goto free_irq;
+
+	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
+		mpc8xxx_spi->rx_shift = 16;
+		mpc8xxx_spi->tx_shift = 24;
+	}
+
+	/* SPI controller initializations */
+	mpc8xxx_spi_write_reg(&reg_base->mode, 0);
+	mpc8xxx_spi_write_reg(&reg_base->mask, 0);
+	mpc8xxx_spi_write_reg(&reg_base->command, 0);
+	mpc8xxx_spi_write_reg(&reg_base->event, 0xffffffff);
+
+	/* Init eSPI CS mode register */
+	for (i = 0; i < pdata->max_chipselect; i++)
+		mpc8xxx_spi_write_reg(&reg_base->csmode[i], CSMODE_INIT_VAL);
+
+	/* Enable SPI interface */
+	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
+
+	mpc8xxx_spi_write_reg(&reg_base->mode, regval);
+
+	ret = spi_register_master(master);
+	if (ret < 0)
+		goto unreg_master;
+
+	dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq);
+
+	return master;
+
+unreg_master:
+	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
+free_irq:
+	iounmap(mpc8xxx_spi->reg_base);
+err_probe:
+	spi_master_put(master);
+err:
+	return ERR_PTR(ret);
+}
+
+static int of_fsl_espi_get_chipselects(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	const u32 *prop;
+	int len;
+
+	prop = of_get_property(np, "fsl,espi-num-chipselects", &len);
+	if (!prop || len < sizeof(*prop)) {
+		dev_err(dev, "No 'fsl,espi-num-chipselects' property\n");
+		return -EINVAL;
+	}
+
+	pdata->max_chipselect = *prop;
+	pdata->cs_control = NULL;
+
+	return 0;
+}
+
+static int __devinit of_fsl_espi_probe(struct platform_device *ofdev,
+					const struct of_device_id *ofid)
+{
+	struct device *dev = &ofdev->dev;
+	struct device_node *np = ofdev->dev.of_node;
+	struct spi_master *master;
+	struct resource mem;
+	struct resource irq;
+	int ret = -ENOMEM;
+
+	ret = of_mpc8xxx_spi_probe(ofdev, ofid);
+	if (ret)
+		return ret;
+
+	ret = of_fsl_espi_get_chipselects(dev);
+	if (ret)
+		goto err;
+
+	ret = of_address_to_resource(np, 0, &mem);
+	if (ret)
+		goto err;
+
+	ret = of_irq_to_resource(np, 0, &irq);
+	if (!ret) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	master = fsl_espi_probe(dev, &mem, irq.start);
+	if (IS_ERR(master)) {
+		ret = PTR_ERR(master);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+}
+
+static int __devexit of_fsl_espi_remove(struct platform_device *dev)
+{
+	int ret;
+
+	ret = mpc8xxx_spi_remove(&dev->dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct of_device_id of_fsl_espi_match[] = {
+	{ .compatible = "fsl,mpc8536-espi" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, of_fsl_espi_match);
+
+static struct of_platform_driver fsl_espi_driver = {
+	.driver = {
+		.name = "fsl_espi",
+		.owner = THIS_MODULE,
+		.of_match_table = of_fsl_espi_match,
+	},
+	.probe		= of_fsl_espi_probe,
+	.remove		= __devexit_p(of_fsl_espi_remove),
+};
+
+static int __init fsl_espi_init(void)
+{
+	return of_register_platform_driver(&fsl_espi_driver);
+}
+module_init(fsl_espi_init);
+
+static void __exit fsl_espi_exit(void)
+{
+	of_unregister_platform_driver(&fsl_espi_driver);
+}
+module_exit(fsl_espi_exit);
+
+MODULE_AUTHOR("Mingkai Hu");
+MODULE_DESCRIPTION("Enhanced Freescale SPI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_fsl_lib.h b/drivers/spi/spi_fsl_lib.h
index 6ae8949..9c81498 100644
--- a/drivers/spi/spi_fsl_lib.h
+++ b/drivers/spi/spi_fsl_lib.h
@@ -26,6 +26,7 @@ struct mpc8xxx_spi {
 	/* rx & tx bufs from the spi_transfer */
 	const void *tx;
 	void *rx;
+	int len;
 
 	int subblock;
 	struct spi_pram __iomem *pram;
-- 
1.6.4

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

* [PATCH v3 4/7] powerpc/of: add eSPI controller dts bindings and DTS modification
  2010-09-30  8:00     ` [PATCH v3 3/7] eSPI: add eSPI controller support Mingkai Hu
@ 2010-09-30  8:00       ` Mingkai Hu
  2010-09-30  8:00         ` [PATCH v3 5/7] mtd: m25p80: add support to parse the SPI flash's partitions Mingkai Hu
  2010-10-01 11:22       ` [PATCH v3 3/7] eSPI: add eSPI controller support Anton Vorontsov
  1 sibling, 1 reply; 23+ messages in thread
From: Mingkai Hu @ 2010-09-30  8:00 UTC (permalink / raw)
  To: linuxppc-dev, spi-devel-general, linux-mtd; +Cc: kumar.gala, Mingkai Hu

Also modifiy the document of cell-index in SPI controller. Add the
SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board.

Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
---
v3:
 - Add "fsl,p4080-espi" compatible property.

 Documentation/powerpc/dts-bindings/fsl/spi.txt |   24 ++++++++++-
 arch/powerpc/boot/dts/mpc8536ds.dts            |   52 ++++++++++++++++++++++++
 arch/powerpc/boot/dts/p4080ds.dts              |   11 ++---
 3 files changed, 79 insertions(+), 8 deletions(-)

diff --git a/Documentation/powerpc/dts-bindings/fsl/spi.txt b/Documentation/powerpc/dts-bindings/fsl/spi.txt
index 80510c0..777abd7 100644
--- a/Documentation/powerpc/dts-bindings/fsl/spi.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/spi.txt
@@ -1,7 +1,9 @@
 * SPI (Serial Peripheral Interface)
 
 Required properties:
-- cell-index : SPI controller index.
+- cell-index : QE SPI subblock index.
+		0: QE subblock SPI1
+		1: QE subblock SPI2
 - compatible : should be "fsl,spi".
 - mode : the SPI operation mode, it can be "cpu" or "cpu-qe".
 - reg : Offset and length of the register set for the device
@@ -29,3 +31,23 @@ Example:
 		gpios = <&gpio 18 1	// device reg=<0>
 			 &gpio 19 1>;	// device reg=<1>
 	};
+
+
+* eSPI (Enhanced Serial Peripheral Interface)
+
+Required properties:
+- compatible : should be "fsl,mpc8536-espi".
+- reg : Offset and length of the register set for the device.
+- interrupts : should contain eSPI interrupt, the device has one interrupt.
+- fsl,espi-num-chipselects : the number of the chipselect signals.
+
+Example:
+	spi@110000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "fsl,mpc8536-espi";
+		reg = <0x110000 0x1000>;
+		interrupts = <53 0x2>;
+		interrupt-parent = <&mpic>;
+		fsl,espi-num-chipselects = <4>;
+	};
diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts
index 815cebb..a75c10e 100644
--- a/arch/powerpc/boot/dts/mpc8536ds.dts
+++ b/arch/powerpc/boot/dts/mpc8536ds.dts
@@ -108,6 +108,58 @@
 			};
 		};
 
+		spi@7000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,mpc8536-espi";
+			reg = <0x7000 0x1000>;
+			interrupts = <59 0x2>;
+			interrupt-parent = <&mpic>;
+			fsl,espi-num-chipselects = <4>;
+
+			flash@0 {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "spansion,s25sl12801";
+				reg = <0>;
+				spi-max-frequency = <40000000>;
+				partition@u-boot {
+					label = "u-boot";
+					reg = <0x00000000 0x00100000>;
+					read-only;
+				};
+				partition@kernel {
+					label = "kernel";
+					reg = <0x00100000 0x00500000>;
+					read-only;
+				};
+				partition@dtb {
+					label = "dtb";
+					reg = <0x00600000 0x00100000>;
+					read-only;
+				};
+				partition@fs {
+					label = "file system";
+					reg = <0x00700000 0x00900000>;
+				};
+			};
+			flash@1 {
+				compatible = "spansion,s25sl12801";
+				reg = <1>;
+				spi-max-frequency = <40000000>;
+			};
+			flash@2 {
+				compatible = "spansion,s25sl12801";
+				reg = <2>;
+				spi-max-frequency = <40000000>;
+			};
+			flash@3 {
+				compatible = "spansion,s25sl12801";
+				reg = <3>;
+				spi-max-frequency = <40000000>;
+			};
+		};
+
 		dma@21300 {
 			#address-cells = <1>;
 			#size-cells = <1>;
diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts
index 2f0de24..5b7fc29 100644
--- a/arch/powerpc/boot/dts/p4080ds.dts
+++ b/arch/powerpc/boot/dts/p4080ds.dts
@@ -236,22 +236,19 @@
 		};
 
 		spi@110000 {
-			cell-index = <0>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			compatible = "fsl,espi";
+			compatible = "fsl,p4080-espi", "fsl,mpc8536-espi";
 			reg = <0x110000 0x1000>;
 			interrupts = <53 0x2>;
 			interrupt-parent = <&mpic>;
-			espi,num-ss-bits = <4>;
-			mode = "cpu";
+			fsl,espi-num-chipselects = <4>;
 
-			fsl_m25p80@0 {
+			flash@0 {
 				#address-cells = <1>;
 				#size-cells = <1>;
-				compatible = "fsl,espi-flash";
+				compatible = "spansion,s25sl12801";
 				reg = <0>;
-				linux,modalias = "fsl_m25p80";
 				spi-max-frequency = <40000000>; /* input clock */
 				partition@u-boot {
 					label = "u-boot";
-- 
1.6.4

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

* [PATCH v3 5/7] mtd: m25p80: add support to parse the SPI flash's partitions
  2010-09-30  8:00       ` [PATCH v3 4/7] powerpc/of: add eSPI controller dts bindings and DTS modification Mingkai Hu
@ 2010-09-30  8:00         ` Mingkai Hu
  2010-09-30  8:00           ` [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page Mingkai Hu
  2010-09-30 21:34           ` [PATCH v3 5/7] mtd: m25p80: add support to parse the SPI flash's partitions Grant Likely
  0 siblings, 2 replies; 23+ messages in thread
From: Mingkai Hu @ 2010-09-30  8:00 UTC (permalink / raw)
  To: linuxppc-dev, spi-devel-general, linux-mtd; +Cc: kumar.gala, Mingkai Hu

Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
---
v3:
 - Move the SPI flash partition code to the probe function.

 drivers/mtd/devices/m25p80.c |   39 +++++++++++++++++++++++++++------------
 1 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 6f512b5..47d53c7 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -772,7 +772,7 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
 static int __devinit m25p_probe(struct spi_device *spi)
 {
 	const struct spi_device_id	*id = spi_get_device_id(spi);
-	struct flash_platform_data	*data;
+	struct flash_platform_data	data, *pdata;
 	struct m25p			*flash;
 	struct flash_info		*info;
 	unsigned			i;
@@ -782,13 +782,27 @@ static int __devinit m25p_probe(struct spi_device *spi)
 	 * a chip ID, try the JEDEC id commands; they'll work for most
 	 * newer chips, even if we don't recognize the particular chip.
 	 */
-	data = spi->dev.platform_data;
-	if (data && data->type) {
+	pdata = spi->dev.platform_data;
+	if (!pdata && spi->dev.of_node) {
+		int nr_parts;
+		struct mtd_partition *parts;
+		struct device_node *np = spi->dev.of_node;
+
+		nr_parts = of_mtd_parse_partitions(&spi->dev, np, &parts);
+		if (nr_parts) {
+			pdata = &data;
+			memset(pdata, 0, sizeof(*pdata));
+			pdata->parts = parts;
+			pdata->nr_parts = nr_parts;
+		}
+	}
+
+	if (pdata && pdata->type) {
 		const struct spi_device_id *plat_id;
 
 		for (i = 0; i < ARRAY_SIZE(m25p_ids) - 1; i++) {
 			plat_id = &m25p_ids[i];
-			if (strcmp(data->type, plat_id->name))
+			if (strcmp(pdata->type, plat_id->name))
 				continue;
 			break;
 		}
@@ -796,7 +810,8 @@ static int __devinit m25p_probe(struct spi_device *spi)
 		if (i < ARRAY_SIZE(m25p_ids) - 1)
 			id = plat_id;
 		else
-			dev_warn(&spi->dev, "unrecognized id %s\n", data->type);
+			dev_warn(&spi->dev, "unrecognized id %s\n",
+					pdata->type);
 	}
 
 	info = (void *)id->driver_data;
@@ -847,8 +862,8 @@ static int __devinit m25p_probe(struct spi_device *spi)
 		write_sr(flash, 0);
 	}
 
-	if (data && data->name)
-		flash->mtd.name = data->name;
+	if (pdata && pdata->name)
+		flash->mtd.name = pdata->name;
 	else
 		flash->mtd.name = dev_name(&spi->dev);
 
@@ -919,9 +934,9 @@ static int __devinit m25p_probe(struct spi_device *spi)
 					part_probes, &parts, 0);
 		}
 
-		if (nr_parts <= 0 && data && data->parts) {
-			parts = data->parts;
-			nr_parts = data->nr_parts;
+		if (nr_parts <= 0 && pdata && pdata->parts) {
+			parts = pdata->parts;
+			nr_parts = pdata->nr_parts;
 		}
 
 		if (nr_parts > 0) {
@@ -937,9 +952,9 @@ static int __devinit m25p_probe(struct spi_device *spi)
 			flash->partitioned = 1;
 			return add_mtd_partitions(&flash->mtd, parts, nr_parts);
 		}
-	} else if (data && data->nr_parts)
+	} else if (pdata && pdata->nr_parts)
 		dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
-				data->nr_parts, data->name);
+				pdata->nr_parts, pdata->name);
 
 	return add_mtd_device(&flash->mtd) == 1 ? -ENODEV : 0;
 }
-- 
1.6.4

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

* [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
  2010-09-30  8:00         ` [PATCH v3 5/7] mtd: m25p80: add support to parse the SPI flash's partitions Mingkai Hu
@ 2010-09-30  8:00           ` Mingkai Hu
  2010-09-30  8:00             ` [PATCH v3 7/7] DTS: add fsl,spi-quirk-trans-len-limit property Mingkai Hu
  2010-09-30 21:41             ` [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page Grant Likely
  2010-09-30 21:34           ` [PATCH v3 5/7] mtd: m25p80: add support to parse the SPI flash's partitions Grant Likely
  1 sibling, 2 replies; 23+ messages in thread
From: Mingkai Hu @ 2010-09-30  8:00 UTC (permalink / raw)
  To: linuxppc-dev, spi-devel-general, linux-mtd; +Cc: kumar.gala, Mingkai Hu

For Freescale's eSPI controller, the max transaction length one time
is limitted by the SPCOM[TRANSLEN] field which is 0xFFFF. When used
mkfs.ext2 command to create ext2 filesystem on the flash, the read
length will exceed the max value of the SPCOM[TRANSLEN] field, so
change the read function to read page by page.

For other SPI flash driver, also needed to supply the read function
if used the eSPI controller.

Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
---
v3:
 - Add a quirks member for the SPI master to handle the contrains of the
   SPI controller. I can't think of other method. :-(

 drivers/mtd/devices/m25p80.c |   78 ++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/spi_fsl_lib.c    |    4 ++
 include/linux/spi/spi.h      |    5 +++
 3 files changed, 87 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 47d53c7..f65cca8 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -377,6 +377,81 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
 }
 
 /*
+ * Read an address range from the flash chip page by page.
+ * Some controller has transaction length limitation such as the
+ * Freescale's eSPI controller can only trasmit 0xFFFF bytes one
+ * time, so we have to read page by page if the len is more than
+ * the limitation.
+ */
+static int m25p80_page_read(struct mtd_info *mtd, loff_t from, size_t len,
+	size_t *retlen, u_char *buf)
+{
+	struct m25p *flash = mtd_to_m25p(mtd);
+	struct spi_transfer t[2];
+	struct spi_message m;
+	u32 i, page_size = 0;
+
+	DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
+			dev_name(&flash->spi->dev), __func__, "from",
+			(u32)from, len);
+
+	/* sanity checks */
+	if (!len)
+		return 0;
+
+	if (from + len > flash->mtd.size)
+		return -EINVAL;
+
+	spi_message_init(&m);
+	memset(t, 0, (sizeof t));
+
+	/* NOTE:
+	 * OPCODE_FAST_READ (if available) is faster.
+	 * Should add 1 byte DUMMY_BYTE.
+	 */
+	t[0].tx_buf = flash->command;
+	t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].rx_buf = buf;
+	spi_message_add_tail(&t[1], &m);
+
+	/* Byte count starts at zero. */
+	if (retlen)
+		*retlen = 0;
+
+	mutex_lock(&flash->lock);
+
+	/* Wait till previous write/erase is done. */
+	if (wait_till_ready(flash)) {
+		/* REVISIT status return?? */
+		mutex_unlock(&flash->lock);
+		return 1;
+	}
+
+	/* Set up the write data buffer. */
+	flash->command[0] = OPCODE_READ;
+
+	for (i = page_size; i < len; i += page_size) {
+		page_size = len - i;
+		if (page_size > flash->page_size)
+			page_size = flash->page_size;
+		m25p_addr2cmd(flash, from + i, flash->command);
+		t[1].len = page_size;
+		t[1].rx_buf = buf + i;
+
+		spi_sync(flash->spi, &m);
+
+		*retlen += m.actual_length - m25p_cmdsz(flash)
+			- FAST_READ_DUMMY_BYTE;
+	}
+
+	mutex_unlock(&flash->lock);
+
+	return 0;
+}
+
+/*
  * Write an address range to the flash chip.  Data must be written in
  * FLASH_PAGESIZE chunks.  The address range may be any size provided
  * it is within the physical boundaries.
@@ -874,6 +949,9 @@ static int __devinit m25p_probe(struct spi_device *spi)
 	flash->mtd.erase = m25p80_erase;
 	flash->mtd.read = m25p80_read;
 
+	if (spi->master->quirks & SPI_QUIRK_TRANS_LEN_LIMIT)
+		flash->mtd.read = m25p80_page_read;
+
 	/* sst flash chips use AAI word program */
 	if (info->jedec_id >> 16 == 0xbf)
 		flash->mtd.write = sst_write;
diff --git a/drivers/spi/spi_fsl_lib.c b/drivers/spi/spi_fsl_lib.c
index 5cd741f..c8d8c2d 100644
--- a/drivers/spi/spi_fsl_lib.c
+++ b/drivers/spi/spi_fsl_lib.c
@@ -135,6 +135,10 @@ int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
 	master->cleanup = mpc8xxx_spi_cleanup;
 	master->dev.of_node = dev->of_node;
 
+	if (of_get_property(dev->of_node,
+				"fsl,spi-quirk-trans-len-limit", NULL))
+		master->quirks |= SPI_QUIRK_TRANS_LEN_LIMIT;
+
 	mpc8xxx_spi = spi_master_get_devdata(master);
 	mpc8xxx_spi->dev = dev;
 	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 92e52a1..4234dfd 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -304,6 +304,11 @@ struct spi_master {
 
 	/* called on release() to free memory provided by spi_master */
 	void			(*cleanup)(struct spi_device *spi);
+
+	/* some constraints of the controller */
+	u16			quirks;
+#define SPI_QUIRK_TRANS_LEN_LIMIT	BIT(0)	/* have trans length limit */
+
 };
 
 static inline void *spi_master_get_devdata(struct spi_master *master)
-- 
1.6.4

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

* [PATCH v3 7/7] DTS: add fsl,spi-quirk-trans-len-limit property
  2010-09-30  8:00           ` [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page Mingkai Hu
@ 2010-09-30  8:00             ` Mingkai Hu
  2010-09-30 21:41             ` [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page Grant Likely
  1 sibling, 0 replies; 23+ messages in thread
From: Mingkai Hu @ 2010-09-30  8:00 UTC (permalink / raw)
  To: linuxppc-dev, spi-devel-general, linux-mtd; +Cc: kumar.gala, Mingkai Hu

Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
---
v3:
 - Add "spi-quirk-trans-len-limit" property to the board's dts.

 Documentation/powerpc/dts-bindings/fsl/spi.txt |    3 +++
 arch/powerpc/boot/dts/mpc8536ds.dts            |    1 +
 arch/powerpc/boot/dts/p4080ds.dts              |    1 +
 3 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/Documentation/powerpc/dts-bindings/fsl/spi.txt b/Documentation/powerpc/dts-bindings/fsl/spi.txt
index 777abd7..e1cb84e 100644
--- a/Documentation/powerpc/dts-bindings/fsl/spi.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/spi.txt
@@ -41,6 +41,9 @@ Required properties:
 - interrupts : should contain eSPI interrupt, the device has one interrupt.
 - fsl,espi-num-chipselects : the number of the chipselect signals.
 
+Optional properties:
+- fsl,spi-quirk-trans-len-limit : the max trans length is limited to 0xFFFF.
+
 Example:
 	spi@110000 {
 		#address-cells = <1>;
diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts
index a75c10e..6911c76 100644
--- a/arch/powerpc/boot/dts/mpc8536ds.dts
+++ b/arch/powerpc/boot/dts/mpc8536ds.dts
@@ -116,6 +116,7 @@
 			interrupts = <59 0x2>;
 			interrupt-parent = <&mpic>;
 			fsl,espi-num-chipselects = <4>;
+			fsl,spi-quirk-trans-len-limit;
 
 			flash@0 {
 				#address-cells = <1>;
diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts
index 5b7fc29..060fc45 100644
--- a/arch/powerpc/boot/dts/p4080ds.dts
+++ b/arch/powerpc/boot/dts/p4080ds.dts
@@ -243,6 +243,7 @@
 			interrupts = <53 0x2>;
 			interrupt-parent = <&mpic>;
 			fsl,espi-num-chipselects = <4>;
+			fsl,spi-quirk-trans-len-limit;
 
 			flash@0 {
 				#address-cells = <1>;
-- 
1.6.4

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

* Re: [PATCH v3 5/7] mtd: m25p80: add support to parse the SPI flash's partitions
  2010-09-30  8:00         ` [PATCH v3 5/7] mtd: m25p80: add support to parse the SPI flash's partitions Mingkai Hu
  2010-09-30  8:00           ` [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page Mingkai Hu
@ 2010-09-30 21:34           ` Grant Likely
  2010-10-08  2:42             ` Hu Mingkai-B21284
  1 sibling, 1 reply; 23+ messages in thread
From: Grant Likely @ 2010-09-30 21:34 UTC (permalink / raw)
  To: Mingkai Hu; +Cc: linuxppc-dev, kumar.gala, linux-mtd, spi-devel-general

On Thu, Sep 30, 2010 at 5:00 PM, Mingkai Hu <Mingkai.hu@freescale.com> wrot=
e:
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> ---
> v3:
> =A0- Move the SPI flash partition code to the probe function.
>
> =A0drivers/mtd/devices/m25p80.c | =A0 39 +++++++++++++++++++++++++++-----=
-------
> =A01 files changed, 27 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index 6f512b5..47d53c7 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -772,7 +772,7 @@ static const struct spi_device_id *__devinit jedec_pr=
obe(struct spi_device *spi)
> =A0static int __devinit m25p_probe(struct spi_device *spi)
> =A0{
> =A0 =A0 =A0 =A0const struct spi_device_id =A0 =A0 =A0*id =3D spi_get_devi=
ce_id(spi);
> - =A0 =A0 =A0 struct flash_platform_data =A0 =A0 =A0*data;
> + =A0 =A0 =A0 struct flash_platform_data =A0 =A0 =A0data, *pdata;
> =A0 =A0 =A0 =A0struct m25p =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flash=
;
> =A0 =A0 =A0 =A0struct flash_info =A0 =A0 =A0 =A0 =A0 =A0 =A0 *info;
> =A0 =A0 =A0 =A0unsigned =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0i;
> @@ -782,13 +782,27 @@ static int __devinit m25p_probe(struct spi_device *=
spi)
> =A0 =A0 =A0 =A0 * a chip ID, try the JEDEC id commands; they'll work for =
most
> =A0 =A0 =A0 =A0 * newer chips, even if we don't recognize the particular =
chip.
> =A0 =A0 =A0 =A0 */
> - =A0 =A0 =A0 data =3D spi->dev.platform_data;
> - =A0 =A0 =A0 if (data && data->type) {
> + =A0 =A0 =A0 pdata =3D spi->dev.platform_data;
> + =A0 =A0 =A0 if (!pdata && spi->dev.of_node) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 int nr_parts;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct mtd_partition *parts;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct device_node *np =3D spi->dev.of_node=
;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 nr_parts =3D of_mtd_parse_partitions(&spi->=
dev, np, &parts);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (nr_parts) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata =3D &data;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 memset(pdata, 0, sizeof(*pd=
ata));
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata->parts =3D parts;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata->nr_parts =3D nr_part=
s;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }

Yes, this is the correct way to go about adding the partitions.
However, this patch can be made simpler by not renaming 'data' to
'pdata' and by moving the above code down to just before the partition
information is actually used.  in the OF case, only the parts and the
nr_parts values written into data, and those values aren't used until
the last part of the probe function.

Regardless, in principle this patch is correct:

Acked-by: Grant Likely <grant.likely@secretlab.ca>

> +
> + =A0 =A0 =A0 if (pdata && pdata->type) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const struct spi_device_id *plat_id;
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0for (i =3D 0; i < ARRAY_SIZE(m25p_ids) - 1=
; i++) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0plat_id =3D &m25p_ids[i];
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (strcmp(data->type, plat=
_id->name))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (strcmp(pdata->type, pla=
t_id->name))
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0continue;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> @@ -796,7 +810,8 @@ static int __devinit m25p_probe(struct spi_device *sp=
i)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (i < ARRAY_SIZE(m25p_ids) - 1)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0id =3D plat_id;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&spi->dev, "unreco=
gnized id %s\n", data->type);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&spi->dev, "unreco=
gnized id %s\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 pdata->type);
> =A0 =A0 =A0 =A0}
>
> =A0 =A0 =A0 =A0info =3D (void *)id->driver_data;
> @@ -847,8 +862,8 @@ static int __devinit m25p_probe(struct spi_device *sp=
i)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0write_sr(flash, 0);
> =A0 =A0 =A0 =A0}
>
> - =A0 =A0 =A0 if (data && data->name)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 flash->mtd.name =3D data->name;
> + =A0 =A0 =A0 if (pdata && pdata->name)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 flash->mtd.name =3D pdata->name;
> =A0 =A0 =A0 =A0else
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flash->mtd.name =3D dev_name(&spi->dev);
>
> @@ -919,9 +934,9 @@ static int __devinit m25p_probe(struct spi_device *sp=
i)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0part_probes, &parts, 0);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
>
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (nr_parts <=3D 0 && data && data->parts)=
 {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 parts =3D data->parts;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 nr_parts =3D data->nr_parts=
;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (nr_parts <=3D 0 && pdata && pdata->part=
s) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 parts =3D pdata->parts;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 nr_parts =3D pdata->nr_part=
s;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}

As per my comment earlier; since parts and nr_parts isn't needed
before this point, this block could simply be:

if (nr_parts <=3D 0 && data && data->parts) {
        parts =3D data->parts;
        nr_parts =3D data->nr_parts;
}
if (nr_parts <=3D 0 && spi->dev.of_node)
  =A0 =A0 =A0 nr_parts =3D of_mtd_parse_partitions(&spi->dev, np, &parts);

And most of the other changes to this file goes away.  Simpler, yes?

g.

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

* Re: [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
  2010-09-30  8:00           ` [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page Mingkai Hu
  2010-09-30  8:00             ` [PATCH v3 7/7] DTS: add fsl,spi-quirk-trans-len-limit property Mingkai Hu
@ 2010-09-30 21:41             ` Grant Likely
  1 sibling, 0 replies; 23+ messages in thread
From: Grant Likely @ 2010-09-30 21:41 UTC (permalink / raw)
  To: Mingkai Hu; +Cc: linuxppc-dev, kumar.gala, linux-mtd, spi-devel-general

Hmmm.... for some reason the previous replies didn't get picked up by
patchwork, so I'm replying with my comment again for the public
record.

In this case the eSPI controller driver is buggy and needs to be
fixed.  If the hardware can only support small transfers, then it is
the responsibilty of the driver to chain up smaller chunks into one
big transfer, and make sure that the CS line doesn't go low in the
middle of it.

g.

On Thu, Sep 30, 2010 at 5:00 PM, Mingkai Hu <Mingkai.hu@freescale.com> wrot=
e:
> For Freescale's eSPI controller, the max transaction length one time
> is limitted by the SPCOM[TRANSLEN] field which is 0xFFFF. When used
> mkfs.ext2 command to create ext2 filesystem on the flash, the read
> length will exceed the max value of the SPCOM[TRANSLEN] field, so
> change the read function to read page by page.
>
> For other SPI flash driver, also needed to supply the read function
> if used the eSPI controller.
>
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> ---
> v3:
> =A0- Add a quirks member for the SPI master to handle the contrains of th=
e
> =A0 SPI controller. I can't think of other method. :-(
>
> =A0drivers/mtd/devices/m25p80.c | =A0 78 ++++++++++++++++++++++++++++++++=
++++++++++
> =A0drivers/spi/spi_fsl_lib.c =A0 =A0| =A0 =A04 ++
> =A0include/linux/spi/spi.h =A0 =A0 =A0| =A0 =A05 +++
> =A03 files changed, 87 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index 47d53c7..f65cca8 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -377,6 +377,81 @@ static int m25p80_read(struct mtd_info *mtd, loff_t =
from, size_t len,
> =A0}
>
> =A0/*
> + * Read an address range from the flash chip page by page.
> + * Some controller has transaction length limitation such as the
> + * Freescale's eSPI controller can only trasmit 0xFFFF bytes one
> + * time, so we have to read page by page if the len is more than
> + * the limitation.
> + */
> +static int m25p80_page_read(struct mtd_info *mtd, loff_t from, size_t le=
n,
> + =A0 =A0 =A0 size_t *retlen, u_char *buf)
> +{
> + =A0 =A0 =A0 struct m25p *flash =3D mtd_to_m25p(mtd);
> + =A0 =A0 =A0 struct spi_transfer t[2];
> + =A0 =A0 =A0 struct spi_message m;
> + =A0 =A0 =A0 u32 i, page_size =3D 0;
> +
> + =A0 =A0 =A0 DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_name(&flash->spi->dev),=
 __func__, "from",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (u32)from, len);
> +
> + =A0 =A0 =A0 /* sanity checks */
> + =A0 =A0 =A0 if (!len)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return 0;
> +
> + =A0 =A0 =A0 if (from + len > flash->mtd.size)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
> +
> + =A0 =A0 =A0 spi_message_init(&m);
> + =A0 =A0 =A0 memset(t, 0, (sizeof t));
> +
> + =A0 =A0 =A0 /* NOTE:
> + =A0 =A0 =A0 =A0* OPCODE_FAST_READ (if available) is faster.
> + =A0 =A0 =A0 =A0* Should add 1 byte DUMMY_BYTE.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 t[0].tx_buf =3D flash->command;
> + =A0 =A0 =A0 t[0].len =3D m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
> + =A0 =A0 =A0 spi_message_add_tail(&t[0], &m);
> +
> + =A0 =A0 =A0 t[1].rx_buf =3D buf;
> + =A0 =A0 =A0 spi_message_add_tail(&t[1], &m);
> +
> + =A0 =A0 =A0 /* Byte count starts at zero. */
> + =A0 =A0 =A0 if (retlen)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 *retlen =3D 0;
> +
> + =A0 =A0 =A0 mutex_lock(&flash->lock);
> +
> + =A0 =A0 =A0 /* Wait till previous write/erase is done. */
> + =A0 =A0 =A0 if (wait_till_ready(flash)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* REVISIT status return?? */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mutex_unlock(&flash->lock);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return 1;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Set up the write data buffer. */
> + =A0 =A0 =A0 flash->command[0] =3D OPCODE_READ;
> +
> + =A0 =A0 =A0 for (i =3D page_size; i < len; i +=3D page_size) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 page_size =3D len - i;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (page_size > flash->page_size)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 page_size =3D flash->page_s=
ize;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 m25p_addr2cmd(flash, from + i, flash->comma=
nd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 t[1].len =3D page_size;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 t[1].rx_buf =3D buf + i;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spi_sync(flash->spi, &m);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 *retlen +=3D m.actual_length - m25p_cmdsz(f=
lash)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 - FAST_READ_DUMMY_BYTE;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 mutex_unlock(&flash->lock);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +/*
> =A0* Write an address range to the flash chip. =A0Data must be written in
> =A0* FLASH_PAGESIZE chunks. =A0The address range may be any size provided
> =A0* it is within the physical boundaries.
> @@ -874,6 +949,9 @@ static int __devinit m25p_probe(struct spi_device *sp=
i)
> =A0 =A0 =A0 =A0flash->mtd.erase =3D m25p80_erase;
> =A0 =A0 =A0 =A0flash->mtd.read =3D m25p80_read;
>
> + =A0 =A0 =A0 if (spi->master->quirks & SPI_QUIRK_TRANS_LEN_LIMIT)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 flash->mtd.read =3D m25p80_page_read;
> +
> =A0 =A0 =A0 =A0/* sst flash chips use AAI word program */
> =A0 =A0 =A0 =A0if (info->jedec_id >> 16 =3D=3D 0xbf)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flash->mtd.write =3D sst_write;
> diff --git a/drivers/spi/spi_fsl_lib.c b/drivers/spi/spi_fsl_lib.c
> index 5cd741f..c8d8c2d 100644
> --- a/drivers/spi/spi_fsl_lib.c
> +++ b/drivers/spi/spi_fsl_lib.c
> @@ -135,6 +135,10 @@ int mpc8xxx_spi_probe(struct device *dev, struct res=
ource *mem,
> =A0 =A0 =A0 =A0master->cleanup =3D mpc8xxx_spi_cleanup;
> =A0 =A0 =A0 =A0master->dev.of_node =3D dev->of_node;
>
> + =A0 =A0 =A0 if (of_get_property(dev->of_node,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "fsl,spi-qu=
irk-trans-len-limit", NULL))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 master->quirks |=3D SPI_QUIRK_TRANS_LEN_LIM=
IT;
> +
> =A0 =A0 =A0 =A0mpc8xxx_spi =3D spi_master_get_devdata(master);
> =A0 =A0 =A0 =A0mpc8xxx_spi->dev =3D dev;
> =A0 =A0 =A0 =A0mpc8xxx_spi->get_rx =3D mpc8xxx_spi_rx_buf_u8;
> diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
> index 92e52a1..4234dfd 100644
> --- a/include/linux/spi/spi.h
> +++ b/include/linux/spi/spi.h
> @@ -304,6 +304,11 @@ struct spi_master {
>
> =A0 =A0 =A0 =A0/* called on release() to free memory provided by spi_mast=
er */
> =A0 =A0 =A0 =A0void =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(*cleanup)(str=
uct spi_device *spi);
> +
> + =A0 =A0 =A0 /* some constraints of the controller */
> + =A0 =A0 =A0 u16 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 quirks;
> +#define SPI_QUIRK_TRANS_LEN_LIMIT =A0 =A0 =A0BIT(0) =A0/* have trans len=
gth limit */
> +
> =A0};
>
> =A0static inline void *spi_master_get_devdata(struct spi_master *master)
> --
> 1.6.4
>
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

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

* Re: [PATCH v3 3/7] eSPI: add eSPI controller support
  2010-09-30  8:00     ` [PATCH v3 3/7] eSPI: add eSPI controller support Mingkai Hu
  2010-09-30  8:00       ` [PATCH v3 4/7] powerpc/of: add eSPI controller dts bindings and DTS modification Mingkai Hu
@ 2010-10-01 11:22       ` Anton Vorontsov
  2010-10-08  6:35         ` Hu Mingkai-B21284
  1 sibling, 1 reply; 23+ messages in thread
From: Anton Vorontsov @ 2010-10-01 11:22 UTC (permalink / raw)
  To: Mingkai Hu; +Cc: linuxppc-dev, kumar.gala, linux-mtd, spi-devel-general

Hello Mingkai,

There are mostly cosmetic comments down below.

On Thu, Sep 30, 2010 at 04:00:42PM +0800, Mingkai Hu wrote:
[...]
> +/*
> + * Freescale eSPI controller driver.
> + *
> + * Copyright 2010 Freescale Semiconductor, Inc.
> + *
> + * 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.
> + */
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/irq.h>
> +#include <linux/spi/spi.h>
> +#include <linux/platform_device.h>
> +#include <linux/fsl_devices.h>
> +#include <linux/mm.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_spi.h>
> +#include <sysdev/fsl_soc.h>

Please move the sysdev/ include after linux/.
Will make it a bit prettier. :-)

> +#include <linux/interrupt.h>
> +#include <linux/err.h>
> +
> +#include "spi_fsl_lib.h"
[...]
> +static void fsl_espi_change_mode(struct spi_device *spi)
> +{
> +	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
> +	struct spi_mpc8xxx_cs *cs = spi->controller_state;
> +	struct fsl_espi_reg *reg_base = (struct fsl_espi_reg *)mspi->reg_base;

No need for the type cast. The same for the rest of the code.

> +	__be32 __iomem *mode;
> +	__be32 __iomem *espi_mode = NULL;
> +	u32 tmp;
> +	unsigned long flags;
> +
> +	espi_mode = &reg_base->mode;
> +	mode = &reg_base->csmode[spi->chip_select];

Could save a few lines by turning this into initializers.

> +
> +	/* Turn off IRQs locally to minimize time that SPI is disabled. */
> +	local_irq_save(flags);
> +
> +	/* Turn off SPI unit prior changing mode */
> +	tmp = mpc8xxx_spi_read_reg(espi_mode);
> +	mpc8xxx_spi_write_reg(espi_mode, tmp & ~SPMODE_ENABLE);
> +	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
> +	mpc8xxx_spi_write_reg(espi_mode, tmp);
> +
> +	local_irq_restore(flags);
> +}
> +
> +static u32 fsl_espi_tx_buf_lsb(struct mpc8xxx_spi *mpc8xxx_spi)
> +{
> +	u32 data;
> +	u16 data_h, data_l;

u16 data_h;
u16 data_l;

> +

No need for this empty line.

> +	const u32 *tx = mpc8xxx_spi->tx;

<- Instead, add an empty line here.

> +	if (!tx)
> +		return 0;
> +
> +	data = *tx++ << mpc8xxx_spi->tx_shift;
> +	data_l = data & 0xffff;
> +	data_h = (data >> 16) & 0xffff;
> +	swab16s(&data_l);
> +	swab16s(&data_h);
> +	data = data_h | data_l;
> +
> +	mpc8xxx_spi->tx = tx;
> +	return data;
> +}
> +
> +static int fsl_espi_setup_transfer(struct spi_device *spi,
> +					struct spi_transfer *t)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	int bits_per_word = 0;
> +	u8 pm;
> +	u32 hz = 0;
> +	struct spi_mpc8xxx_cs	*cs = spi->controller_state;

Stray tab.

> +
> +	mpc8xxx_spi = spi_master_get_devdata(spi->master);

Could move this to the initializer.

> +
> +	if (t) {
> +		bits_per_word = t->bits_per_word;
> +		hz = t->speed_hz;
> +	}
> +
> +	/* spi_transfer level calls that work per-word */
> +	if (!bits_per_word)
> +		bits_per_word = spi->bits_per_word;
> +
> +	/* Make sure its a bit width we support [4..16] */
> +	if ((bits_per_word < 4) || (bits_per_word > 16))
> +		return -EINVAL;
> +
> +	if (!hz)
> +		hz = spi->max_speed_hz;
> +
> +	cs->rx_shift = 0;
> +	cs->tx_shift = 0;
> +	cs->get_rx = mpc8xxx_spi_rx_buf_u32;
> +	cs->get_tx = mpc8xxx_spi_tx_buf_u32;
> +	if (bits_per_word <= 8) {
> +		cs->rx_shift = 8 - bits_per_word;
> +	} else if (bits_per_word <= 16) {
> +		cs->rx_shift = 16 - bits_per_word;
> +		if (spi->mode & SPI_LSB_FIRST)
> +			cs->get_tx = fsl_espi_tx_buf_lsb;
> +	} else
> +		return -EINVAL;

} else {
}

> +
> +	mpc8xxx_spi->rx_shift = cs->rx_shift;
> +	mpc8xxx_spi->tx_shift = cs->tx_shift;
> +	mpc8xxx_spi->get_rx = cs->get_rx;
> +	mpc8xxx_spi->get_tx = cs->get_tx;
> +
> +	bits_per_word = bits_per_word - 1;
> +
> +	/* mask out bits we are going to set */
> +	cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16
> +				  | CSMODE_PM(0xF));

No need to break this statement.

> +
> +	cs->hw_mode |= CSMODE_LEN(bits_per_word);
> +
> +	if ((mpc8xxx_spi->spibrg / hz) > 64) {
> +		cs->hw_mode |= CSMODE_DIV16;
> +		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
> +
> +		WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
> +			  "Will use %d Hz instead.\n", dev_name(&spi->dev),
> +			  hz, mpc8xxx_spi->spibrg / 1024);
> +		if (pm > 16)
> +			pm = 16;
> +	} else {
> +		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
> +	}
> +	if (pm)
> +		pm--;
> +
> +	cs->hw_mode |= CSMODE_PM(pm);
> +
> +	fsl_espi_change_mode(spi);
> +	return 0;
> +}
> +
> +int fsl_espi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t,
> +		unsigned int len)

Does this need to be global?

> +{
> +	u32 word;
> +	struct fsl_espi_reg *reg_base = (struct fsl_espi_reg *)mspi->reg_base;
> +
> +	mspi->count = len;
> +
> +	/* enable rx ints */
> +	mpc8xxx_spi_write_reg(&reg_base->mask, SPIM_NE);
> +
> +	/* transmit word */
> +	word = mspi->get_tx(mspi);
> +	mpc8xxx_spi_write_reg(&reg_base->transmit, word);
> +
> +	return 0;
> +}
> +
> +static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t,
> +			    bool is_dma_mapped)

No need for the is_dma_mapped argument.

> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +	struct fsl_espi_reg *reg_base;
> +	unsigned int len = t->len;
> +	u8 bits_per_word;
> +	int ret;
> +
> +	reg_base = (struct fsl_espi_reg *)mpc8xxx_spi->reg_base;

Better write this as an initializer, no need for the cast.

> +
> +	bits_per_word = spi->bits_per_word;
> +	if (t->bits_per_word)
> +		bits_per_word = t->bits_per_word;
[...]
> +static int fsl_espi_setup(struct spi_device *spi)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	struct fsl_espi_reg *reg_base;
> +	int retval;
> +	u32 hw_mode;
> +	u32 loop_mode;
> +	struct spi_mpc8xxx_cs	*cs = spi->controller_state;

Stray tab.

> +
> +	if (!spi->max_speed_hz)
> +		return -EINVAL;
> +
> +	if (!cs) {
> +		cs = kzalloc(sizeof *cs, GFP_KERNEL);
> +		if (!cs)
> +			return -ENOMEM;
> +		spi->controller_state = cs;
> +	}
[...]
> +		rx_data = mpc8xxx_spi_read_reg(&reg_base->receive);
> +
> +		if (mspi->rx)
> +			mspi->get_rx(rx_data, mspi);
> +	}
> +
> +	if ((events & SPIE_NF) == 0)

if (!(events & bit)) is a bit more more natural. Also, the if
statement here needs braces.

> +		/* spin until TX is done */
> +		while (((events = mpc8xxx_spi_read_reg(&reg_base->event))
> +					& SPIE_NF) == 0)
> +			cpu_relax();

This is dangerous. There's a handy spin_event_timeout()
in asm/delay.h.

> +
> +	/* Clear the events */
> +	mpc8xxx_spi_write_reg(&reg_base->event, events);
> +
> +	mspi->count -= 1;
> +	if (mspi->count) {
> +		u32 word = mspi->get_tx(mspi);
> +
> +		mpc8xxx_spi_write_reg(&reg_base->transmit, word);
> +	} else {
> +		complete(&mspi->done);
> +	}
> +}
> +
> +static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
> +{
> +	struct mpc8xxx_spi *mspi = context_data;
> +	struct fsl_espi_reg *reg_base = (struct fsl_espi_reg *)mspi->reg_base;
> +	irqreturn_t ret = IRQ_NONE;
> +	u32 events;
> +
> +	/* Get interrupt events(tx/rx) */
> +	events = mpc8xxx_spi_read_reg(&reg_base->event);
> +	if (events)
> +		ret = IRQ_HANDLED;
> +
> +	dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);

dev_vdbg()

> +
> +	fsl_espi_cpu_irq(mspi, events);
> +
> +	return ret;
> +}
> +
> +static void fsl_espi_remove(struct mpc8xxx_spi *mspi)
> +{
> +	iounmap(mspi->reg_base);
> +}
> +
> +static struct spi_master * __devinit fsl_espi_probe(struct device *dev,
> +		struct resource *mem, unsigned int irq)
> +{
> +	struct fsl_spi_platform_data *pdata = dev->platform_data;
> +	struct spi_master *master;
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	struct fsl_espi_reg *reg_base;
> +	u32 regval;
> +	int i, ret = 0;
> +
> +	master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
> +	if (master == NULL) {

Sometimes you check for !allocated, and sometimes allocated == NULL.
Be consistent. (And !allocated is more natural.)

> +		ret = -ENOMEM;
> +		goto err;
> +	}
> +
> +	dev_set_drvdata(dev, master);
> +
> +	ret = mpc8xxx_spi_probe(dev, mem, irq);
> +	if (ret)
> +		goto err_probe;
> +
> +	master->setup = fsl_espi_setup;
> +
> +	mpc8xxx_spi = spi_master_get_devdata(master);
> +	mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg;
> +	mpc8xxx_spi->spi_remove = fsl_espi_remove;
> +
> +	mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
> +	if (mpc8xxx_spi->reg_base == NULL) {

Ditto.

> +		ret = -ENOMEM;
> +		goto err_probe;
> +	}
> +
> +	reg_base = (struct fsl_espi_reg *)mpc8xxx_spi->reg_base;
> +
> +	/* Register for SPI Interrupt */
> +	ret = request_irq(mpc8xxx_spi->irq, fsl_espi_irq,
> +			  0, "fsl_espi", mpc8xxx_spi);
> +
> +	if (ret != 0)

Every time someone writes 'if (rc != 0)', a kitty dies.
Simple 'if (rc)' saves kittens.

> +		goto free_irq;
> +
> +	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
> +		mpc8xxx_spi->rx_shift = 16;
> +		mpc8xxx_spi->tx_shift = 24;
> +	}
[...]
> +
> +static int __devexit of_fsl_espi_remove(struct platform_device *dev)
> +{
> +	int ret;
> +
> +	ret = mpc8xxx_spi_remove(&dev->dev);
> +	if (ret)
> +		return ret;
> +
> +	return 0;

Just 'return mpc8xxx_spi_remove(&dev->dev);' is sufficient.

Also, I think there's no need for this wrapper nowadays (but
splitting OF and real probe() stuff is still appropriate).

> +}
> +
> +static const struct of_device_id of_fsl_espi_match[] = {
> +	{ .compatible = "fsl,mpc8536-espi" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, of_fsl_espi_match);
> +
> +static struct of_platform_driver fsl_espi_driver = {
> +	.driver = {
> +		.name = "fsl_espi",
> +		.owner = THIS_MODULE,
> +		.of_match_table = of_fsl_espi_match,
> +	},
> +	.probe		= of_fsl_espi_probe,
> +	.remove		= __devexit_p(of_fsl_espi_remove),
> +};
> +
> +static int __init fsl_espi_init(void)
> +{
> +	return of_register_platform_driver(&fsl_espi_driver);
> +}
> +module_init(fsl_espi_init);
> +
> +static void __exit fsl_espi_exit(void)
> +{
> +	of_unregister_platform_driver(&fsl_espi_driver);
> +}
> +module_exit(fsl_espi_exit);
> +
> +MODULE_AUTHOR("Mingkai Hu");
> +MODULE_DESCRIPTION("Enhanced Freescale SPI Driver");

This sounds like that this is an enhanced version of the
Freescale SPI driver, which it is not. ;-)

> +MODULE_LICENSE("GPL");
> diff --git a/drivers/spi/spi_fsl_lib.h b/drivers/spi/spi_fsl_lib.h
> index 6ae8949..9c81498 100644
> --- a/drivers/spi/spi_fsl_lib.h
> +++ b/drivers/spi/spi_fsl_lib.h
> @@ -26,6 +26,7 @@ struct mpc8xxx_spi {
>  	/* rx & tx bufs from the spi_transfer */
>  	const void *tx;
>  	void *rx;
> +	int len;

I'd place the #ifdef CONFIG_SPI_ESPI, for documentation purposes.

Thanks,

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

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

* Re: [PATCH v3 2/7] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
  2010-09-30  8:00   ` [PATCH v3 2/7] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Mingkai Hu
  2010-09-30  8:00     ` [PATCH v3 3/7] eSPI: add eSPI controller support Mingkai Hu
@ 2010-10-01 11:22     ` Anton Vorontsov
  2010-10-08  6:37       ` Hu Mingkai-B21284
  1 sibling, 1 reply; 23+ messages in thread
From: Anton Vorontsov @ 2010-10-01 11:22 UTC (permalink / raw)
  To: Mingkai Hu; +Cc: linuxppc-dev, kumar.gala, linux-mtd, spi-devel-general

On Thu, Sep 30, 2010 at 04:00:41PM +0800, Mingkai Hu wrote:
[...]
> -static void mpc8xxx_spi_change_mode(struct spi_device *spi)
> +static void fsl_spi_change_mode(struct spi_device *spi)
>  {
>  	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
>  	struct spi_mpc8xxx_cs *cs = spi->controller_state;
> -	__be32 __iomem *mode = &mspi->base->mode;
> +	struct fsl_spi_reg *reg_base = (struct fsl_spi_reg *)mspi->reg_base;

No need for these type casts (the same is for the whole patch).

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

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

* RE: [PATCH v3 5/7] mtd: m25p80: add support to parse the SPI flash's partitions
  2010-09-30 21:34           ` [PATCH v3 5/7] mtd: m25p80: add support to parse the SPI flash's partitions Grant Likely
@ 2010-10-08  2:42             ` Hu Mingkai-B21284
  0 siblings, 0 replies; 23+ messages in thread
From: Hu Mingkai-B21284 @ 2010-10-08  2:42 UTC (permalink / raw)
  To: Grant Likely
  Cc: linuxppc-dev, Gala Kumar-B11780, linux-mtd, Zang Roy-R61911,
	spi-devel-general



> -----Original Message-----
> From: glikely@secretlab.ca [mailto:glikely@secretlab.ca] On Behalf Of =
Grant
> Likely
> Sent: Friday, October 01, 2010 5:35 AM
> To: Hu Mingkai-B21284
> Cc: linuxppc-dev@ozlabs.org; spi-devel-general@lists.sourceforge.net; =
linux-
> mtd@lists.infradead.org; Gala Kumar-B11780; Zang Roy-R61911
> Subject: Re: [PATCH v3 5/7] mtd: m25p80: add support to parse the SPI =
flash's
> partitions
>=20
> On Thu, Sep 30, 2010 at 5:00 PM, Mingkai Hu <Mingkai.hu@freescale.com> =
wrote:
> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> > ---
> > v3:
> > =A0- Move the SPI flash partition code to the probe function.
> >
> > =A0drivers/mtd/devices/m25p80.c | =A0 39 =
+++++++++++++++++++++++++++------------
> > =A01 files changed, 27 insertions(+), 12 deletions(-)
> >
> > diff --git a/drivers/mtd/devices/m25p80.c =
b/drivers/mtd/devices/m25p80.c
> > index 6f512b5..47d53c7 100644
> > --- a/drivers/mtd/devices/m25p80.c
> > +++ b/drivers/mtd/devices/m25p80.c
> > @@ -772,7 +772,7 @@ static const struct spi_device_id *__devinit
> jedec_probe(struct spi_device *spi)
> > =A0static int __devinit m25p_probe(struct spi_device *spi)
> > =A0{
> > =A0 =A0 =A0 =A0const struct spi_device_id =A0 =A0 =A0*id =3D =
spi_get_device_id(spi);
> > - =A0 =A0 =A0 struct flash_platform_data =A0 =A0 =A0*data;
> > + =A0 =A0 =A0 struct flash_platform_data =A0 =A0 =A0data, *pdata;
> > =A0 =A0 =A0 =A0struct m25p =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
*flash;
> > =A0 =A0 =A0 =A0struct flash_info =A0 =A0 =A0 =A0 =A0 =A0 =A0 *info;
> > =A0 =A0 =A0 =A0unsigned =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0i;
> > @@ -782,13 +782,27 @@ static int __devinit m25p_probe(struct =
spi_device *spi)
> > =A0 =A0 =A0 =A0 * a chip ID, try the JEDEC id commands; they'll work =
for most
> > =A0 =A0 =A0 =A0 * newer chips, even if we don't recognize the =
particular chip.
> > =A0 =A0 =A0 =A0 */
> > - =A0 =A0 =A0 data =3D spi->dev.platform_data;
> > - =A0 =A0 =A0 if (data && data->type) {
> > + =A0 =A0 =A0 pdata =3D spi->dev.platform_data;
> > + =A0 =A0 =A0 if (!pdata && spi->dev.of_node) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 int nr_parts;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct mtd_partition *parts;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct device_node *np =3D =
spi->dev.of_node;
> > +
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 nr_parts =3D =
of_mtd_parse_partitions(&spi->dev, np, &parts);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (nr_parts) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata =3D &data;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 memset(pdata, 0, =
sizeof(*pdata));
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata->parts =3D =
parts;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata->nr_parts =3D =
nr_parts;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > + =A0 =A0 =A0 }
>=20
> Yes, this is the correct way to go about adding the partitions.
> However, this patch can be made simpler by not renaming 'data' to
> 'pdata' and by moving the above code down to just before the partition
> information is actually used.  in the OF case, only the parts and the
> nr_parts values written into data, and those values aren't used until
> the last part of the probe function.
>=20
> Regardless, in principle this patch is correct:
>=20
> Acked-by: Grant Likely <grant.likely@secretlab.ca>
>=20
> > +
> > + =A0 =A0 =A0 if (pdata && pdata->type) {
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const struct spi_device_id *plat_id;
> >
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0for (i =3D 0; i < =
ARRAY_SIZE(m25p_ids) - 1; i++) {
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0plat_id =3D =
&m25p_ids[i];
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (strcmp(data->type, =
plat_id->name))
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if =
(strcmp(pdata->type, plat_id->name))
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0continue;
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> > @@ -796,7 +810,8 @@ static int __devinit m25p_probe(struct =
spi_device *spi)
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (i < ARRAY_SIZE(m25p_ids) - 1)
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0id =3D plat_id;
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&spi->dev, =
"unrecognized id %s\n", data-
> >type);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&spi->dev, =
"unrecognized id %s\n",
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 pdata->type);
> > =A0 =A0 =A0 =A0}
> >
> > =A0 =A0 =A0 =A0info =3D (void *)id->driver_data;
> > @@ -847,8 +862,8 @@ static int __devinit m25p_probe(struct =
spi_device *spi)
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0write_sr(flash, 0);
> > =A0 =A0 =A0 =A0}
> >
> > - =A0 =A0 =A0 if (data && data->name)
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 flash->mtd.name =3D data->name;
> > + =A0 =A0 =A0 if (pdata && pdata->name)
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 flash->mtd.name =3D pdata->name;
> > =A0 =A0 =A0 =A0else
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flash->mtd.name =3D =
dev_name(&spi->dev);
> >
> > @@ -919,9 +934,9 @@ static int __devinit m25p_probe(struct =
spi_device *spi)
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0part_probes, &parts, 0);
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> >
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (nr_parts <=3D 0 && data && =
data->parts) {
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 parts =3D data->parts;
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 nr_parts =3D =
data->nr_parts;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (nr_parts <=3D 0 && pdata && =
pdata->parts) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 parts =3D =
pdata->parts;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 nr_parts =3D =
pdata->nr_parts;
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
>=20
> As per my comment earlier; since parts and nr_parts isn't needed
> before this point, this block could simply be:
>=20
> if (nr_parts <=3D 0 && data && data->parts) {
>         parts =3D data->parts;
>         nr_parts =3D data->nr_parts;
> }
> if (nr_parts <=3D 0 && spi->dev.of_node)
>   =A0 =A0 =A0 nr_parts =3D of_mtd_parse_partitions(&spi->dev, np, =
&parts);
>=20
> And most of the other changes to this file goes away.  Simpler, yes?
>=20

Yes, you're right, I'll fix it. Also thanks for your suggestion and ACK.

Thanks,
Mingkai

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

* RE: [PATCH v3 3/7] eSPI: add eSPI controller support
  2010-10-01 11:22       ` [PATCH v3 3/7] eSPI: add eSPI controller support Anton Vorontsov
@ 2010-10-08  6:35         ` Hu Mingkai-B21284
  0 siblings, 0 replies; 23+ messages in thread
From: Hu Mingkai-B21284 @ 2010-10-08  6:35 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: linuxppc-dev, Gala Kumar-B11780, linux-mtd, spi-devel-general

DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogQW50b24gVm9yb250c292
IFttYWlsdG86Y2JvdWF0bWFpbHJ1QGdtYWlsLmNvbV0NCj4gU2VudDogRnJpZGF5LCBPY3RvYmVy
IDAxLCAyMDEwIDc6MjIgUE0NCj4gVG86IEh1IE1pbmdrYWktQjIxMjg0DQo+IENjOiBsaW51eHBw
Yy1kZXZAb3psYWJzLm9yZzsgc3BpLWRldmVsLWdlbmVyYWxAbGlzdHMuc291cmNlZm9yZ2UubmV0
OyBsaW51eC0NCj4gbXRkQGxpc3RzLmluZnJhZGVhZC5vcmc7IEdhbGEgS3VtYXItQjExNzgwDQo+
IFN1YmplY3Q6IFJlOiBbUEFUQ0ggdjMgMy83XSBlU1BJOiBhZGQgZVNQSSBjb250cm9sbGVyIHN1
cHBvcnQNCj4gDQo+IEhlbGxvIE1pbmdrYWksDQo+IA0KPiBUaGVyZSBhcmUgbW9zdGx5IGNvc21l
dGljIGNvbW1lbnRzIGRvd24gYmVsb3cuDQo+IA0KPiA+ICsJCS8qIHNwaW4gdW50aWwgVFggaXMg
ZG9uZSAqLw0KPiA+ICsJCXdoaWxlICgoKGV2ZW50cyA9IG1wYzh4eHhfc3BpX3JlYWRfcmVnKCZy
ZWdfYmFzZS0+ZXZlbnQpKQ0KPiA+ICsJCQkJCSYgU1BJRV9ORikgPT0gMCkNCj4gPiArCQkJY3B1
X3JlbGF4KCk7DQo+IA0KPiBUaGlzIGlzIGRhbmdlcm91cy4gVGhlcmUncyBhIGhhbmR5IHNwaW5f
ZXZlbnRfdGltZW91dCgpIGluIGFzbS9kZWxheS5oLg0KPiANCg0KV2hlbiB0aW1lb3V0LCBjYW4g
SSB1c2UgcmV0dXJuIGluIHRoZSBpbnRlcnJ1cHQgZnVuY3Rpb24gZGlyZWN0bHkgbGlrZSB0aGlz
Pw0KDQppZiAoIShldmVudHMgJiBTUElFX05GKSkgew0KICAgICAgICBpbnQgcmV0Ow0KICAgICAg
ICAvKiBzcGluIHVudGlsIFRYIGlzIGRvbmUgKi8NCiAgICAgICAgcmV0ID0gc3Bpbl9ldmVudF90
aW1lb3V0KCgoZXZlbnRzID0gbXBjOHh4eF9zcGlfcmVhZF9yZWcoDQogICAgICAgICAgICAgICAg
ICAgICAgICAmcmVnX2Jhc2UtPmV2ZW50KSkgJiBTUElFX05GKSA9PSAwLCAxMDAwLCAwKTsNCiAg
ICAgICAgaWYgKCFyZXQpIHsNCiAgICAgICAgICAgICAgICBkZXZfZXJyKG1zcGktPmRldiwgInRp
cmVkIHdhaXRpbmcgZm9yIFNQSUVfTkZcbiIpOw0KICAgICAgICAgICAgICAgIHJldHVybjsNCiAg
ICAgICAgfQ0KfQ0KDQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3Qgb2Zf
ZGV2aWNlX2lkIG9mX2ZzbF9lc3BpX21hdGNoW10gPSB7DQo+ID4gKwl7IC5jb21wYXRpYmxlID0g
ImZzbCxtcGM4NTM2LWVzcGkiIH0sDQo+ID4gKwl7fQ0KPiA+ICt9Ow0KPiA+ICtNT0RVTEVfREVW
SUNFX1RBQkxFKG9mLCBvZl9mc2xfZXNwaV9tYXRjaCk7DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3Ry
dWN0IG9mX3BsYXRmb3JtX2RyaXZlciBmc2xfZXNwaV9kcml2ZXIgPSB7DQo+ID4gKwkuZHJpdmVy
ID0gew0KPiA+ICsJCS5uYW1lID0gImZzbF9lc3BpIiwNCj4gPiArCQkub3duZXIgPSBUSElTX01P
RFVMRSwNCj4gPiArCQkub2ZfbWF0Y2hfdGFibGUgPSBvZl9mc2xfZXNwaV9tYXRjaCwNCj4gPiAr
CX0sDQo+ID4gKwkucHJvYmUJCT0gb2ZfZnNsX2VzcGlfcHJvYmUsDQo+ID4gKwkucmVtb3ZlCQk9
IF9fZGV2ZXhpdF9wKG9mX2ZzbF9lc3BpX3JlbW92ZSksDQo+ID4gK307DQo+ID4gKw0KPiA+ICtz
dGF0aWMgaW50IF9faW5pdCBmc2xfZXNwaV9pbml0KHZvaWQpIHsNCj4gPiArCXJldHVybiBvZl9y
ZWdpc3Rlcl9wbGF0Zm9ybV9kcml2ZXIoJmZzbF9lc3BpX2RyaXZlcik7DQo+ID4gK30NCj4gPiAr
bW9kdWxlX2luaXQoZnNsX2VzcGlfaW5pdCk7DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBfX2V4
aXQgZnNsX2VzcGlfZXhpdCh2b2lkKSB7DQo+ID4gKwlvZl91bnJlZ2lzdGVyX3BsYXRmb3JtX2Ry
aXZlcigmZnNsX2VzcGlfZHJpdmVyKTsNCj4gPiArfQ0KPiA+ICttb2R1bGVfZXhpdChmc2xfZXNw
aV9leGl0KTsNCj4gPiArDQo+ID4gK01PRFVMRV9BVVRIT1IoIk1pbmdrYWkgSHUiKTsNCj4gPiAr
TU9EVUxFX0RFU0NSSVBUSU9OKCJFbmhhbmNlZCBGcmVlc2NhbGUgU1BJIERyaXZlciIpOw0KPiAN
Cj4gVGhpcyBzb3VuZHMgbGlrZSB0aGF0IHRoaXMgaXMgYW4gZW5oYW5jZWQgdmVyc2lvbiBvZiB0
aGUgRnJlZXNjYWxlIFNQSSBkcml2ZXIsDQo+IHdoaWNoIGl0IGlzIG5vdC4gOy0pDQo+IA0KDQpJ
IHF1b3RlZCBmcm9tIHRoZSBVTSwgbWF5YmUgdGhlIGVuaGFuY2VtZW50IGlzIHRoZSBjb250cm9s
bGVyIHRha2VzIG92ZXIgdGhlDQpDUyBzaWduYWwgZnJvbSB0aGUgSFcgcG9pbnQgdmlldy4NCg0K
SSBjaGFuZ2VkIGFsbCB0aGUgb3RoZXIgY29kZSBhY2NvcmRpbmcgdG8geW91ciBjb21tZW50cy4N
Cg0KVGhhbmtzLA0KTWluZ2thaQ0KDQo=

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

* RE: [PATCH v3 2/7] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
  2010-10-01 11:22     ` [PATCH v3 2/7] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Anton Vorontsov
@ 2010-10-08  6:37       ` Hu Mingkai-B21284
  0 siblings, 0 replies; 23+ messages in thread
From: Hu Mingkai-B21284 @ 2010-10-08  6:37 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: linuxppc-dev, Gala Kumar-B11780, linux-mtd, Zang Roy-R61911,
	spi-devel-general

DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogQW50b24gVm9yb250c292
IFttYWlsdG86Y2JvdWF0bWFpbHJ1QGdtYWlsLmNvbV0NCj4gU2VudDogRnJpZGF5LCBPY3RvYmVy
IDAxLCAyMDEwIDc6MjIgUE0NCj4gVG86IEh1IE1pbmdrYWktQjIxMjg0DQo+IENjOiBsaW51eHBw
Yy1kZXZAb3psYWJzLm9yZzsgc3BpLWRldmVsLWdlbmVyYWxAbGlzdHMuc291cmNlZm9yZ2UubmV0
OyBsaW51eC0NCj4gbXRkQGxpc3RzLmluZnJhZGVhZC5vcmc7IEdhbGEgS3VtYXItQjExNzgwOyBa
YW5nIFJveS1SNjE5MTENCj4gU3ViamVjdDogUmU6IFtQQVRDSCB2MyAyLzddIHNwaS9tcGM4eHh4
OiByZWZhY3RvciB0aGUgY29tbW9uIGNvZGUgZm9yIFNQSS9lU1BJDQo+IGNvbnRyb2xsZXINCj4g
DQo+IE9uIFRodSwgU2VwIDMwLCAyMDEwIGF0IDA0OjAwOjQxUE0gKzA4MDAsIE1pbmdrYWkgSHUg
d3JvdGU6DQo+IFsuLi5dDQo+ID4gLXN0YXRpYyB2b2lkIG1wYzh4eHhfc3BpX2NoYW5nZV9tb2Rl
KHN0cnVjdCBzcGlfZGV2aWNlICpzcGkpDQo+ID4gK3N0YXRpYyB2b2lkIGZzbF9zcGlfY2hhbmdl
X21vZGUoc3RydWN0IHNwaV9kZXZpY2UgKnNwaSkNCj4gPiAgew0KPiA+ICAJc3RydWN0IG1wYzh4
eHhfc3BpICptc3BpID0gc3BpX21hc3Rlcl9nZXRfZGV2ZGF0YShzcGktPm1hc3Rlcik7DQo+ID4g
IAlzdHJ1Y3Qgc3BpX21wYzh4eHhfY3MgKmNzID0gc3BpLT5jb250cm9sbGVyX3N0YXRlOw0KPiA+
IC0JX19iZTMyIF9faW9tZW0gKm1vZGUgPSAmbXNwaS0+YmFzZS0+bW9kZTsNCj4gPiArCXN0cnVj
dCBmc2xfc3BpX3JlZyAqcmVnX2Jhc2UgPSAoc3RydWN0IGZzbF9zcGlfcmVnICopbXNwaS0+cmVn
X2Jhc2U7DQo+IA0KPiBObyBuZWVkIGZvciB0aGVzZSB0eXBlIGNhc3RzICh0aGUgc2FtZSBpcyBm
b3IgdGhlIHdob2xlIHBhdGNoKS4NCj4gDQoNCkZpeCBpdC4NCg0KVGhhbmtzLA0KTWluZ2thaQ0K

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

* Re: [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
  2010-10-08  2:15       ` Hu Mingkai-B21284
@ 2010-10-08  6:11         ` Kumar Gala
  0 siblings, 0 replies; 23+ messages in thread
From: Kumar Gala @ 2010-10-08  6:11 UTC (permalink / raw)
  To: Hu Mingkai-B21284
  Cc: David Brownell, linuxppc-dev, linux-mtd, spi-devel-general,
	Gala Kumar-B11780


On Oct 7, 2010, at 9:15 PM, Hu Mingkai-B21284 wrote:

>>>> Yes, I agree with David on this.  If large transfers don't work,
>>>> then it is the SPI master driver that is buggy.
>>>=20
>>> By the way, does this fix your problem?
>>>=20
>>> https://patchwork.kernel.org/patch/184752/
>>=20
>> It shouldn't. AFAIK, eSPI is PIO-only controller, and the overrun fix =
is for the
>> DMA mode.
>>=20
>> Thanks,
>>=20
>> p.s. Btw, in patch 3/7, is_dma_mapped argument of fsl_espi_bufs() is =
unneeded.
>>=20
>=20
> Yes, the is_dma_mapped isn't needed, I'll remove it.
>=20
> Thanks,
> Mingkai

I'd be really nice if we could close on this patchset in time for .37 =
acceptance.  I'm guessing that cutoff is quickly approaching.

- k=

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

* RE: [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
  2010-09-30 15:06     ` Anton Vorontsov
  2010-09-30 20:57       ` Grant Likely
@ 2010-10-08  2:15       ` Hu Mingkai-B21284
  2010-10-08  6:11         ` Kumar Gala
  1 sibling, 1 reply; 23+ messages in thread
From: Hu Mingkai-B21284 @ 2010-10-08  2:15 UTC (permalink / raw)
  To: Anton Vorontsov, Grant Likely
  Cc: David Brownell, linuxppc-dev, Gala Kumar-B11780, linux-mtd,
	spi-devel-general

DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogQW50b24gVm9yb250c292
IFttYWlsdG86Y2JvdWF0bWFpbHJ1QGdtYWlsLmNvbV0NCj4gU2VudDogVGh1cnNkYXksIFNlcHRl
bWJlciAzMCwgMjAxMCAxMTowNyBQTQ0KPiBUbzogR3JhbnQgTGlrZWx5DQo+IENjOiBEYXZpZCBC
cm93bmVsbDsgbGludXhwcGMtZGV2QG96bGFicy5vcmc7IEh1IE1pbmdrYWktQjIxMjg0OyBsaW51
eC0NCj4gbXRkQGxpc3RzLmluZnJhZGVhZC5vcmc7IEdhbGEgS3VtYXItQjExNzgwOyBzcGktZGV2
ZWwtDQo+IGdlbmVyYWxAbGlzdHMuc291cmNlZm9yZ2UubmV0DQo+IFN1YmplY3Q6IFJlOiBbUEFU
Q0ggdjMgNi83XSBtdGQ6IG0yNXA4MDogYWRkIGEgcmVhZCBmdW5jdGlvbiB0byByZWFkIHBhZ2Ug
YnkNCj4gcGFnZQ0KPiANCj4gT24gVGh1LCBTZXAgMzAsIDIwMTAgYXQgMTE6NDE6NDBQTSArMDkw
MCwgR3JhbnQgTGlrZWx5IHdyb3RlOg0KPiA+IE9uIFRodSwgU2VwIDMwLCAyMDEwIGF0IDExOjE2
IFBNLCBHcmFudCBMaWtlbHkNCj4gPiA8Z3JhbnQubGlrZWx5QHNlY3JldGxhYi5jYT4gd3JvdGU6
DQo+ID4gPiBPbiBUaHUsIFNlcCAzMCwgMjAxMCBhdCA3OjQ2IFBNLCBEYXZpZCBCcm93bmVsbCA8
ZGF2aWQtYkBwYWNiZWxsLm5ldD4gd3JvdGU6DQo+ID4gPj4NCj4gPiA+PiAtLS0gT24gVGh1LCA5
LzMwLzEwLCBNaW5na2FpIEh1IDxNaW5na2FpLmh1QGZyZWVzY2FsZS5jb20+IHdyb3RlOg0KPiA+
ID4+DQo+ID4gPj4+IEZyb206IE1pbmdrYWkgSHUgPE1pbmdrYWkuaHVAZnJlZXNjYWxlLmNvbT4N
Cj4gPiA+Pj4gU3ViamVjdDogW1BBVENIIHYzIDYvN10gbXRkOiBtMjVwODA6IGFkZCBhIHJlYWQg
ZnVuY3Rpb24gdG8gcmVhZA0KPiA+ID4+PiBwYWdlIGJ5IHBhZ2UNCj4gPiA+Pg0KPiA+ID4+IE5B
Sy4NCj4gPiA+Pg0KPiA+ID4+IFdlIHdlbnQgb3ZlciB0aGlzIGJlZm9yZS4NCj4gPiA+DQo+ID4g
PiBZZXMsIEkgYWdyZWUgd2l0aCBEYXZpZCBvbiB0aGlzLiDCoElmIGxhcmdlIHRyYW5zZmVycyBk
b24ndCB3b3JrLA0KPiA+ID4gdGhlbiBpdCBpcyB0aGUgU1BJIG1hc3RlciBkcml2ZXIgdGhhdCBp
cyBidWdneS4NCj4gPg0KPiA+IEJ5IHRoZSB3YXksIGRvZXMgdGhpcyBmaXggeW91ciBwcm9ibGVt
Pw0KPiA+DQo+ID4gaHR0cHM6Ly9wYXRjaHdvcmsua2VybmVsLm9yZy9wYXRjaC8xODQ3NTIvDQo+
IA0KPiBJdCBzaG91bGRuJ3QuIEFGQUlLLCBlU1BJIGlzIFBJTy1vbmx5IGNvbnRyb2xsZXIsIGFu
ZCB0aGUgb3ZlcnJ1biBmaXggaXMgZm9yIHRoZQ0KPiBETUEgbW9kZS4NCj4gDQo+IFRoYW5rcywN
Cj4gDQo+IHAucy4gQnR3LCBpbiBwYXRjaCAzLzcsIGlzX2RtYV9tYXBwZWQgYXJndW1lbnQgb2Yg
ZnNsX2VzcGlfYnVmcygpIGlzIHVubmVlZGVkLg0KPiANCg0KWWVzLCB0aGUgaXNfZG1hX21hcHBl
ZCBpc24ndCBuZWVkZWQsIEknbGwgcmVtb3ZlIGl0Lg0KDQpUaGFua3MsDQpNaW5na2FpDQo=

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

* RE: [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
  2010-09-30 10:46 [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page David Brownell
  2010-09-30 14:16 ` Grant Likely
@ 2010-10-08  2:13 ` Hu Mingkai-B21284
  1 sibling, 0 replies; 23+ messages in thread
From: Hu Mingkai-B21284 @ 2010-10-08  2:13 UTC (permalink / raw)
  To: David Brownell, linuxppc-dev, spi-devel-general, linux-mtd
  Cc: Gala Kumar-B11780, Zang Roy-R61911



> -----Original Message-----
> From: David Brownell [mailto:david-b@pacbell.net]
> Sent: Thursday, September 30, 2010 6:46 PM
> To: linuxppc-dev@ozlabs.org; spi-devel-general@lists.sourceforge.net; =
linux-
> mtd@lists.infradead.org; Hu Mingkai-B21284
> Cc: Gala Kumar-B11780; Zang Roy-R61911; Hu Mingkai-B21284
> Subject: Re: [PATCH v3 6/7] mtd: m25p80: add a read function to read =
page by
> page
>=20
>=20
> --- On Thu, 9/30/10, Mingkai Hu <Mingkai.hu@freescale.com> wrote:
>=20
> > From: Mingkai Hu <Mingkai.hu@freescale.com>
> > Subject: [PATCH v3 6/7] mtd: m25p80: add a read function to read =
page
> > by page
>=20
> NAK.
>=20
> We went over this before.
>=20
> =A0 The bug is in your SPI master controller driver, and the fix there =
involves
> mapping large reads  into multiple smaller reads.=A0 (Example, 128K =
read as two
> 64K reads instead of one of 128K.
>=20
> It's *NEVER* appropriate to commit to patching all upper level drivers =
in order
> to work around bugs in lower level ones.=A0 The set of such upper =
level drivers
> that may need bugfixing is quite large, most will never be used with =
your buggy
> controller driver, and all such patches will need testing (but the =
test
> resources are probably not available).
>=20
> Whatever SPI controller driver you're working with is clearly buggy =
... but not
> unfixably so.
>=20
> DO NOT head down the path of requiring every SPI device driver to =
include
> workarounds for this odd little SPI master driver bug.
>=20
> - Dave
>=20

Thanks for your comments, the controller driver is the proper place to =
handle this, I'll fix it.

Thanks,
Mingkai

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

* Re: [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
  2010-09-30 15:06     ` Anton Vorontsov
@ 2010-09-30 20:57       ` Grant Likely
  2010-10-08  2:15       ` Hu Mingkai-B21284
  1 sibling, 0 replies; 23+ messages in thread
From: Grant Likely @ 2010-09-30 20:57 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: kumar.gala, David Brownell, linuxppc-dev, linux-mtd,
	spi-devel-general, Mingkai Hu

On Fri, Oct 1, 2010 at 12:06 AM, Anton Vorontsov <cbouatmailru@gmail.com> w=
rote:
> On Thu, Sep 30, 2010 at 11:41:40PM +0900, Grant Likely wrote:
>> On Thu, Sep 30, 2010 at 11:16 PM, Grant Likely
>> <grant.likely@secretlab.ca> wrote:
>> > On Thu, Sep 30, 2010 at 7:46 PM, David Brownell <david-b@pacbell.net> =
wrote:
>> >>
>> >> --- On Thu, 9/30/10, Mingkai Hu <Mingkai.hu@freescale.com> wrote:
>> >>
>> >>> From: Mingkai Hu <Mingkai.hu@freescale.com>
>> >>> Subject: [PATCH v3 6/7] mtd: m25p80: add a read function to read pag=
e by page
>> >>
>> >> NAK.
>> >>
>> >> We went over this before.
>> >
>> > Yes, I agree with David on this. =A0If large transfers don't work, the=
n
>> > it is the SPI master driver that is buggy.
>>
>> By the way, does this fix your problem?
>>
>> https://patchwork.kernel.org/patch/184752/
>
> It shouldn't. AFAIK, eSPI is PIO-only controller, and the overrun
> fix is for the DMA mode.
>
> Thanks,
>
> p.s. Btw, in patch 3/7, is_dma_mapped argument of fsl_espi_bufs()
> is unneeded.

Thanks Anton.  Please reply to that patch with this comment so that
patchwork records it and I don't forget about it.

Thanks,
g.

>
> --
> Anton Vorontsov
> email: cbouatmailru@gmail.com
> irc://irc.freenode.net/bd2
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

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

* Re: [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
  2010-09-30 14:41   ` Grant Likely
@ 2010-09-30 15:06     ` Anton Vorontsov
  2010-09-30 20:57       ` Grant Likely
  2010-10-08  2:15       ` Hu Mingkai-B21284
  0 siblings, 2 replies; 23+ messages in thread
From: Anton Vorontsov @ 2010-09-30 15:06 UTC (permalink / raw)
  To: Grant Likely
  Cc: kumar.gala, David Brownell, linuxppc-dev, linux-mtd,
	spi-devel-general, Mingkai Hu

On Thu, Sep 30, 2010 at 11:41:40PM +0900, Grant Likely wrote:
> On Thu, Sep 30, 2010 at 11:16 PM, Grant Likely
> <grant.likely@secretlab.ca> wrote:
> > On Thu, Sep 30, 2010 at 7:46 PM, David Brownell <david-b@pacbell.net> wrote:
> >>
> >> --- On Thu, 9/30/10, Mingkai Hu <Mingkai.hu@freescale.com> wrote:
> >>
> >>> From: Mingkai Hu <Mingkai.hu@freescale.com>
> >>> Subject: [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
> >>
> >> NAK.
> >>
> >> We went over this before.
> >
> > Yes, I agree with David on this.  If large transfers don't work, then
> > it is the SPI master driver that is buggy.
> 
> By the way, does this fix your problem?
> 
> https://patchwork.kernel.org/patch/184752/

It shouldn't. AFAIK, eSPI is PIO-only controller, and the overrun
fix is for the DMA mode.

Thanks,

p.s. Btw, in patch 3/7, is_dma_mapped argument of fsl_espi_bufs()
is unneeded.

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

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

* Re: [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
  2010-09-30 14:16 ` Grant Likely
@ 2010-09-30 14:41   ` Grant Likely
  2010-09-30 15:06     ` Anton Vorontsov
  0 siblings, 1 reply; 23+ messages in thread
From: Grant Likely @ 2010-09-30 14:41 UTC (permalink / raw)
  To: David Brownell
  Cc: linuxppc-dev, Mingkai Hu, linux-mtd, kumar.gala, spi-devel-general

On Thu, Sep 30, 2010 at 11:16 PM, Grant Likely
<grant.likely@secretlab.ca> wrote:
> On Thu, Sep 30, 2010 at 7:46 PM, David Brownell <david-b@pacbell.net> wro=
te:
>>
>> --- On Thu, 9/30/10, Mingkai Hu <Mingkai.hu@freescale.com> wrote:
>>
>>> From: Mingkai Hu <Mingkai.hu@freescale.com>
>>> Subject: [PATCH v3 6/7] mtd: m25p80: add a read function to read page b=
y page
>>
>> NAK.
>>
>> We went over this before.
>
> Yes, I agree with David on this. =A0If large transfers don't work, then
> it is the SPI master driver that is buggy.

By the way, does this fix your problem?

https://patchwork.kernel.org/patch/184752/

g.

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

* Re: [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
  2010-09-30 10:46 [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page David Brownell
@ 2010-09-30 14:16 ` Grant Likely
  2010-09-30 14:41   ` Grant Likely
  2010-10-08  2:13 ` Hu Mingkai-B21284
  1 sibling, 1 reply; 23+ messages in thread
From: Grant Likely @ 2010-09-30 14:16 UTC (permalink / raw)
  To: David Brownell
  Cc: linuxppc-dev, Mingkai Hu, linux-mtd, kumar.gala, spi-devel-general

On Thu, Sep 30, 2010 at 7:46 PM, David Brownell <david-b@pacbell.net> wrote:
>
> --- On Thu, 9/30/10, Mingkai Hu <Mingkai.hu@freescale.com> wrote:
>
>> From: Mingkai Hu <Mingkai.hu@freescale.com>
>> Subject: [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
>
> NAK.
>
> We went over this before.

Yes, I agree with David on this.  If large transfers don't work, then
it is the SPI master driver that is buggy.

g.

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

* Re: [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page
@ 2010-09-30 10:46 David Brownell
  2010-09-30 14:16 ` Grant Likely
  2010-10-08  2:13 ` Hu Mingkai-B21284
  0 siblings, 2 replies; 23+ messages in thread
From: David Brownell @ 2010-09-30 10:46 UTC (permalink / raw)
  To: linuxppc-dev, spi-devel-general, linux-mtd, Mingkai Hu
  Cc: kumar.gala, Mingkai Hu

=0A--- On Thu, 9/30/10, Mingkai Hu <Mingkai.hu@freescale.com> wrote:=0A=0A>=
 From: Mingkai Hu <Mingkai.hu@freescale.com>=0A> Subject: [PATCH v3 6/7] mt=
d: m25p80: add a read function to read page by page=0A=0ANAK.=0A=0AWe went =
over this before.=0A=0A=A0 The bug is in your SPI master controller driver,=
=0Aand the fix there involves mapping large reads=0A into multiple smaller =
reads.=A0 (Example, 128K=0Aread as two 64K reads instead of one of 128K.=0A=
=0AIt's *NEVER* appropriate to commit to patching all=0Aupper level drivers=
 in order to work around bugs=0Ain lower level ones.=A0 The set of such upp=
er level=0Adrivers that may need bugfixing is quite large,=0Amost will neve=
r be used with your buggy controller=0Adriver, and all such patches will ne=
ed testing (but=0Athe test resources are probably not available).=0A=0AWhat=
ever SPI controller driver you're working with=0Ais clearly buggy ... but n=
ot unfixably so.=0A=0ADO NOT head down the path of requiring every SPI=0Ade=
vice driver to include workarounds for this odd=0Alittle SPI master driver =
bug.=0A=0A- Dave=0A=0A=0A=0A=0A=0A

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

end of thread, other threads:[~2010-10-08  6:38 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-30  8:00 [PATCH v3 0/7] refactor spi_mpc8xxx.c and add eSPI controller support Mingkai Hu
2010-09-30  8:00 ` [PATCH v3 1/7] spi/mpc8xxx: rename spi_mpc8xxx.c to spi_fsl_spi.c Mingkai Hu
2010-09-30  8:00   ` [PATCH v3 2/7] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Mingkai Hu
2010-09-30  8:00     ` [PATCH v3 3/7] eSPI: add eSPI controller support Mingkai Hu
2010-09-30  8:00       ` [PATCH v3 4/7] powerpc/of: add eSPI controller dts bindings and DTS modification Mingkai Hu
2010-09-30  8:00         ` [PATCH v3 5/7] mtd: m25p80: add support to parse the SPI flash's partitions Mingkai Hu
2010-09-30  8:00           ` [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page Mingkai Hu
2010-09-30  8:00             ` [PATCH v3 7/7] DTS: add fsl,spi-quirk-trans-len-limit property Mingkai Hu
2010-09-30 21:41             ` [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page Grant Likely
2010-09-30 21:34           ` [PATCH v3 5/7] mtd: m25p80: add support to parse the SPI flash's partitions Grant Likely
2010-10-08  2:42             ` Hu Mingkai-B21284
2010-10-01 11:22       ` [PATCH v3 3/7] eSPI: add eSPI controller support Anton Vorontsov
2010-10-08  6:35         ` Hu Mingkai-B21284
2010-10-01 11:22     ` [PATCH v3 2/7] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Anton Vorontsov
2010-10-08  6:37       ` Hu Mingkai-B21284
2010-09-30 10:46 [PATCH v3 6/7] mtd: m25p80: add a read function to read page by page David Brownell
2010-09-30 14:16 ` Grant Likely
2010-09-30 14:41   ` Grant Likely
2010-09-30 15:06     ` Anton Vorontsov
2010-09-30 20:57       ` Grant Likely
2010-10-08  2:15       ` Hu Mingkai-B21284
2010-10-08  6:11         ` Kumar Gala
2010-10-08  2:13 ` Hu Mingkai-B21284

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