linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] refactor spi_mpc8xxx.c and add eSPI controller support
@ 2010-07-20  2:08 Mingkai Hu
  2010-07-20  2:08 ` [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Mingkai Hu
  2010-07-26  0:36 ` [PATCH 0/6] refactor spi_mpc8xxx.c and add eSPI controller support Grant Likely
  0 siblings, 2 replies; 29+ messages in thread
From: Mingkai Hu @ 2010-07-20  2:08 UTC (permalink / raw)
  To: linuxppc-dev

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 fsl_spi.c, and add the eSPI controller support with fsl_espi.c.

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

[PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
[PATCH 2/6] eSPI: add eSPI controller support
[PATCH 3/6] of/spi: add support to parse the SPI flash's partitions
[PATCH 4/6] mtd: m25p80: change the read function to read page by page
[PATCH 5/6] powerpc/of: add eSPI controller dts bindings
[PATCH 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board

Thanks,
Mingkai

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

* [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
  2010-07-20  2:08 [PATCH 0/6] refactor spi_mpc8xxx.c and add eSPI controller support Mingkai Hu
@ 2010-07-20  2:08 ` Mingkai Hu
  2010-07-20  2:08   ` [PATCH 2/6] eSPI: add eSPI controller support Mingkai Hu
  2010-07-26  0:14   ` [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Grant Likely
  2010-07-26  0:36 ` [PATCH 0/6] refactor spi_mpc8xxx.c and add eSPI controller support Grant Likely
  1 sibling, 2 replies; 29+ messages in thread
From: Mingkai Hu @ 2010-07-20  2:08 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Mingkai Hu

Refactor the common code to file spi_mpc8xxx.c used by SPI/eSPI
controller driver, move the SPI controller driver to a new file
fsl_spi.c, and leave the QE/CPM SPI controller code in this file.

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>
---
 drivers/spi/Kconfig       |   13 +-
 drivers/spi/Makefile      |    1 +
 drivers/spi/fsl_spi.c     | 1118 ++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/spi_mpc8xxx.c | 1198 ++-------------------------------------------
 drivers/spi/spi_mpc8xxx.h |  135 +++++
 5 files changed, 1299 insertions(+), 1166 deletions(-)
 create mode 100644 drivers/spi/fsl_spi.c
 create mode 100644 drivers/spi/spi_mpc8xxx.h

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 91c2f4f..cd564e2 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -183,11 +183,18 @@ config SPI_MPC512x_PSC
 	  Controller in SPI master mode.
 
 config SPI_MPC8xxx
-	tristate "Freescale MPC8xxx SPI controller"
+	bool
 	depends on FSL_SOC
 	help
-	  This enables using the Freescale MPC8xxx SPI controllers in master
-	  mode.
+	  This enables using the Freescale MPC8xxx SPI/eSPI controllers
+	  driver library.
+
+config SPI_FSL_SPI
+	tristate "Freescale SPI controller"
+	depends on FSL_SOC
+	select SPI_MPC8xxx
+	help
+	  This enables using the Freescale SPI controllers in master mode.
 
 config SPI_OMAP_UWIRE
 	tristate "OMAP1 MicroWire"
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index e9cbd18..dca9fea 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_MPC8xxx)		+= spi_mpc8xxx.o
+obj-$(CONFIG_SPI_FSL_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/fsl_spi.c b/drivers/spi/fsl_spi.c
new file mode 100644
index 0000000..a1637c0
--- /dev/null
+++ b/drivers/spi/fsl_spi.c
@@ -0,0 +1,1118 @@
+/*
+ * 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>
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/irq.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/of_spi.h>
+
+#include <sysdev/fsl_soc.h>
+#include <asm/cpm.h>
+#include <asm/qe.h>
+
+#include "spi_mpc8xxx.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 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)
+
+static void *fsl_dummy_rx;
+static DEFINE_MUTEX(fsl_dummy_rx_lock);
+static int fsl_dummy_rx_refcnt;
+
+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;
+	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 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;
+	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;
+
+		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)
+{
+	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 fsl_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);
+
+	fsl_spi_change_mode(spi);
+	return 0;
+}
+
+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;
+
+	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 fsl_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 */
+	fsl_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 fsl_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 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);
+	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 = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
+	else
+		ret = mpc8xxx_spi_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)
+		fsl_spi_cpm_bufs_complete(mpc8xxx_spi);
+
+	return mpc8xxx_spi->count;
+}
+
+static void fsl_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 = fsl_spi_setup_transfer(spi, t);
+			if (status < 0)
+				break;
+		}
+
+		if (cs_change) {
+			fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE);
+			ndelay(nsecs);
+		}
+		cs_change = t->cs_change;
+		if (t->len)
+			status = fsl_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);
+			fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+			ndelay(nsecs);
+		}
+	}
+
+	m->status = status;
+	m->complete(m->context);
+
+	if (status || !cs_change) {
+		ndelay(nsecs);
+		fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+	}
+
+	fsl_spi_setup_transfer(spi, NULL);
+}
+
+static int fsl_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 = fsl_spi_setup_transfer(spi, NULL);
+	if (retval < 0) {
+		cs->hw_mode = hw_mode; /* Restore settings */
+		return retval;
+	}
+	return 0;
+}
+
+static void fsl_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)
+		fsl_spi_cpm_bufs_start(mspi);
+	else
+		complete(&mspi->done);
+}
+
+static void fsl_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 void fsl_spi_irq(struct mpc8xxx_spi *mspi, u32 events)
+{
+	if (mspi->flags & SPI_CPM_MODE)
+		fsl_spi_cpm_irq(mspi, events);
+	else
+		fsl_spi_cpu_irq(mspi, events);
+}
+
+static void *fsl_spi_alloc_dummy_rx(void)
+{
+	mutex_lock(&fsl_dummy_rx_lock);
+
+	if (!fsl_dummy_rx)
+		fsl_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
+	if (fsl_dummy_rx)
+		fsl_dummy_rx_refcnt++;
+
+	mutex_unlock(&fsl_dummy_rx_lock);
+
+	return fsl_dummy_rx;
+}
+
+static void fsl_spi_free_dummy_rx(void)
+{
+	mutex_lock(&fsl_dummy_rx_lock);
+
+	switch (fsl_dummy_rx_refcnt) {
+	case 0:
+		WARN_ON(1);
+		break;
+	case 1:
+		kfree(fsl_dummy_rx);
+		fsl_dummy_rx = NULL;
+		/* fall through */
+	default:
+		fsl_dummy_rx_refcnt--;
+		break;
+	}
+
+	mutex_unlock(&fsl_dummy_rx_lock);
+}
+
+static unsigned long fsl_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 fsl_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 (!fsl_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 = 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;
+	}
+
+	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, 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");
+		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:
+	fsl_spi_free_dummy_rx();
+	return -ENOMEM;
+}
+
+static void fsl_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));
+	fsl_spi_free_dummy_rx();
+}
+
+static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
+{
+	fsl_spi_cpm_free(mspi);
+}
+
+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;
+	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);
+
+	ret = mpc8xxx_spi_probe(dev, mem, irq);
+	if (ret)
+		goto err_probe;
+
+	master->setup = fsl_spi_setup;
+
+	mpc8xxx_spi = spi_master_get_devdata(master);
+	mpc8xxx_spi->spi_do_one_msg = fsl_spi_do_one_msg;
+	mpc8xxx_spi->spi_remove = fsl_spi_remove;
+	mpc8xxx_spi->spi_irq = fsl_spi_irq;
+
+	ret = fsl_spi_cpm_init(mpc8xxx_spi);
+	if (ret)
+		goto err_probe;
+
+	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(&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);
+
+	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:
+	fsl_spi_cpm_free(mpc8xxx_spi);
+err_probe:
+	spi_master_put(master);
+err:
+	return ERR_PTR(ret);
+}
+
+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);
+	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_fsl_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 = fsl_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_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);
+	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_fsl_spi_probe(struct of_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_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 = fsl_spi_probe(dev, &mem, irq.start);
+	if (IS_ERR(master)) {
+		ret = PTR_ERR(master);
+		goto err;
+	}
+
+	of_register_spi_devices(master, np);
+
+	return 0;
+
+err:
+	of_fsl_spi_free_chipselects(dev);
+	return ret;
+}
+
+static int __devexit of_fsl_spi_remove(struct of_device *ofdev)
+{
+	int ret;
+
+	ret = mpc8xxx_spi_remove(&ofdev->dev);
+	if (ret)
+		return ret;
+	of_fsl_spi_free_chipselects(&ofdev->dev);
+	return 0;
+}
+
+static const struct of_device_id of_fsl_spi_match[] = {
+	{ .compatible = "fsl,spi" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_fsl_spi_match);
+
+static struct of_platform_driver of_fsl_spi_driver = {
+	.driver = {
+		.name = "fsl_spi",
+		.owner = THIS_MODULE,
+		.of_match_table = of_fsl_spi_match,
+	},
+	.probe		= of_fsl_spi_probe,
+	.remove		= __devexit_p(of_fsl_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 = fsl_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 fsl_spi_init(void)
+{
+	legacy_driver_register();
+	return of_register_platform_driver(&of_fsl_spi_driver);
+}
+
+static void __exit fsl_spi_exit(void)
+{
+	of_unregister_platform_driver(&of_fsl_spi_driver);
+	legacy_driver_unregister();
+}
+
+module_init(fsl_spi_init);
+module_exit(fsl_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
index 97ab0a8..efed70e 100644
--- a/drivers/spi/spi_mpc8xxx.c
+++ b/drivers/spi/spi_mpc8xxx.c
@@ -9,174 +9,25 @@
  * 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/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/of_spi.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 */
+#include "spi_mpc8xxx.h"
 
-	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									  \
+#define MPC8XXX_SPI_RX_BUF(type) 					  \
 void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
 {									  \
 	type *rx = mpc8xxx_spi->rx;					  \
@@ -184,8 +35,7 @@ void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
 	mpc8xxx_spi->rx = rx;						  \
 }
 
-#define MPC83XX_SPI_TX_BUF(type)				\
-static								\
+#define MPC8XXX_SPI_TX_BUF(type)				\
 u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
 {								\
 	u32 data;						\
@@ -197,308 +47,20 @@ u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
 	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);
+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)
 
-	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 mpc8xxx_spi_probe_info *
+to_of_pinfo(struct fsl_spi_platform_data *pdata)
 {
-	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;
+	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
 }
 
-static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
+int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi,
 				struct spi_transfer *t, unsigned int len)
 {
 	u32 word;
@@ -515,110 +77,7 @@ static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
 	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)
+void mpc8xxx_spi_work(struct work_struct *work)
 {
 	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
 						       work);
@@ -631,108 +90,15 @@ static void mpc8xxx_spi_work(struct work_struct *work)
 		list_del_init(&m->queue);
 		spin_unlock_irq(&mpc8xxx_spi->lock);
 
-		mpc8xxx_spi_do_one_msg(m);
+		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);
 }
 
-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)
+irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
 {
 	struct mpc8xxx_spi *mspi = context_data;
 	irqreturn_t ret = IRQ_NONE;
@@ -745,15 +111,13 @@ static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
 
 	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);
+	if (mspi->spi_irq)
+		mspi->spi_irq(mspi, events);
 
 	return ret;
 }
 
-static int mpc8xxx_spi_transfer(struct spi_device *spi,
+int mpc8xxx_spi_transfer(struct spi_device *spi,
 				struct spi_message *m)
 {
 	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
@@ -771,206 +135,12 @@ static int mpc8xxx_spi_transfer(struct spi_device *spi,
 }
 
 
-static void mpc8xxx_spi_cleanup(struct spi_device *spi)
+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)
+const char *mpc8xxx_spi_strmode(unsigned int flags)
 {
 	if (flags & SPI_QE_CPU_MODE) {
 		return "QE CPU";
@@ -985,28 +155,20 @@ static const char *mpc8xxx_spi_strmode(unsigned int flags)
 	return "CPU";
 }
 
-static struct spi_master * __devinit
-mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
+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;
-	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);
+	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->setup = mpc8xxx_spi_setup;
 	master->transfer = mpc8xxx_spi_transfer;
 	master->cleanup = mpc8xxx_spi_cleanup;
 
@@ -1017,23 +179,15 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
 	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;
+		goto err;
 	}
 
 	mpc8xxx_spi->irq = irq;
@@ -1048,18 +202,6 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
 	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);
@@ -1072,30 +214,17 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
 		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;
+	return 0;
 
-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);
+	return ret;
 }
 
-static int __devexit mpc8xxx_spi_remove(struct device *dev)
+int __devexit mpc8xxx_spi_remove(struct device *dev)
 {
 	struct mpc8xxx_spi *mpc8xxx_spi;
 	struct spi_master *master;
@@ -1109,143 +238,20 @@ static int __devexit mpc8xxx_spi_remove(struct device *dev)
 
 	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;
+	if (mpc8xxx_spi->spi_remove)
+		mpc8xxx_spi->spi_remove(mpc8xxx_spi);
 
-	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 of_device *ofdev,
+int __devinit of_mpc8xxx_spi_probe(struct of_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;
 
@@ -1265,7 +271,7 @@ static int __devinit of_mpc8xxx_spi_probe(struct of_device *ofdev,
 		pdata->sysclk = fsl_get_sys_freq();
 		if (pdata->sysclk == -1) {
 			ret = -ENODEV;
-			goto err_clk;
+			goto err;
 		}
 	}
 
@@ -1279,143 +285,9 @@ static int __devinit of_mpc8xxx_spi_probe(struct of_device *ofdev,
 	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;
-	}
-
-	of_register_spi_devices(master, np);
-
 	return 0;
 
 err:
-	of_mpc8xxx_spi_free_chipselects(dev);
-err_clk:
 	kfree(pinfo);
 	return ret;
 }
-
-static int __devexit of_mpc8xxx_spi_remove(struct of_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.h b/drivers/spi/spi_mpc8xxx.h
new file mode 100644
index 0000000..dcc6443
--- /dev/null
+++ b/drivers/spi/spi_mpc8xxx.h
@@ -0,0 +1,135 @@
+/*
+ * MPC8xxx SPI/eSPI controller common driver.
+ *
+ * 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_MPC8XXX_H__
+#define __SPI_MPC8XXX_H__
+
+/* SPI Controller registers */
+struct mpc8xxx_spi_reg {
+	u8 res1[0x20];
+	__be32 mode;
+	__be32 event;
+	__be32 mask;
+	__be32 command;
+	__be32 transmit;
+	__be32 receive;
+};
+
+/* 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 *);
+
+	/* hooks for different controller driver */
+	void (*spi_do_one_msg) (struct spi_message *m);
+	void (*spi_remove) (struct mpc8xxx_spi *mspi);
+	void (*spi_irq) (struct mpc8xxx_spi *mspi, u32 events);
+
+	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;
+};
+
+#define	SPIM_NE		0x00000200	/* Not empty */
+
+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 void mpc8xxx_spi_work(struct work_struct *work);
+extern irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data);
+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 of_device *ofdev,
+		const struct of_device_id *ofid);
+
+#endif /* __SPI_MPC8XXX_H__ */
-- 
1.6.4

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

* [PATCH 2/6] eSPI: add eSPI controller support
  2010-07-20  2:08 ` [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Mingkai Hu
@ 2010-07-20  2:08   ` Mingkai Hu
  2010-07-20  2:08     ` [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions Mingkai Hu
  2010-07-26  0:25     ` [PATCH 2/6] eSPI: add eSPI controller support Grant Likely
  2010-07-26  0:14   ` [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Grant Likely
  1 sibling, 2 replies; 29+ messages in thread
From: Mingkai Hu @ 2010-07-20  2:08 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Mingkai Hu

Add eSPI controller support based on the common code spi_mpc8xxx.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, so all the
   transfers in the same message are needed to combine to one transfer.

Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
---
 drivers/spi/Kconfig       |    7 +
 drivers/spi/Makefile      |    1 +
 drivers/spi/fsl_espi.c    |  562 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/spi_mpc8xxx.h |   12 +
 4 files changed, 582 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/fsl_espi.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index cd564e2..c647a00 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -196,6 +196,13 @@ config SPI_FSL_SPI
 	help
 	  This enables using the Freescale SPI controllers in master mode.
 
+config SPI_FSL_ESPI
+	tristate "Freescale eSPI controller"
+	depends on FSL_SOC
+	select SPI_MPC8xxx
+	help
+	  This enables using the Freescale eSPI controllers in master mode.
+
 config SPI_OMAP_UWIRE
 	tristate "OMAP1 MicroWire"
 	depends on ARCH_OMAP1
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index dca9fea..6af459b 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -36,6 +36,7 @@ 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)		+= fsl_spi.o
+obj-$(CONFIG_SPI_FSL_ESPI)		+= fsl_espi.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/fsl_espi.c b/drivers/spi/fsl_espi.c
new file mode 100644
index 0000000..ac70c8c
--- /dev/null
+++ b/drivers/spi/fsl_espi.c
@@ -0,0 +1,562 @@
+/*
+ * MPC8xxx 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 "spi_mpc8xxx.h"
+
+/* 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;
+	__be32 __iomem *mode;
+	__be32 __iomem *espi_mode = NULL;
+	u32 tmp;
+	unsigned long flags;
+
+	espi_mode = &mspi->base->mode;
+	mode = &mspi->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;
+	u8 bits_per_word, 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] */
+	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;
+}
+
+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);
+	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;
+
+	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(&mpc8xxx_spi->base->command,
+		(SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
+
+	ret = mpc8xxx_spi_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);
+
+	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;
+	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);
+
+	hw_mode = cs->hw_mode; /* Save orginal settings */
+	cs->hw_mode = mpc8xxx_spi_read_reg(
+			&mpc8xxx_spi->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(&mpc8xxx_spi->base->mode);
+	loop_mode &= ~SPMODE_LOOP;
+	if (spi->mode & SPI_LOOP)
+		loop_mode |= SPMODE_LOOP;
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->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_irq(struct mpc8xxx_spi *mspi, u32 events)
+{
+	/* 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(&mspi->base->event);
+		}
+		mspi->len -= 4;
+
+		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 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;
+	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 = NULL;
+	mpc8xxx_spi->spi_irq = fsl_espi_irq;
+
+	/* 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);
+
+	/* Init eSPI CS mode register */
+	for (i = 0; i < pdata->max_chipselect; i++)
+		mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->csmode[i],
+				CSMODE_INIT_VAL);
+
+	/* Enable SPI interface */
+	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
+
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
+
+	ret = spi_register_master(master);
+	if (ret < 0)
+		goto unreg_master;
+
+	dev_info(dev, "at 0x%p (irq = %d)\n", mpc8xxx_spi->base,
+			mpc8xxx_spi->irq);
+
+	return master;
+
+unreg_master:
+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 of_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;
+	}
+
+	of_register_spi_devices(master, np);
+
+	return 0;
+
+err:
+	return ret;
+}
+
+static int __devexit of_fsl_espi_remove(struct of_device *ofdev)
+{
+	int ret;
+
+	ret = mpc8xxx_spi_remove(&ofdev->dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct of_device_id of_fsl_espi_match[] = {
+	{ .compatible = "fsl,espi" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_fsl_espi_match);
+
+static struct of_platform_driver of_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(&of_fsl_espi_driver);
+}
+
+static void __exit fsl_espi_exit(void)
+{
+	of_unregister_platform_driver(&of_fsl_espi_driver);
+}
+
+module_init(fsl_espi_init);
+module_exit(fsl_espi_exit);
+
+MODULE_AUTHOR("Mingkai Hu");
+MODULE_DESCRIPTION("Enhanced MPC8xxx SPI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_mpc8xxx.h b/drivers/spi/spi_mpc8xxx.h
index dcc6443..a8e8270 100644
--- a/drivers/spi/spi_mpc8xxx.h
+++ b/drivers/spi/spi_mpc8xxx.h
@@ -20,6 +20,7 @@
 
 /* SPI Controller registers */
 struct mpc8xxx_spi_reg {
+#ifndef CONFIG_SPI_FSL_ESPI
 	u8 res1[0x20];
 	__be32 mode;
 	__be32 event;
@@ -27,6 +28,16 @@ struct mpc8xxx_spi_reg {
 	__be32 command;
 	__be32 transmit;
 	__be32 receive;
+#else
+	__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 res1[8];		/* 0x018 - 0x01c reserved */
+	__be32 csmode[4];	/* 0x020 - 0x02c eSPI cs mode register */
+#endif
 };
 
 /* SPI Controller driver's private data. */
@@ -37,6 +48,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] 29+ messages in thread

* [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions
  2010-07-20  2:08   ` [PATCH 2/6] eSPI: add eSPI controller support Mingkai Hu
@ 2010-07-20  2:08     ` Mingkai Hu
  2010-07-20  2:08       ` [PATCH 4/6] mtd: m25p80: change the read function to read page by page Mingkai Hu
  2010-07-26  0:28       ` [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions Grant Likely
  2010-07-26  0:25     ` [PATCH 2/6] eSPI: add eSPI controller support Grant Likely
  1 sibling, 2 replies; 29+ messages in thread
From: Mingkai Hu @ 2010-07-20  2:08 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Mingkai Hu

Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
---
 drivers/of/of_spi.c       |   11 +++++++++++
 drivers/spi/spi_mpc8xxx.c |    1 +
 2 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c
index 5fed7e3..284ca0e 100644
--- a/drivers/of/of_spi.c
+++ b/drivers/of/of_spi.c
@@ -10,6 +10,8 @@
 #include <linux/device.h>
 #include <linux/spi/spi.h>
 #include <linux/of_spi.h>
+#include <linux/spi/flash.h>
+#include <linux/mtd/partitions.h>
 
 /**
  * of_register_spi_devices - Register child devices onto the SPI bus
@@ -26,6 +28,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
 	const __be32 *prop;
 	int rc;
 	int len;
+	struct flash_platform_data *pdata;
 
 	for_each_child_of_node(np, nc) {
 		/* Alloc an spi_device */
@@ -81,6 +84,14 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
 		of_node_get(nc);
 		spi->dev.of_node = nc;
 
+		/* Parse the mtd partitions */
+		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+		if (!pdata)
+			return;
+		pdata->nr_parts = of_mtd_parse_partitions(&master->dev,
+				nc, &pdata->parts);
+		spi->dev.platform_data = pdata;
+
 		/* Register the new device */
 		request_module(spi->modalias);
 		rc = spi_add_device(spi);
diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c
index efed70e..0fadaeb 100644
--- a/drivers/spi/spi_mpc8xxx.c
+++ b/drivers/spi/spi_mpc8xxx.c
@@ -137,6 +137,7 @@ int mpc8xxx_spi_transfer(struct spi_device *spi,
 
 void mpc8xxx_spi_cleanup(struct spi_device *spi)
 {
+	kfree(spi->dev.platform_data);
 	kfree(spi->controller_state);
 }
 
-- 
1.6.4

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

* [PATCH 4/6] mtd: m25p80: change the read function to read page by page
  2010-07-20  2:08     ` [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions Mingkai Hu
@ 2010-07-20  2:08       ` Mingkai Hu
  2010-07-20  2:08         ` [PATCH 5/6] powerpc/of: add eSPI controller dts bindings Mingkai Hu
  2010-07-26  0:30         ` [PATCH 4/6] mtd: m25p80: change the read function to read page by page Grant Likely
  2010-07-26  0:28       ` [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions Grant Likely
  1 sibling, 2 replies; 29+ messages in thread
From: Mingkai Hu @ 2010-07-20  2:08 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Mingkai Hu

For Freescale's eSPI controller, the max transaction length one time
is limitted by the SPCOM[TRANSLEN] field which is 0x10000. 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 change the read function
if used the eSPI controller.

Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
---
 drivers/mtd/devices/m25p80.c |   18 ++++++++++++++----
 1 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 81e49a9..6cbe6b1 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -317,6 +317,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
 	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",
@@ -341,7 +342,6 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
 	spi_message_add_tail(&t[0], &m);
 
 	t[1].rx_buf = buf;
-	t[1].len = len;
 	spi_message_add_tail(&t[1], &m);
 
 	/* Byte count starts at zero. */
@@ -364,11 +364,21 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
 
 	/* Set up the write data buffer. */
 	flash->command[0] = OPCODE_READ;
-	m25p_addr2cmd(flash, from, flash->command);
 
-	spi_sync(flash->spi, &m);
+	for (i = page_size; i < len; i += page_size) {
+		page_size = len - i;
+		if (page_size > flash->page_size)
+			page_size = flash->page_size;
 
-	*retlen = m.actual_length - m25p_cmdsz(flash) - FAST_READ_DUMMY_BYTE;
+		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);
 
-- 
1.6.4

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

* [PATCH 5/6] powerpc/of: add eSPI controller dts bindings
  2010-07-20  2:08       ` [PATCH 4/6] mtd: m25p80: change the read function to read page by page Mingkai Hu
@ 2010-07-20  2:08         ` Mingkai Hu
  2010-07-20  2:08           ` [PATCH 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board Mingkai Hu
  2010-07-26  0:33           ` [PATCH 5/6] powerpc/of: add eSPI controller dts bindings Grant Likely
  2010-07-26  0:30         ` [PATCH 4/6] mtd: m25p80: change the read function to read page by page Grant Likely
  1 sibling, 2 replies; 29+ messages in thread
From: Mingkai Hu @ 2010-07-20  2:08 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Mingkai Hu

Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
---
 Documentation/powerpc/dts-bindings/fsl/spi.txt |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/Documentation/powerpc/dts-bindings/fsl/spi.txt b/Documentation/powerpc/dts-bindings/fsl/spi.txt
index 80510c0..b360bf9 100644
--- a/Documentation/powerpc/dts-bindings/fsl/spi.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/spi.txt
@@ -29,3 +29,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,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,espi";
+		reg = <0x110000 0x1000>;
+		interrupts = <53 0x2>;
+		interrupt-parent = <&mpic>;
+		fsl,espi-num-chipselects = <4>;
+	};
-- 
1.6.4

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

* [PATCH 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board
  2010-07-20  2:08         ` [PATCH 5/6] powerpc/of: add eSPI controller dts bindings Mingkai Hu
@ 2010-07-20  2:08           ` Mingkai Hu
  2010-07-26  0:35             ` Grant Likely
  2010-07-26  0:33           ` [PATCH 5/6] powerpc/of: add eSPI controller dts bindings Grant Likely
  1 sibling, 1 reply; 29+ messages in thread
From: Mingkai Hu @ 2010-07-20  2:08 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Mingkai Hu

Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
---
 arch/powerpc/boot/dts/mpc8536ds.dts |   52 +++++++++++++++++++++++++++++++++++
 arch/powerpc/boot/dts/p4080ds.dts   |    9 ++----
 2 files changed, 55 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts
index 815cebb..e5d07ec 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,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 6b29eab..ac7dd23 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";
 			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] 29+ messages in thread

* Re: [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
  2010-07-20  2:08 ` [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Mingkai Hu
  2010-07-20  2:08   ` [PATCH 2/6] eSPI: add eSPI controller support Mingkai Hu
@ 2010-07-26  0:14   ` Grant Likely
  2010-07-26  6:18     ` Hu Mingkai-B21284
  2010-07-26  7:07     ` Zang Roy-R61911
  1 sibling, 2 replies; 29+ messages in thread
From: Grant Likely @ 2010-07-26  0:14 UTC (permalink / raw)
  To: Mingkai Hu, @angua.secretlab.ca; +Cc: linuxppc-dev

On Tue, Jul 20, 2010 at 10:08:20AM +0800, Mingkai Hu wrote:
> Refactor the common code to file spi_mpc8xxx.c used by SPI/eSPI
> controller driver, move the SPI controller driver to a new file
> fsl_spi.c, and leave the QE/CPM SPI controller code in this file.
> 
> 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>
> ---
>  drivers/spi/Kconfig       |   13 +-
>  drivers/spi/Makefile      |    1 +
>  drivers/spi/fsl_spi.c     | 1118 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/spi/spi_mpc8xxx.c | 1198 ++-------------------------------------------
>  drivers/spi/spi_mpc8xxx.h |  135 +++++

Please name files spi-*.[ch].  I'm going to start enforcing this naming convention in the drivers/spi directory.

>  5 files changed, 1299 insertions(+), 1166 deletions(-)
>  create mode 100644 drivers/spi/fsl_spi.c
>  create mode 100644 drivers/spi/spi_mpc8xxx.h
> 
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 91c2f4f..cd564e2 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -183,11 +183,18 @@ config SPI_MPC512x_PSC
>  	  Controller in SPI master mode.
>  
>  config SPI_MPC8xxx
> -	tristate "Freescale MPC8xxx SPI controller"
> +	bool

This should be tristate so it can be loaded as a module.

>  	depends on FSL_SOC
>  	help
> -	  This enables using the Freescale MPC8xxx SPI controllers in master
> -	  mode.
> +	  This enables using the Freescale MPC8xxx SPI/eSPI controllers
> +	  driver library.

Drop the help text entirely.  It isn't needed on non-user-visible options.

> +
> +config SPI_FSL_SPI
> +	tristate "Freescale SPI controller"

"Freescale SPI controller is rather generic and doesn't give any clues
as to which devices actually have this controller.  At the very least
the help text should state what parts contain this controller.

On that note, the naming convention seems a little loose.  Since both the eSPI and SPI are using SPI_MPC8xxx, then really the names should be:

config SPI_MPC8xxx_SPI
and
config SPI_MPC8xxx_ESPI

> +	depends on FSL_SOC
> +	select SPI_MPC8xxx
> +	help
> +	  This enables using the Freescale SPI controllers in master mode.
>  
>  config SPI_OMAP_UWIRE
>  	tristate "OMAP1 MicroWire"
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index e9cbd18..dca9fea 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_MPC8xxx)		+= spi_mpc8xxx.o
> +obj-$(CONFIG_SPI_FSL_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/fsl_spi.c b/drivers/spi/fsl_spi.c
> new file mode 100644
> index 0000000..a1637c0
> --- /dev/null
> +++ b/drivers/spi/fsl_spi.c
> @@ -0,0 +1,1118 @@
> +/*
> + * 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>
> + *
> + * 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/types.h>
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +#include <linux/irq.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/of_spi.h>
> +
> +#include <sysdev/fsl_soc.h>
> +#include <asm/cpm.h>
> +#include <asm/qe.h>
> +
> +#include "spi_mpc8xxx.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 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)
> +
> +static void *fsl_dummy_rx;
> +static DEFINE_MUTEX(fsl_dummy_rx_lock);
> +static int fsl_dummy_rx_refcnt;
> +
> +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;
> +	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 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;
> +	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;
> +
> +		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)
> +{
> +	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 fsl_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);
> +
> +	fsl_spi_change_mode(spi);
> +	return 0;
> +}
> +
> +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;
> +
> +	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 fsl_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 */
> +	fsl_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 fsl_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 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);
> +	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 = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
> +	else
> +		ret = mpc8xxx_spi_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)
> +		fsl_spi_cpm_bufs_complete(mpc8xxx_spi);
> +
> +	return mpc8xxx_spi->count;
> +}
> +
> +static void fsl_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 = fsl_spi_setup_transfer(spi, t);
> +			if (status < 0)
> +				break;
> +		}
> +
> +		if (cs_change) {
> +			fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE);
> +			ndelay(nsecs);
> +		}
> +		cs_change = t->cs_change;
> +		if (t->len)
> +			status = fsl_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);
> +			fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
> +			ndelay(nsecs);
> +		}
> +	}
> +
> +	m->status = status;
> +	m->complete(m->context);
> +
> +	if (status || !cs_change) {
> +		ndelay(nsecs);
> +		fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
> +	}
> +
> +	fsl_spi_setup_transfer(spi, NULL);
> +}
> +
> +static int fsl_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 = fsl_spi_setup_transfer(spi, NULL);
> +	if (retval < 0) {
> +		cs->hw_mode = hw_mode; /* Restore settings */
> +		return retval;
> +	}
> +	return 0;
> +}
> +
> +static void fsl_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)
> +		fsl_spi_cpm_bufs_start(mspi);
> +	else
> +		complete(&mspi->done);
> +}
> +
> +static void fsl_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 void fsl_spi_irq(struct mpc8xxx_spi *mspi, u32 events)
> +{
> +	if (mspi->flags & SPI_CPM_MODE)
> +		fsl_spi_cpm_irq(mspi, events);
> +	else
> +		fsl_spi_cpu_irq(mspi, events);
> +}
> +
> +static void *fsl_spi_alloc_dummy_rx(void)
> +{
> +	mutex_lock(&fsl_dummy_rx_lock);
> +
> +	if (!fsl_dummy_rx)
> +		fsl_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
> +	if (fsl_dummy_rx)
> +		fsl_dummy_rx_refcnt++;
> +
> +	mutex_unlock(&fsl_dummy_rx_lock);
> +
> +	return fsl_dummy_rx;
> +}
> +
> +static void fsl_spi_free_dummy_rx(void)
> +{
> +	mutex_lock(&fsl_dummy_rx_lock);
> +
> +	switch (fsl_dummy_rx_refcnt) {
> +	case 0:
> +		WARN_ON(1);
> +		break;
> +	case 1:
> +		kfree(fsl_dummy_rx);
> +		fsl_dummy_rx = NULL;
> +		/* fall through */
> +	default:
> +		fsl_dummy_rx_refcnt--;
> +		break;
> +	}
> +
> +	mutex_unlock(&fsl_dummy_rx_lock);
> +}
> +
> +static unsigned long fsl_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 fsl_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 (!fsl_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 = 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;
> +	}
> +
> +	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, 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");
> +		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:
> +	fsl_spi_free_dummy_rx();
> +	return -ENOMEM;
> +}
> +
> +static void fsl_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));
> +	fsl_spi_free_dummy_rx();
> +}
> +
> +static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
> +{
> +	fsl_spi_cpm_free(mspi);
> +}
> +
> +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;
> +	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);
> +
> +	ret = mpc8xxx_spi_probe(dev, mem, irq);
> +	if (ret)
> +		goto err_probe;
> +
> +	master->setup = fsl_spi_setup;
> +
> +	mpc8xxx_spi = spi_master_get_devdata(master);
> +	mpc8xxx_spi->spi_do_one_msg = fsl_spi_do_one_msg;
> +	mpc8xxx_spi->spi_remove = fsl_spi_remove;
> +	mpc8xxx_spi->spi_irq = fsl_spi_irq;
> +
> +	ret = fsl_spi_cpm_init(mpc8xxx_spi);
> +	if (ret)
> +		goto err_probe;
> +
> +	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(&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);
> +
> +	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:
> +	fsl_spi_cpm_free(mpc8xxx_spi);
> +err_probe:
> +	spi_master_put(master);
> +err:
> +	return ERR_PTR(ret);
> +}
> +
> +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);
> +	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_fsl_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 = fsl_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_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);
> +	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_fsl_spi_probe(struct of_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_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 = fsl_spi_probe(dev, &mem, irq.start);
> +	if (IS_ERR(master)) {
> +		ret = PTR_ERR(master);
> +		goto err;
> +	}
> +
> +	of_register_spi_devices(master, np);
> +
> +	return 0;
> +
> +err:
> +	of_fsl_spi_free_chipselects(dev);
> +	return ret;
> +}
> +
> +static int __devexit of_fsl_spi_remove(struct of_device *ofdev)
> +{
> +	int ret;
> +
> +	ret = mpc8xxx_spi_remove(&ofdev->dev);
> +	if (ret)
> +		return ret;
> +	of_fsl_spi_free_chipselects(&ofdev->dev);
> +	return 0;
> +}
> +
> +static const struct of_device_id of_fsl_spi_match[] = {
> +	{ .compatible = "fsl,spi" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, of_fsl_spi_match);
> +
> +static struct of_platform_driver of_fsl_spi_driver = {
> +	.driver = {
> +		.name = "fsl_spi",
> +		.owner = THIS_MODULE,
> +		.of_match_table = of_fsl_spi_match,
> +	},
> +	.probe		= of_fsl_spi_probe,
> +	.remove		= __devexit_p(of_fsl_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 = fsl_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 fsl_spi_init(void)
> +{
> +	legacy_driver_register();
> +	return of_register_platform_driver(&of_fsl_spi_driver);
> +}
> +
> +static void __exit fsl_spi_exit(void)
> +{
> +	of_unregister_platform_driver(&of_fsl_spi_driver);
> +	legacy_driver_unregister();
> +}

It would appear that the legacy driver should *also* be separated out into its own module.  I realize you're just cut & pasting code here, but it should be considered for a followup patch.

> +
> +module_init(fsl_spi_init);
> +module_exit(fsl_spi_exit);

module_init() should appear immediately after the init fsl_spi_init() function.

> +
> +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
> index 97ab0a8..efed70e 100644
> --- a/drivers/spi/spi_mpc8xxx.c
> +++ b/drivers/spi/spi_mpc8xxx.c
> @@ -9,174 +9,25 @@
>   * 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/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/of_spi.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 */
> +#include "spi_mpc8xxx.h"
>  
> -	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									  \
> +#define MPC8XXX_SPI_RX_BUF(type) 					  \
>  void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
>  {									  \
>  	type *rx = mpc8xxx_spi->rx;					  \
> @@ -184,8 +35,7 @@ void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
>  	mpc8xxx_spi->rx = rx;						  \
>  }
>  
> -#define MPC83XX_SPI_TX_BUF(type)				\
> -static								\
> +#define MPC8XXX_SPI_TX_BUF(type)				\
>  u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
>  {								\
>  	u32 data;						\
> @@ -197,308 +47,20 @@ u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
>  	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);
> +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)
>  
> -	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 mpc8xxx_spi_probe_info *
> +to_of_pinfo(struct fsl_spi_platform_data *pdata)
>  {
> -	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;
> +	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
>  }
>  
> -static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
> +int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi,
>  				struct spi_transfer *t, unsigned int len)
>  {
>  	u32 word;
> @@ -515,110 +77,7 @@ static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
>  	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)
> +void mpc8xxx_spi_work(struct work_struct *work)
>  {
>  	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
>  						       work);
> @@ -631,108 +90,15 @@ static void mpc8xxx_spi_work(struct work_struct *work)
>  		list_del_init(&m->queue);
>  		spin_unlock_irq(&mpc8xxx_spi->lock);
>  
> -		mpc8xxx_spi_do_one_msg(m);
> +		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);
>  }
>  
> -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)
> +irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
>  {
>  	struct mpc8xxx_spi *mspi = context_data;
>  	irqreturn_t ret = IRQ_NONE;
> @@ -745,15 +111,13 @@ static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
>  
>  	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);
> +	if (mspi->spi_irq)
> +		mspi->spi_irq(mspi, events);
>  
>  	return ret;
>  }
>  
> -static int mpc8xxx_spi_transfer(struct spi_device *spi,
> +int mpc8xxx_spi_transfer(struct spi_device *spi,
>  				struct spi_message *m)
>  {
>  	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> @@ -771,206 +135,12 @@ static int mpc8xxx_spi_transfer(struct spi_device *spi,
>  }
>  
>  
> -static void mpc8xxx_spi_cleanup(struct spi_device *spi)
> +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)
> +const char *mpc8xxx_spi_strmode(unsigned int flags)
>  {
>  	if (flags & SPI_QE_CPU_MODE) {
>  		return "QE CPU";
> @@ -985,28 +155,20 @@ static const char *mpc8xxx_spi_strmode(unsigned int flags)
>  	return "CPU";
>  }
>  
> -static struct spi_master * __devinit
> -mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
> +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;
> -	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);
> +	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->setup = mpc8xxx_spi_setup;
>  	master->transfer = mpc8xxx_spi_transfer;
>  	master->cleanup = mpc8xxx_spi_cleanup;
>  
> @@ -1017,23 +179,15 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
>  	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;
> +		goto err;
>  	}
>  
>  	mpc8xxx_spi->irq = irq;
> @@ -1048,18 +202,6 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
>  	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);
> @@ -1072,30 +214,17 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
>  		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;
> +	return 0;
>  
> -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);
> +	return ret;
>  }
>  
> -static int __devexit mpc8xxx_spi_remove(struct device *dev)
> +int __devexit mpc8xxx_spi_remove(struct device *dev)
>  {
>  	struct mpc8xxx_spi *mpc8xxx_spi;
>  	struct spi_master *master;
> @@ -1109,143 +238,20 @@ static int __devexit mpc8xxx_spi_remove(struct device *dev)
>  
>  	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;
> +	if (mpc8xxx_spi->spi_remove)
> +		mpc8xxx_spi->spi_remove(mpc8xxx_spi);
>  
> -	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 of_device *ofdev,
> +int __devinit of_mpc8xxx_spi_probe(struct of_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;
>  
> @@ -1265,7 +271,7 @@ static int __devinit of_mpc8xxx_spi_probe(struct of_device *ofdev,
>  		pdata->sysclk = fsl_get_sys_freq();
>  		if (pdata->sysclk == -1) {
>  			ret = -ENODEV;
> -			goto err_clk;
> +			goto err;
>  		}
>  	}
>  
> @@ -1279,143 +285,9 @@ static int __devinit of_mpc8xxx_spi_probe(struct of_device *ofdev,
>  	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;
> -	}
> -
> -	of_register_spi_devices(master, np);
> -
>  	return 0;
>  
>  err:
> -	of_mpc8xxx_spi_free_chipselects(dev);
> -err_clk:
>  	kfree(pinfo);
>  	return ret;
>  }
> -
> -static int __devexit of_mpc8xxx_spi_remove(struct of_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.h b/drivers/spi/spi_mpc8xxx.h
> new file mode 100644
> index 0000000..dcc6443
> --- /dev/null
> +++ b/drivers/spi/spi_mpc8xxx.h
> @@ -0,0 +1,135 @@
> +/*
> + * MPC8xxx SPI/eSPI controller common driver.
> + *
> + * 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_MPC8XXX_H__
> +#define __SPI_MPC8XXX_H__
> +
> +/* SPI Controller registers */
> +struct mpc8xxx_spi_reg {
> +	u8 res1[0x20];
> +	__be32 mode;
> +	__be32 event;
> +	__be32 mask;
> +	__be32 command;
> +	__be32 transmit;
> +	__be32 receive;
> +};
> +
> +/* 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 *);
> +
> +	/* hooks for different controller driver */
> +	void (*spi_do_one_msg) (struct spi_message *m);
> +	void (*spi_remove) (struct mpc8xxx_spi *mspi);
> +	void (*spi_irq) (struct mpc8xxx_spi *mspi, u32 events);
> +
> +	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;
> +};
> +
> +#define	SPIM_NE		0x00000200	/* Not empty */
> +
> +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 void mpc8xxx_spi_work(struct work_struct *work);
> +extern irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data);
> +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 of_device *ofdev,
> +		const struct of_device_id *ofid);
> +
> +#endif /* __SPI_MPC8XXX_H__ */
> -- 
> 1.6.4
> 
> 

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

* Re: [PATCH 2/6] eSPI: add eSPI controller support
  2010-07-20  2:08   ` [PATCH 2/6] eSPI: add eSPI controller support Mingkai Hu
  2010-07-20  2:08     ` [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions Mingkai Hu
@ 2010-07-26  0:25     ` Grant Likely
  2010-07-26  7:02       ` Hu Mingkai-B21284
  1 sibling, 1 reply; 29+ messages in thread
From: Grant Likely @ 2010-07-26  0:25 UTC (permalink / raw)
  To: Mingkai Hu; +Cc: linuxppc-dev

On Tue, Jul 20, 2010 at 10:08:21AM +0800, Mingkai Hu wrote:
> Add eSPI controller support based on the common code spi_mpc8xxx.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, so all the
>    transfers in the same message are needed to combine to one transfer.
> 
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> ---
>  drivers/spi/Kconfig       |    7 +
>  drivers/spi/Makefile      |    1 +
>  drivers/spi/fsl_espi.c    |  562 +++++++++++++++++++++++++++++++++++++++++++++
>  drivers/spi/spi_mpc8xxx.h |   12 +
>  4 files changed, 582 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/spi/fsl_espi.c
> 
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index cd564e2..c647a00 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -196,6 +196,13 @@ config SPI_FSL_SPI
>  	help
>  	  This enables using the Freescale SPI controllers in master mode.
>  
> +config SPI_FSL_ESPI
> +	tristate "Freescale eSPI controller"
> +	depends on FSL_SOC
> +	select SPI_MPC8xxx
> +	help
> +	  This enables using the Freescale eSPI controllers in master mode.
> +

Ditto from last patch.  config SPI_MPC8xxx_SPI

>  config SPI_OMAP_UWIRE
>  	tristate "OMAP1 MicroWire"
>  	depends on ARCH_OMAP1
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index dca9fea..6af459b 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -36,6 +36,7 @@ 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)		+= fsl_spi.o
> +obj-$(CONFIG_SPI_FSL_ESPI)		+= fsl_espi.o

spi_mpc8xxx_espi.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/fsl_espi.c b/drivers/spi/fsl_espi.c
> new file mode 100644
> index 0000000..ac70c8c
> --- /dev/null
> +++ b/drivers/spi/fsl_espi.c
> @@ -0,0 +1,562 @@
> +/*
> + * MPC8xxx 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 "spi_mpc8xxx.h"
> +
> +/* 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 */

Inconsistent whitespacing.  Some lines use tabs; others spaces.  Should be consistent on all the lines.

> +
> +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;
> +	__be32 __iomem *mode;
> +	__be32 __iomem *espi_mode = NULL;
> +	u32 tmp;
> +	unsigned long flags;
> +
> +	espi_mode = &mspi->base->mode;
> +	mode = &mspi->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)

Break the line in the arguments instead of the declaration.  When grepping, the stuff at the front of the line is more important to see.  So:

+static int fsl_espi_setup_transfer(struct spi_device *spi,
+				   struct spi_transfer *t)

> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	u8 bits_per_word, 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;
> +	}

Just initialize bits_per_word and hz to 0 when they are declared to eliminate the else clause.

> +
> +	/* 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;

When the if clause has { }, please use braces in the else clause also.

> +	if (pm)
> +		pm--;
> +
> +	cs->hw_mode |= CSMODE_PM(pm);
> +
> +	fsl_espi_change_mode(spi);
> +	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);
> +	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;
> +
> +	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(&mpc8xxx_spi->base->command,
> +		(SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
> +
> +	ret = mpc8xxx_spi_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);
> +
> +	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;
> +	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);
> +
> +	hw_mode = cs->hw_mode; /* Save orginal settings */
> +	cs->hw_mode = mpc8xxx_spi_read_reg(
> +			&mpc8xxx_spi->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(&mpc8xxx_spi->base->mode);
> +	loop_mode &= ~SPMODE_LOOP;
> +	if (spi->mode & SPI_LOOP)
> +		loop_mode |= SPMODE_LOOP;
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->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_irq(struct mpc8xxx_spi *mspi, u32 events)
> +{
> +	/* 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(&mspi->base->event);
> +		}
> +		mspi->len -= 4;
> +
> +		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 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;
> +	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 = NULL;
> +	mpc8xxx_spi->spi_irq = fsl_espi_irq;
> +
> +	/* 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);
> +
> +	/* Init eSPI CS mode register */
> +	for (i = 0; i < pdata->max_chipselect; i++)
> +		mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->csmode[i],
> +				CSMODE_INIT_VAL);
> +
> +	/* Enable SPI interface */
> +	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
> +
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
> +
> +	ret = spi_register_master(master);
> +	if (ret < 0)
> +		goto unreg_master;
> +
> +	dev_info(dev, "at 0x%p (irq = %d)\n", mpc8xxx_spi->base,
> +			mpc8xxx_spi->irq);
> +
> +	return master;
> +
> +unreg_master:
> +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 of_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;
> +	}
> +
> +	of_register_spi_devices(master, np);
> +
> +	return 0;
> +
> +err:
> +	return ret;
> +}
> +
> +static int __devexit of_fsl_espi_remove(struct of_device *ofdev)
> +{
> +	int ret;
> +
> +	ret = mpc8xxx_spi_remove(&ofdev->dev);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id of_fsl_espi_match[] = {
> +	{ .compatible = "fsl,espi" },

Not good practice.  Use the real chip name in the compatible value.  "fsl,<chip>-espi".

> +	{},

NIT: Drop the comma here to hint that no more elements should follow after the null entry.

> +};
> +MODULE_DEVICE_TABLE(of, of_fsl_espi_match);
> +
> +static struct of_platform_driver of_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(&of_fsl_espi_driver);
> +}
> +
> +static void __exit fsl_espi_exit(void)
> +{
> +	of_unregister_platform_driver(&of_fsl_espi_driver);
> +}
> +
> +module_init(fsl_espi_init);

Move module_init() to right below fsl_espi_init.

> +module_exit(fsl_espi_exit);
> +
> +MODULE_AUTHOR("Mingkai Hu");
> +MODULE_DESCRIPTION("Enhanced MPC8xxx SPI Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/spi/spi_mpc8xxx.h b/drivers/spi/spi_mpc8xxx.h
> index dcc6443..a8e8270 100644
> --- a/drivers/spi/spi_mpc8xxx.h
> +++ b/drivers/spi/spi_mpc8xxx.h
> @@ -20,6 +20,7 @@
>  
>  /* SPI Controller registers */
>  struct mpc8xxx_spi_reg {
> +#ifndef CONFIG_SPI_FSL_ESPI
>  	u8 res1[0x20];
>  	__be32 mode;
>  	__be32 event;
> @@ -27,6 +28,16 @@ struct mpc8xxx_spi_reg {
>  	__be32 command;
>  	__be32 transmit;
>  	__be32 receive;
> +#else
> +	__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 res1[8];		/* 0x018 - 0x01c reserved */
> +	__be32 csmode[4];	/* 0x020 - 0x02c eSPI cs mode register */
> +#endif

Not multiplatform friendly.  If the two devices use different register maps, then the register map needs to be defined in the .c file.  You need to code for the case where a single kernel may contain both drivers.

>  };
>  
>  /* SPI Controller driver's private data. */
> @@ -37,6 +48,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	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions
  2010-07-20  2:08     ` [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions Mingkai Hu
  2010-07-20  2:08       ` [PATCH 4/6] mtd: m25p80: change the read function to read page by page Mingkai Hu
@ 2010-07-26  0:28       ` Grant Likely
  2010-07-26  7:25         ` Hu Mingkai-B21284
  1 sibling, 1 reply; 29+ messages in thread
From: Grant Likely @ 2010-07-26  0:28 UTC (permalink / raw)
  To: Mingkai Hu; +Cc: linuxppc-dev

On Tue, Jul 20, 2010 at 10:08:22AM +0800, Mingkai Hu wrote:
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> ---
>  drivers/of/of_spi.c       |   11 +++++++++++
>  drivers/spi/spi_mpc8xxx.c |    1 +
>  2 files changed, 12 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c
> index 5fed7e3..284ca0e 100644
> --- a/drivers/of/of_spi.c
> +++ b/drivers/of/of_spi.c
> @@ -10,6 +10,8 @@
>  #include <linux/device.h>
>  #include <linux/spi/spi.h>
>  #include <linux/of_spi.h>
> +#include <linux/spi/flash.h>
> +#include <linux/mtd/partitions.h>
>  
>  /**
>   * of_register_spi_devices - Register child devices onto the SPI bus
> @@ -26,6 +28,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
>  	const __be32 *prop;
>  	int rc;
>  	int len;
> +	struct flash_platform_data *pdata;
>  
>  	for_each_child_of_node(np, nc) {
>  		/* Alloc an spi_device */
> @@ -81,6 +84,14 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
>  		of_node_get(nc);
>  		spi->dev.of_node = nc;
>  
> +		/* Parse the mtd partitions */
> +		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
> +		if (!pdata)
> +			return;
> +		pdata->nr_parts = of_mtd_parse_partitions(&master->dev,
> +				nc, &pdata->parts);
> +		spi->dev.platform_data = pdata;
> +

Nack.  Not all spi devices are mtd devices.  In fact, most are not.

The spi driver itself should call the of_mtd_parse_partitions code to get the partition map.  Do not use pdata in this case.

>  		/* Register the new device */
>  		request_module(spi->modalias);
>  		rc = spi_add_device(spi);
> diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c
> index efed70e..0fadaeb 100644
> --- a/drivers/spi/spi_mpc8xxx.c
> +++ b/drivers/spi/spi_mpc8xxx.c
> @@ -137,6 +137,7 @@ int mpc8xxx_spi_transfer(struct spi_device *spi,
>  
>  void mpc8xxx_spi_cleanup(struct spi_device *spi)
>  {
> +	kfree(spi->dev.platform_data);

Irrelevant given the above comment, but how does this even work?  What if a driver was detached and reattached to an spi_device?  The platform_data would be freed.  Not to mention that the pointer isn't cleared, so the driver would have no idea that it has a freed pointer.

>  	kfree(spi->controller_state);
>  }
>  
> -- 
> 1.6.4
> 
> 

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

* Re: [PATCH 4/6] mtd: m25p80: change the read function to read page by page
  2010-07-20  2:08       ` [PATCH 4/6] mtd: m25p80: change the read function to read page by page Mingkai Hu
  2010-07-20  2:08         ` [PATCH 5/6] powerpc/of: add eSPI controller dts bindings Mingkai Hu
@ 2010-07-26  0:30         ` Grant Likely
  2010-07-26  7:33           ` Hu Mingkai-B21284
  1 sibling, 1 reply; 29+ messages in thread
From: Grant Likely @ 2010-07-26  0:30 UTC (permalink / raw)
  To: Mingkai Hu; +Cc: linuxppc-dev

On Tue, Jul 20, 2010 at 10:08:23AM +0800, Mingkai Hu wrote:
> For Freescale's eSPI controller, the max transaction length one time
> is limitted by the SPCOM[TRANSLEN] field which is 0x10000. 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 change the read function
> if used the eSPI controller.
> 
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> ---
>  drivers/mtd/devices/m25p80.c |   18 ++++++++++++++----
>  1 files changed, 14 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index 81e49a9..6cbe6b1 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -317,6 +317,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
>  	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",
> @@ -341,7 +342,6 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
>  	spi_message_add_tail(&t[0], &m);
>  
>  	t[1].rx_buf = buf;
> -	t[1].len = len;
>  	spi_message_add_tail(&t[1], &m);
>  
>  	/* Byte count starts at zero. */
> @@ -364,11 +364,21 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
>  
>  	/* Set up the write data buffer. */
>  	flash->command[0] = OPCODE_READ;
> -	m25p_addr2cmd(flash, from, flash->command);
>  
> -	spi_sync(flash->spi, &m);
> +	for (i = page_size; i < len; i += page_size) {
> +		page_size = len - i;
> +		if (page_size > flash->page_size)
> +			page_size = flash->page_size;
>  
> -	*retlen = m.actual_length - m25p_cmdsz(flash) - FAST_READ_DUMMY_BYTE;
> +		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;
> +	}

This patch seems to cripple all users just because eSPI cannot handle it.  Am I reading it wrong?

>  
>  	mutex_unlock(&flash->lock);
>  
> -- 
> 1.6.4
> 
> 

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

* Re: [PATCH 5/6] powerpc/of: add eSPI controller dts bindings
  2010-07-20  2:08         ` [PATCH 5/6] powerpc/of: add eSPI controller dts bindings Mingkai Hu
  2010-07-20  2:08           ` [PATCH 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board Mingkai Hu
@ 2010-07-26  0:33           ` Grant Likely
  2010-07-26  7:35             ` Hu Mingkai-B21284
  1 sibling, 1 reply; 29+ messages in thread
From: Grant Likely @ 2010-07-26  0:33 UTC (permalink / raw)
  To: Mingkai Hu; +Cc: linuxppc-dev

On Tue, Jul 20, 2010 at 10:08:24AM +0800, Mingkai Hu wrote:
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> ---
>  Documentation/powerpc/dts-bindings/fsl/spi.txt |   20 ++++++++++++++++++++
>  1 files changed, 20 insertions(+), 0 deletions(-)
> 
> diff --git a/Documentation/powerpc/dts-bindings/fsl/spi.txt b/Documentation/powerpc/dts-bindings/fsl/spi.txt
> index 80510c0..b360bf9 100644
> --- a/Documentation/powerpc/dts-bindings/fsl/spi.txt
> +++ b/Documentation/powerpc/dts-bindings/fsl/spi.txt
> @@ -29,3 +29,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,espi".

Good practice is to always fully identify the SoC in the compatible values, followed by an optional list of other specific chips it is compatible with.  Generic compatibles like "fsl,espi" are not a good idea.

+- compatible: should be "fsl,<chip>-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,espi";
> +		reg = <0x110000 0x1000>;
> +		interrupts = <53 0x2>;
> +		interrupt-parent = <&mpic>;
> +		fsl,espi-num-chipselects = <4>;
> +	};
> -- 
> 1.6.4
> 
> 

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

* Re: [PATCH 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board
  2010-07-20  2:08           ` [PATCH 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board Mingkai Hu
@ 2010-07-26  0:35             ` Grant Likely
  2010-07-26  7:39               ` Hu Mingkai-B21284
  0 siblings, 1 reply; 29+ messages in thread
From: Grant Likely @ 2010-07-26  0:35 UTC (permalink / raw)
  To: Mingkai Hu; +Cc: linuxppc-dev

On Tue, Jul 20, 2010 at 10:08:25AM +0800, Mingkai Hu wrote:
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> ---
>  arch/powerpc/boot/dts/mpc8536ds.dts |   52 +++++++++++++++++++++++++++++++++++
>  arch/powerpc/boot/dts/p4080ds.dts   |    9 ++----
>  2 files changed, 55 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts
> index 815cebb..e5d07ec 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,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";

whitespace inconsitencies

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

whitespace inconsitencies

> +				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 6b29eab..ac7dd23 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";
>  			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";

whitespace inconsistencies

>  				reg = <0>;
> -				linux,modalias = "fsl_m25p80";
>  				spi-max-frequency = <40000000>; /* input clock */
>  				partition@u-boot {
>  					label = "u-boot";
> -- 
> 1.6.4
> 
> 

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

* Re: [PATCH 0/6] refactor spi_mpc8xxx.c and add eSPI controller support
  2010-07-20  2:08 [PATCH 0/6] refactor spi_mpc8xxx.c and add eSPI controller support Mingkai Hu
  2010-07-20  2:08 ` [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Mingkai Hu
@ 2010-07-26  0:36 ` Grant Likely
  2010-07-26  5:52   ` Hu Mingkai-B21284
  1 sibling, 1 reply; 29+ messages in thread
From: Grant Likely @ 2010-07-26  0:36 UTC (permalink / raw)
  To: Mingkai Hu; +Cc: linuxppc-dev

On Tue, Jul 20, 2010 at 10:08:19AM +0800, Mingkai Hu wrote:
> 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 fsl_spi.c, and add the eSPI controller support with fsl_espi.c.
> 
> Tested on P4080DS and MPC8536DS board based on latest Linux tree.
> 
> [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
> [PATCH 2/6] eSPI: add eSPI controller support
> [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions
> [PATCH 4/6] mtd: m25p80: change the read function to read page by page
> [PATCH 5/6] powerpc/of: add eSPI controller dts bindings
> [PATCH 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board

Hi Mingkai,

Thanks for the patches, I've just sent my review.  Make sure you cc: spi-devel-general@lists.sourceforge.net when you post v2

g.

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

* RE: [PATCH 0/6] refactor spi_mpc8xxx.c and add eSPI controller support
  2010-07-26  0:36 ` [PATCH 0/6] refactor spi_mpc8xxx.c and add eSPI controller support Grant Likely
@ 2010-07-26  5:52   ` Hu Mingkai-B21284
  0 siblings, 0 replies; 29+ messages in thread
From: Hu Mingkai-B21284 @ 2010-07-26  5:52 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, Zang Roy-R61911

=20

> -----Original Message-----
> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of=20
> Grant Likely
> Sent: Monday, July 26, 2010 8:36 AM
> To: Hu Mingkai-B21284
> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang=20
> Roy-R61911
> Subject: Re: [PATCH 0/6] refactor spi_mpc8xxx.c and add eSPI=20
> controller support
>=20
> On Tue, Jul 20, 2010 at 10:08:19AM +0800, Mingkai Hu wrote:
> > This patchset refactor the file spi_mpc8xxx.c to abstract=20
> some common=20
> > code as a lib used by the SPI/eSPI controller driver, move the SPI=20
> > controller driver code to fsl_spi.c, and add the eSPI=20
> controller support with fsl_espi.c.
> >=20
> > Tested on P4080DS and MPC8536DS board based on latest Linux tree.
> >=20
> > [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI=20
> > controller [PATCH 2/6] eSPI: add eSPI controller support=20
> [PATCH 3/6]=20
> > of/spi: add support to parse the SPI flash's partitions [PATCH 4/6]=20
> > mtd: m25p80: change the read function to read page by page=20
> [PATCH 5/6]=20
> > powerpc/of: add eSPI controller dts bindings [PATCH 6/6]=20
> DTS: add SPI=20
> > flash(s25fl128p01) support on p4080ds and mpc8536ds board
>=20
> Hi Mingkai,
>=20
> Thanks for the patches, I've just sent my review.  Make sure=20
> you cc: spi-devel-general@lists.sourceforge.net when you post v2
>=20

Many thanks for you  review and comments, I'll submit the v2 version
with cc to spi-devel-general maillist.

Thanks,
Mingkai

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

* RE: [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
  2010-07-26  0:14   ` [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Grant Likely
@ 2010-07-26  6:18     ` Hu Mingkai-B21284
  2010-07-26  6:48       ` Grant Likely
  2010-07-26  7:07     ` Zang Roy-R61911
  1 sibling, 1 reply; 29+ messages in thread
From: Hu Mingkai-B21284 @ 2010-07-26  6:18 UTC (permalink / raw)
  To: Grant Likely, @angua.secretlab.ca; +Cc: linuxppc-dev, Zang Roy-R61911

=20

> -----Original Message-----
> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of=20
> Grant Likely
> Sent: Monday, July 26, 2010 8:14 AM
> To: Hu Mingkai-B21284; "@angua.secretlab.ca"@angua.secretlab.ca
> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang=20
> Roy-R61911
> Subject: Re: [PATCH 1/6] spi/mpc8xxx: refactor the common=20
> code for SPI/eSPI controller
>=20
> On Tue, Jul 20, 2010 at 10:08:20AM +0800, Mingkai Hu wrote:
> > Refactor the common code to file spi_mpc8xxx.c used by SPI/eSPI
> > controller driver, move the SPI controller driver to a new file
> > fsl_spi.c, and leave the QE/CPM SPI controller code in this file.
> >=20
> > 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.
> >=20
> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> > ---
> >  drivers/spi/Kconfig       |   13 +-
> >  drivers/spi/Makefile      |    1 +
> >  drivers/spi/fsl_spi.c     | 1118=20
> ++++++++++++++++++++++++++++++++++++++++++
> >  drivers/spi/spi_mpc8xxx.c | 1198=20
> ++-------------------------------------------
> >  drivers/spi/spi_mpc8xxx.h |  135 +++++
>=20
> Please name files spi-*.[ch].  I'm going to start enforcing=20
> this naming convention in the drivers/spi directory.
>=20

Ok.

> >  5 files changed, 1299 insertions(+), 1166 deletions(-)
> >  create mode 100644 drivers/spi/fsl_spi.c
> >  create mode 100644 drivers/spi/spi_mpc8xxx.h
> >=20
> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> > index 91c2f4f..cd564e2 100644
> > --- a/drivers/spi/Kconfig
> > +++ b/drivers/spi/Kconfig
> > @@ -183,11 +183,18 @@ config SPI_MPC512x_PSC
> >  	  Controller in SPI master mode.
> > =20
> >  config SPI_MPC8xxx
> > -	tristate "Freescale MPC8xxx SPI controller"
> > +	bool
>=20
> This should be tristate so it can be loaded as a module.
>=20

This option is selected by FSL_SPI and FSL_ESPI option, can we load the
driver as a module?

> >  	depends on FSL_SOC
> >  	help
> > -	  This enables using the Freescale MPC8xxx SPI=20
> controllers in master
> > -	  mode.
> > +	  This enables using the Freescale MPC8xxx SPI/eSPI controllers
> > +	  driver library.
>=20
> Drop the help text entirely.  It isn't needed on=20
> non-user-visible options.
>=20

Ok.

> > +
> > +config SPI_FSL_SPI
> > +	tristate "Freescale SPI controller"
>=20
> "Freescale SPI controller is rather generic and doesn't give any clues
> as to which devices actually have this controller.  At the very least
> the help text should state what parts contain this controller.
>=20

Ok.

> On that note, the naming convention seems a little loose. =20
> Since both the eSPI and SPI are using SPI_MPC8xxx, then=20
> really the names should be:
>=20
> config SPI_MPC8xxx_SPI
> and
> config SPI_MPC8xxx_ESPI
>

I'll chage it, SPI_MPC8xxx_SPI/ESPI is more clearer.
=20
> > +static void __exit fsl_spi_exit(void)
> > +{
> > +	of_unregister_platform_driver(&of_fsl_spi_driver);
> > +	legacy_driver_unregister();
> > +}
>=20
> It would appear that the legacy driver should *also* be=20
> separated out into its own module.  I realize you're just cut=20
> & pasting code here, but it should be considered for a followup patch.
>=20

Can we remove the legacy driver thoroughly?
If we separated out the code, what's the proper name for it?
spi_mpc8xxx_legacy.c?

> > +
> > +module_init(fsl_spi_init);
> > +module_exit(fsl_spi_exit);
>=20
> module_init() should appear immediately after the init=20
> fsl_spi_init() function.
>=20

Ok.

Thanks,
Mingkai=20

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

* Re: [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
  2010-07-26  6:18     ` Hu Mingkai-B21284
@ 2010-07-26  6:48       ` Grant Likely
  0 siblings, 0 replies; 29+ messages in thread
From: Grant Likely @ 2010-07-26  6:48 UTC (permalink / raw)
  To: Hu Mingkai-B21284; +Cc: @angua.secretlab.ca, linuxppc-dev, Zang Roy-R61911

On Mon, Jul 26, 2010 at 12:18 AM, Hu Mingkai-B21284
<B21284@freescale.com> wrote:
>
>
>> -----Original Message-----
>> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of
>> Grant Likely
>> Sent: Monday, July 26, 2010 8:14 AM
>> To: Hu Mingkai-B21284; "@angua.secretlab.ca"@angua.secretlab.ca
>> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang
>> Roy-R61911
>> Subject: Re: [PATCH 1/6] spi/mpc8xxx: refactor the common
>> code for SPI/eSPI controller
>>
>> On Tue, Jul 20, 2010 at 10:08:20AM +0800, Mingkai Hu wrote:
>> > Refactor the common code to file spi_mpc8xxx.c used by SPI/eSPI
>> > controller driver, move the SPI controller driver to a new file
>> > fsl_spi.c, and leave the QE/CPM SPI controller code in this file.
>> >
>> > 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>
>> > ---
>> > =A0drivers/spi/Kconfig =A0 =A0 =A0 | =A0 13 +-
>> > =A0drivers/spi/Makefile =A0 =A0 =A0| =A0 =A01 +
>> > =A0drivers/spi/fsl_spi.c =A0 =A0 | 1118
>> ++++++++++++++++++++++++++++++++++++++++++
>> > =A0drivers/spi/spi_mpc8xxx.c | 1198
>> ++-------------------------------------------
>> > =A0drivers/spi/spi_mpc8xxx.h | =A0135 +++++
>>
>> Please name files spi-*.[ch]. =A0I'm going to start enforcing
>> this naming convention in the drivers/spi directory.
>>
>
> Ok.
>
>> > =A05 files changed, 1299 insertions(+), 1166 deletions(-)
>> > =A0create mode 100644 drivers/spi/fsl_spi.c
>> > =A0create mode 100644 drivers/spi/spi_mpc8xxx.h
>> >
>> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
>> > index 91c2f4f..cd564e2 100644
>> > --- a/drivers/spi/Kconfig
>> > +++ b/drivers/spi/Kconfig
>> > @@ -183,11 +183,18 @@ config SPI_MPC512x_PSC
>> > =A0 =A0 =A0 Controller in SPI master mode.
>> >
>> > =A0config SPI_MPC8xxx
>> > - =A0 tristate "Freescale MPC8xxx SPI controller"
>> > + =A0 bool
>>
>> This should be tristate so it can be loaded as a module.
>>
>
> This option is selected by FSL_SPI and FSL_ESPI option, can we load the
> driver as a module?

Yes.  You may need to export some symbols, but the common library can
be loaded as a module.

>> > +static void __exit fsl_spi_exit(void)
>> > +{
>> > + =A0 of_unregister_platform_driver(&of_fsl_spi_driver);
>> > + =A0 legacy_driver_unregister();
>> > +}
>>
>> It would appear that the legacy driver should *also* be
>> separated out into its own module. =A0I realize you're just cut
>> & pasting code here, but it should be considered for a followup patch.
>>
>
> Can we remove the legacy driver thoroughly?
> If we separated out the code, what's the proper name for it?
> spi_mpc8xxx_legacy.c?

Sure.

g.

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

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

* RE: [PATCH 2/6] eSPI: add eSPI controller support
  2010-07-26  0:25     ` [PATCH 2/6] eSPI: add eSPI controller support Grant Likely
@ 2010-07-26  7:02       ` Hu Mingkai-B21284
  0 siblings, 0 replies; 29+ messages in thread
From: Hu Mingkai-B21284 @ 2010-07-26  7:02 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, Zang Roy-R61911

=20

> -----Original Message-----
> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of=20
> Grant Likely
> Sent: Monday, July 26, 2010 8:25 AM
> To: Hu Mingkai-B21284
> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang=20
> Roy-R61911
> Subject: Re: [PATCH 2/6] eSPI: add eSPI controller support
>=20
> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index=20
> > cd564e2..c647a00 100644
> > --- a/drivers/spi/Kconfig
> > +++ b/drivers/spi/Kconfig
> > @@ -196,6 +196,13 @@ config SPI_FSL_SPI
> >  	help
> >  	  This enables using the Freescale SPI controllers in=20
> master mode.
> > =20
> > +config SPI_FSL_ESPI
> > +	tristate "Freescale eSPI controller"
> > +	depends on FSL_SOC
> > +	select SPI_MPC8xxx
> > +	help
> > +	  This enables using the Freescale eSPI controllers in=20
> master mode.
> > +
>=20
> Ditto from last patch.  config SPI_MPC8xxx_SPI
>=20

Ok.

> >  config SPI_OMAP_UWIRE
> >  	tristate "OMAP1 MicroWire"
> >  	depends on ARCH_OMAP1
> > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index=20
> > dca9fea..6af459b 100644
> > --- a/drivers/spi/Makefile
> > +++ b/drivers/spi/Makefile
> > @@ -36,6 +36,7 @@ obj-$(CONFIG_SPI_MPC52xx_PSC)	=09
> +=3D mpc52xx_psc_spi.o
> >  obj-$(CONFIG_SPI_MPC52xx)		+=3D mpc52xx_spi.o
> >  obj-$(CONFIG_SPI_MPC8xxx)		+=3D spi_mpc8xxx.o
> >  obj-$(CONFIG_SPI_FSL_SPI)		+=3D fsl_spi.o
> > +obj-$(CONFIG_SPI_FSL_ESPI)		+=3D fsl_espi.o
>=20
> spi_mpc8xxx_espi.o
>=20

Ok.

> >  obj-$(CONFIG_SPI_PPC4xx)		+=3D spi_ppc4xx.o
> >  obj-$(CONFIG_SPI_S3C24XX_GPIO)		+=3D spi_s3c24xx_gpio.o
> >  obj-$(CONFIG_SPI_S3C24XX)		+=3D spi_s3c24xx_hw.o
> > diff --git a/drivers/spi/fsl_espi.c=20
> b/drivers/spi/fsl_espi.c new file=20
> > mode 100644 index 0000000..ac70c8c
> > --- /dev/null
> > +++ b/drivers/spi/fsl_espi.c
> > @@ -0,0 +1,562 @@
> > +/*
> > + * MPC8xxx eSPI controller driver.
> > + *
> > + * Copyright 2010 Freescale Semiconductor, Inc.
> > + *
> > + * This program is free software; you can redistribute  it and/or=20
> > +modify it
> > + * under  the terms of  the GNU General  Public License as=20
> published=20
> > +by the
> > + * Free Software Foundation;  either version 2 of the  License, or=20
> > +(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 "spi_mpc8xxx.h"
> > +
> > +/* 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=20
> SPMODE_INIT_VAL=20
> > +(SPMODE_TXTHR(4) | SPMODE_RXTHR(3)) #define CSMODE_INIT_VAL=20
> > +(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=20
> transaction length */
>=20
> Inconsistent whitespacing.  Some lines use tabs; others=20
> spaces.  Should be consistent on all the lines.
>=20

Ok.

> > +
> > +static
> > +int fsl_espi_setup_transfer(struct spi_device *spi, struct=20
> > +spi_transfer *t)
>=20
> Break the line in the arguments instead of the declaration. =20
> When grepping, the stuff at the front of the line is more=20
> important to see.  So:
>=20
> +static int fsl_espi_setup_transfer(struct spi_device *spi,
> +				   struct spi_transfer *t)
>=20

Ok.

> > +{
> > +	struct mpc8xxx_spi *mpc8xxx_spi;
> > +	u8 bits_per_word, pm;
> > +	u32 hz;
> > +	struct spi_mpc8xxx_cs	*cs =3D spi->controller_state;
> > +
> > +	mpc8xxx_spi =3D spi_master_get_devdata(spi->master);
> > +
> > +	if (t) {
> > +		bits_per_word =3D t->bits_per_word;
> > +		hz =3D t->speed_hz;
> > +	} else {
> > +		bits_per_word =3D 0;
> > +		hz =3D 0;
> > +	}
>=20
> Just initialize bits_per_word and hz to 0 when they are=20
> declared to eliminate the else clause.
>=20

Good suggestion.

> > +
> > +	/* spi_transfer level calls that work per-word */
> > +	if (!bits_per_word)
> > +		bits_per_word =3D 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 =3D spi->max_speed_hz;
> > +
> > +	cs->rx_shift =3D 0;
> > +	cs->tx_shift =3D 0;
> > +	cs->get_rx =3D mpc8xxx_spi_rx_buf_u32;
> > +	cs->get_tx =3D mpc8xxx_spi_tx_buf_u32;
> > +	if (bits_per_word <=3D 8) {
> > +		cs->rx_shift =3D 8 - bits_per_word;
> > +	} else if (bits_per_word <=3D 16) {
> > +		cs->rx_shift =3D 16 - bits_per_word;
> > +		if (spi->mode & SPI_LSB_FIRST)
> > +			cs->get_tx =3D fsl_espi_tx_buf_lsb;
> > +	} else
> > +		return -EINVAL;
> > +
> > +	mpc8xxx_spi->rx_shift =3D cs->rx_shift;
> > +	mpc8xxx_spi->tx_shift =3D cs->tx_shift;
> > +	mpc8xxx_spi->get_rx =3D cs->get_rx;
> > +	mpc8xxx_spi->get_tx =3D cs->get_tx;
> > +
> > +	bits_per_word =3D bits_per_word - 1;
> > +
> > +	/* mask out bits we are going to set */
> > +	cs->hw_mode &=3D ~(CSMODE_LEN(0xF) | CSMODE_DIV16
> > +				  | CSMODE_PM(0xF));
> > +
> > +	cs->hw_mode |=3D CSMODE_LEN(bits_per_word);
> > +
> > +	if ((mpc8xxx_spi->spibrg / hz) > 64) {
> > +		cs->hw_mode |=3D CSMODE_DIV16;
> > +		pm =3D (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
> > +
> > +		WARN_ONCE(pm > 16, "%s: Requested speed is too=20
> low: %d Hz. "
> > +			  "Will use %d Hz instead.\n",=20
> dev_name(&spi->dev),
> > +			  hz, mpc8xxx_spi->spibrg / 1024);
> > +		if (pm > 16)
> > +			pm =3D 16;
> > +	} else
> > +		pm =3D (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
>=20
> When the if clause has { }, please use braces in the else clause also.
>=20

Ok.

> > +static const struct of_device_id of_fsl_espi_match[] =3D {
> > +	{ .compatible =3D "fsl,espi" },
>=20
> Not good practice.  Use the real chip name in the compatible=20
> value.  "fsl,<chip>-espi".
>=20

Ok.

> > +	{},
>=20
> NIT: Drop the comma here to hint that no more elements should=20
> follow after the null entry.
>=20

Ok.

> > +};
> > +MODULE_DEVICE_TABLE(of, of_fsl_espi_match);
> > +
> > +static struct of_platform_driver of_fsl_espi_driver =3D {
> > +	.driver =3D {
> > +		.name =3D "fsl_espi",
> > +		.owner =3D THIS_MODULE,
> > +		.of_match_table =3D of_fsl_espi_match,
> > +	},
> > +	.probe		=3D of_fsl_espi_probe,
> > +	.remove		=3D __devexit_p(of_fsl_espi_remove),
> > +};
> > +
> > +static int __init fsl_espi_init(void) {
> > +	return of_register_platform_driver(&of_fsl_espi_driver);
> > +}
> > +
> > +static void __exit fsl_espi_exit(void) {
> > +	of_unregister_platform_driver(&of_fsl_espi_driver);
> > +}
> > +
> > +module_init(fsl_espi_init);
>=20
> Move module_init() to right below fsl_espi_init.
>=20
Ok.

> > +module_exit(fsl_espi_exit);
> > +
> > +MODULE_AUTHOR("Mingkai Hu");
> > +MODULE_DESCRIPTION("Enhanced MPC8xxx SPI Driver");=20
> > +MODULE_LICENSE("GPL");
> > diff --git a/drivers/spi/spi_mpc8xxx.h b/drivers/spi/spi_mpc8xxx.h=20
> > index dcc6443..a8e8270 100644
> > --- a/drivers/spi/spi_mpc8xxx.h
> > +++ b/drivers/spi/spi_mpc8xxx.h
> > @@ -20,6 +20,7 @@
> > =20
> >  /* SPI Controller registers */
> >  struct mpc8xxx_spi_reg {
> > +#ifndef CONFIG_SPI_FSL_ESPI
> >  	u8 res1[0x20];
> >  	__be32 mode;
> >  	__be32 event;
> > @@ -27,6 +28,16 @@ struct mpc8xxx_spi_reg {
> >  	__be32 command;
> >  	__be32 transmit;
> >  	__be32 receive;
> > +#else
> > +	__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=20
> access register*/
> > +	__be32 receive;		/* 0x014 - eSPI receive FIFO=20
> access register*/
> > +	u8 res1[8];		/* 0x018 - 0x01c reserved */
> > +	__be32 csmode[4];	/* 0x020 - 0x02c eSPI cs mode=20
> register */
> > +#endif
>=20
> Not multiplatform friendly.  If the two devices use different=20
> register maps, then the register map needs to be defined in=20
> the .c file.  You need to code for the case where a single=20
> kernel may contain both drivers.
>=20

You're right, this will disable the kernel supporting both drivers.
I'll fix it.

Thanks,
Mingkai

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

* RE: [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
  2010-07-26  0:14   ` [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Grant Likely
  2010-07-26  6:18     ` Hu Mingkai-B21284
@ 2010-07-26  7:07     ` Zang Roy-R61911
  2010-07-26  7:45       ` Grant Likely
  1 sibling, 1 reply; 29+ messages in thread
From: Zang Roy-R61911 @ 2010-07-26  7:07 UTC (permalink / raw)
  To: Grant Likely, Hu Mingkai-B21284, galak; +Cc: linuxppc-dev

=20

> -----Original Message-----
> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of=20
> Grant Likely
> Sent: Monday, July 26, 2010 8:14 AM
> To: Hu Mingkai-B21284; "@angua.secretlab.ca"@angua.secretlab.ca
> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang=20
> Roy-R61911
> Subject: Re: [PATCH 1/6] spi/mpc8xxx: refactor the common=20
> code for SPI/eSPI controller
>=20
> On Tue, Jul 20, 2010 at 10:08:20AM +0800, Mingkai Hu wrote:
> > Refactor the common code to file spi_mpc8xxx.c used by SPI/eSPI
> > controller driver, move the SPI controller driver to a new file
> > fsl_spi.c, and leave the QE/CPM SPI controller code in this file.
> >=20
> > 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.
> >=20
> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> > ---
> >  drivers/spi/Kconfig       |   13 +-
> >  drivers/spi/Makefile      |    1 +
> >  drivers/spi/fsl_spi.c     | 1118=20
> ++++++++++++++++++++++++++++++++++++++++++
> >  drivers/spi/spi_mpc8xxx.c | 1198=20
> ++-------------------------------------------
> >  drivers/spi/spi_mpc8xxx.h |  135 +++++
>=20
> Please name files spi-*.[ch].  I'm going to start enforcing=20
> this naming convention in the drivers/spi directory.
>=20
> >  5 files changed, 1299 insertions(+), 1166 deletions(-)
> >  create mode 100644 drivers/spi/fsl_spi.c
> >  create mode 100644 drivers/spi/spi_mpc8xxx.h
> >=20
> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> > index 91c2f4f..cd564e2 100644
> > --- a/drivers/spi/Kconfig
> > +++ b/drivers/spi/Kconfig
> > @@ -183,11 +183,18 @@ config SPI_MPC512x_PSC
> >  	  Controller in SPI master mode.
> > =20
> >  config SPI_MPC8xxx
> > -	tristate "Freescale MPC8xxx SPI controller"
> > +	bool
>=20
> This should be tristate so it can be loaded as a module.
>=20
> >  	depends on FSL_SOC
> >  	help
> > -	  This enables using the Freescale MPC8xxx SPI=20
> controllers in master
> > -	  mode.
> > +	  This enables using the Freescale MPC8xxx SPI/eSPI controllers
> > +	  driver library.
>=20
> Drop the help text entirely.  It isn't needed on=20
> non-user-visible options.
>=20
> > +
> > +config SPI_FSL_SPI
> > +	tristate "Freescale SPI controller"
>=20
> "Freescale SPI controller is rather generic and doesn't give any clues
> as to which devices actually have this controller.  At the very least
> the help text should state what parts contain this controller.
>=20
> On that note, the naming convention seems a little loose. =20
> Since both the eSPI and SPI are using SPI_MPC8xxx, then=20
> really the names should be:
>=20
> config SPI_MPC8xxx_SPI
> and
> config SPI_MPC8xxx_ESPI

SPI_FSL_SPI and SPI_FSL_ESDP are better at this point.
83xx platforms and some of 85xx platforms use SPI controller.=20
>From mpc8536, 85xx use ESP controller, BUT currently all P10xx, P20xx,
P40xx use ESPI controller.=20
8xxx will not cover pxxx serial processor.
Thanks.
Roy

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

* RE: [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions
  2010-07-26  0:28       ` [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions Grant Likely
@ 2010-07-26  7:25         ` Hu Mingkai-B21284
  2010-07-26  7:52           ` Grant Likely
  0 siblings, 1 reply; 29+ messages in thread
From: Hu Mingkai-B21284 @ 2010-07-26  7:25 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, Zang Roy-R61911

=20

> -----Original Message-----
> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of=20
> Grant Likely
> Sent: Monday, July 26, 2010 8:28 AM
> To: Hu Mingkai-B21284
> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang=20
> Roy-R61911
> Subject: Re: [PATCH 3/6] of/spi: add support to parse the SPI=20
> flash's partitions
>=20
> On Tue, Jul 20, 2010 at 10:08:22AM +0800, Mingkai Hu wrote:
> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> > ---
> >  drivers/of/of_spi.c       |   11 +++++++++++
> >  drivers/spi/spi_mpc8xxx.c |    1 +
> >  2 files changed, 12 insertions(+), 0 deletions(-)
> >=20
> > diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c index=20
> > 5fed7e3..284ca0e 100644
> > --- a/drivers/of/of_spi.c
> > +++ b/drivers/of/of_spi.c
> > @@ -10,6 +10,8 @@
> >  #include <linux/device.h>
> >  #include <linux/spi/spi.h>
> >  #include <linux/of_spi.h>
> > +#include <linux/spi/flash.h>
> > +#include <linux/mtd/partitions.h>
> > =20
> >  /**
> >   * of_register_spi_devices - Register child devices onto=20
> the SPI bus=20
> > @@ -26,6 +28,7 @@ void of_register_spi_devices(struct=20
> spi_master *master, struct device_node *np)
> >  	const __be32 *prop;
> >  	int rc;
> >  	int len;
> > +	struct flash_platform_data *pdata;
> > =20
> >  	for_each_child_of_node(np, nc) {
> >  		/* Alloc an spi_device */
> > @@ -81,6 +84,14 @@ void of_register_spi_devices(struct=20
> spi_master *master, struct device_node *np)
> >  		of_node_get(nc);
> >  		spi->dev.of_node =3D nc;
> > =20
> > +		/* Parse the mtd partitions */
> > +		pdata =3D kzalloc(sizeof(*pdata), GFP_KERNEL);
> > +		if (!pdata)
> > +			return;
> > +		pdata->nr_parts =3D of_mtd_parse_partitions(&master->dev,
> > +				nc, &pdata->parts);
> > +		spi->dev.platform_data =3D pdata;
> > +
>=20
> Nack.  Not all spi devices are mtd devices.  In fact, most are not.
>=20
> The spi driver itself should call the of_mtd_parse_partitions=20
> code to get the partition map.  Do not use pdata in this case.
>=20

Yes, we can call of_mtd_parse_partitions to get the partiton map, but
how can we
pass this map to spi device to register to MTD layer?

The spi device is created and registered when call
of_register_spi_device in the
spi controller probe function, then the spi device will traverse the spi
device driver
list to find the proper driver, if matched, then call the spi device
driver probe code
where the mtd partition info is registered to the mtd layer.

so where is the proper place to put the of_mtd_parse_partitions code?


> >  		/* Register the new device */
> >  		request_module(spi->modalias);
> >  		rc =3D spi_add_device(spi);
> > diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c=20
> > index efed70e..0fadaeb 100644
> > --- a/drivers/spi/spi_mpc8xxx.c
> > +++ b/drivers/spi/spi_mpc8xxx.c
> > @@ -137,6 +137,7 @@ int mpc8xxx_spi_transfer(struct spi_device *spi,
> > =20
> >  void mpc8xxx_spi_cleanup(struct spi_device *spi)  {
> > +	kfree(spi->dev.platform_data);
>=20
> Irrelevant given the above comment, but how does this even=20
> work?  What if a driver was detached and reattached to an=20
> spi_device?  The platform_data would be freed.  Not to=20
> mention that the pointer isn't cleared, so the driver would=20
> have no idea that it has a freed pointer.
>=20

It works. If the driver detached, the spi device platform_data will be
released,
when reattached, the of_register_spi_devices will be called again, the
platform_data
will be allocated.

Thanks,
Mingkai

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

* RE: [PATCH 4/6] mtd: m25p80: change the read function to read page by page
  2010-07-26  0:30         ` [PATCH 4/6] mtd: m25p80: change the read function to read page by page Grant Likely
@ 2010-07-26  7:33           ` Hu Mingkai-B21284
  2010-07-26  7:55             ` Grant Likely
  0 siblings, 1 reply; 29+ messages in thread
From: Hu Mingkai-B21284 @ 2010-07-26  7:33 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, Zang Roy-R61911

=20

> -----Original Message-----
> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of=20
> Grant Likely
> Sent: Monday, July 26, 2010 8:30 AM
> To: Hu Mingkai-B21284
> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang=20
> Roy-R61911
> Subject: Re: [PATCH 4/6] mtd: m25p80: change the read=20
> function to read page by page
>=20
> On Tue, Jul 20, 2010 at 10:08:23AM +0800, Mingkai Hu wrote:
> > For Freescale's eSPI controller, the max transaction length=20
> one time=20
> > is limitted by the SPCOM[TRANSLEN] field which is 0x10000. When used
> > mkfs.ext2 command to create ext2 filesystem on the flash, the read=20
> > length will exceed the max value of the SPCOM[TRANSLEN] field, so=20
> > change the read function to read page by page.
> >=20
> > For other SPI flash driver, also needed to change the read=20
> function if=20
> > used the eSPI controller.
> >=20
> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> > ---
> >  drivers/mtd/devices/m25p80.c |   18 ++++++++++++++----
> >  1 files changed, 14 insertions(+), 4 deletions(-)
> >=20
> > diff --git a/drivers/mtd/devices/m25p80.c=20
> > b/drivers/mtd/devices/m25p80.c index 81e49a9..6cbe6b1 100644
> > --- a/drivers/mtd/devices/m25p80.c
> > +++ b/drivers/mtd/devices/m25p80.c
> > @@ -317,6 +317,7 @@ static int m25p80_read(struct mtd_info=20
> *mtd, loff_t from, size_t len,
> >  	struct m25p *flash =3D mtd_to_m25p(mtd);
> >  	struct spi_transfer t[2];
> >  	struct spi_message m;
> > +	u32 i, page_size =3D 0;
> > =20
> >  	DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
> >  			dev_name(&flash->spi->dev), __func__,=20
> "from", @@ -341,7 +342,6 @@=20
> > static int m25p80_read(struct mtd_info *mtd, loff_t from,=20
> size_t len,
> >  	spi_message_add_tail(&t[0], &m);
> > =20
> >  	t[1].rx_buf =3D buf;
> > -	t[1].len =3D len;
> >  	spi_message_add_tail(&t[1], &m);
> > =20
> >  	/* Byte count starts at zero. */
> > @@ -364,11 +364,21 @@ static int m25p80_read(struct mtd_info *mtd,=20
> > loff_t from, size_t len,
> > =20
> >  	/* Set up the write data buffer. */
> >  	flash->command[0] =3D OPCODE_READ;
> > -	m25p_addr2cmd(flash, from, flash->command);
> > =20
> > -	spi_sync(flash->spi, &m);
> > +	for (i =3D page_size; i < len; i +=3D page_size) {
> > +		page_size =3D len - i;
> > +		if (page_size > flash->page_size)
> > +			page_size =3D flash->page_size;
> > =20
> > -	*retlen =3D m.actual_length - m25p_cmdsz(flash) -=20
> FAST_READ_DUMMY_BYTE;
> > +		m25p_addr2cmd(flash, from + i, flash->command);
> > +		t[1].len =3D page_size;
> > +		t[1].rx_buf =3D buf + i;
> > +
> > +		spi_sync(flash->spi, &m);
> > +
> > +		*retlen +=3D m.actual_length - m25p_cmdsz(flash)
> > +			- FAST_READ_DUMMY_BYTE;
> > +	}
>=20
> This patch seems to cripple all users just because eSPI=20
> cannot handle it.  Am I reading it wrong?
>=20

You're right, this will cripple all users.

At first, I want to contain this specific code with CONFIG_SPI_FSL_ESPI
option,
or register a specific read function like:

#ifdef CONFIG_SPI_FSL_ESPI
        flash->mtd.read =3D m25p80_read_espi;
#endif

but this will make the code looks arguly, are there other ways?

Thanks,
Mingkai

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

* RE: [PATCH 5/6] powerpc/of: add eSPI controller dts bindings
  2010-07-26  0:33           ` [PATCH 5/6] powerpc/of: add eSPI controller dts bindings Grant Likely
@ 2010-07-26  7:35             ` Hu Mingkai-B21284
  0 siblings, 0 replies; 29+ messages in thread
From: Hu Mingkai-B21284 @ 2010-07-26  7:35 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, Zang Roy-R61911

=20

> -----Original Message-----
> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of=20
> Grant Likely
> Sent: Monday, July 26, 2010 8:34 AM
> To: Hu Mingkai-B21284
> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang=20
> Roy-R61911
> Subject: Re: [PATCH 5/6] powerpc/of: add eSPI controller dts bindings
>=20
> On Tue, Jul 20, 2010 at 10:08:24AM +0800, Mingkai Hu wrote:
> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> > ---
> >  Documentation/powerpc/dts-bindings/fsl/spi.txt |   20=20
> ++++++++++++++++++++
> >  1 files changed, 20 insertions(+), 0 deletions(-)
> >=20
> > diff --git a/Documentation/powerpc/dts-bindings/fsl/spi.txt=20
> > b/Documentation/powerpc/dts-bindings/fsl/spi.txt
> > index 80510c0..b360bf9 100644
> > --- a/Documentation/powerpc/dts-bindings/fsl/spi.txt
> > +++ b/Documentation/powerpc/dts-bindings/fsl/spi.txt
> > @@ -29,3 +29,23 @@ Example:
> >  		gpios =3D <&gpio 18 1	// device reg=3D<0>
> >  			 &gpio 19 1>;	// device reg=3D<1>
> >  	};
> > +
> > +
> > +* eSPI (Enhanced Serial Peripheral Interface)
> > +
> > +Required properties:
> > +- compatible : should be "fsl,espi".
>=20
> Good practice is to always fully identify the SoC in the=20
> compatible values, followed by an optional list of other=20
> specific chips it is compatible with.  Generic compatibles=20
> like "fsl,espi" are not a good idea.
>=20
> +- compatible: should be "fsl,<chip>-espi".
>=20

Ok, the mpc8536 is the first chip to develop this driver, so will use
"fsl,mpc8536-espi".

Thanks,
Mingkai

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

* RE: [PATCH 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board
  2010-07-26  0:35             ` Grant Likely
@ 2010-07-26  7:39               ` Hu Mingkai-B21284
  2010-07-26  7:59                 ` Grant Likely
  0 siblings, 1 reply; 29+ messages in thread
From: Hu Mingkai-B21284 @ 2010-07-26  7:39 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, Zang Roy-R61911

=20

> -----Original Message-----
> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of=20
> Grant Likely
> Sent: Monday, July 26, 2010 8:35 AM
> To: Hu Mingkai-B21284
> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang=20
> Roy-R61911
> Subject: Re: [PATCH 6/6] DTS: add SPI flash(s25fl128p01)=20
> support on p4080ds and mpc8536ds board
>=20
> On Tue, Jul 20, 2010 at 10:08:25AM +0800, Mingkai Hu wrote:
> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> > ---
> >  arch/powerpc/boot/dts/mpc8536ds.dts |   52=20
> +++++++++++++++++++++++++++++++++++
> >  arch/powerpc/boot/dts/p4080ds.dts   |    9 ++----
> >  2 files changed, 55 insertions(+), 6 deletions(-)
> >=20
> > diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts=20
> > b/arch/powerpc/boot/dts/mpc8536ds.dts
> > index 815cebb..e5d07ec 100644
> > --- a/arch/powerpc/boot/dts/mpc8536ds.dts
> > +++ b/arch/powerpc/boot/dts/mpc8536ds.dts
> > @@ -108,6 +108,58 @@
> >  			};
> >  		};
> > =20
> > +		spi@7000 {
> > +			#address-cells =3D <1>;
> > +			#size-cells =3D <0>;
> > +			compatible =3D "fsl,espi";
> > +			reg =3D <0x7000 0x1000>;
> > +			interrupts =3D <59 0x2>;
> > +			interrupt-parent =3D <&mpic>;
> > + 			fsl,espi-num-chipselects =3D <4>;
> > +
> > + 			flash@0 {
> > +				#address-cells =3D <1>;
> > +				#size-cells =3D <1>;
> > + 				compatible =3D "spansion,s25sl12801";
>=20
> whitespace inconsitencies
>=20
> > +				reg =3D <0>;
> > +				spi-max-frequency =3D <40000000>;
> > +				partition@u-boot {
> > +					label =3D "u-boot";
> > +					reg =3D <0x00000000 0x00100000>;
> > +					read-only;
> > +				};
> > +				partition@kernel {
> > +					label =3D "kernel";
> > +					reg =3D <0x00100000 0x00500000>;
> > +					read-only;
> > +				};
> > +				partition@dtb {
> > +					label =3D "dtb";
> > +					reg =3D <0x00600000 0x00100000>;
> > +					read-only;
> > +				};
> > +				partition@fs {
> > +					label =3D "file system";
> > +					reg =3D <0x00700000 0x00900000>;
> > +				};
> > +			};
> > + 			flash@1 {
> > + 				compatible =3D "spansion,s25sl12801";
> > +				reg =3D <1>;
> > +				spi-max-frequency =3D <40000000>;
> > +			};
> > + 			flash@2 {
> > + 				compatible =3D "spansion,s25sl12801";
> > +				reg =3D <2>;
> > +				spi-max-frequency =3D <40000000>;
> > +			};
> > + 			flash@3 {
> > + 				compatible =3D "spansion,s25sl12801";
>=20
> whitespace inconsitencies
>=20
> > +				reg =3D <3>;
> > +				spi-max-frequency =3D <40000000>;
> > +			};
> > +		};
> > +
> >  		dma@21300 {
> >  			#address-cells =3D <1>;
> >  			#size-cells =3D <1>;
> > diff --git a/arch/powerpc/boot/dts/p4080ds.dts=20
> > b/arch/powerpc/boot/dts/p4080ds.dts
> > index 6b29eab..ac7dd23 100644
> > --- a/arch/powerpc/boot/dts/p4080ds.dts
> > +++ b/arch/powerpc/boot/dts/p4080ds.dts
> > @@ -236,22 +236,19 @@
> >  		};
> > =20
> >  		spi@110000 {
> > -			cell-index =3D <0>;
> >  			#address-cells =3D <1>;
> >  			#size-cells =3D <0>;
> >  			compatible =3D "fsl,espi";
> >  			reg =3D <0x110000 0x1000>;
> >  			interrupts =3D <53 0x2>;
> >  			interrupt-parent =3D <&mpic>;
> > -			espi,num-ss-bits =3D <4>;
> > -			mode =3D "cpu";
> > + 			fsl,espi-num-chipselects =3D <4>;
> > =20
> > -			fsl_m25p80@0 {
> > + 			flash@0 {
> >  				#address-cells =3D <1>;
> >  				#size-cells =3D <1>;
> > -				compatible =3D "fsl,espi-flash";
> > + 				compatible =3D "spansion,s25sl12801";
>=20
> whitespace inconsistencies
>=20

I use checkpatch to check the patch, but don't find any warnings and
errors.
so what's the whitespace inconsistencies means?

hmk@rock:~/public/linux-2.6$ ./scripts/checkpatch.pl
patch/public/v1/0006-DTS-add-SPI-flash-s25fl128p01-support-on-p4080ds-an
d.patch
total: 0 errors, 0 warnings, 83 lines checked

patch/public/v1/0006-DTS-add-SPI-flash-s25fl128p01-support-on-p4080ds-an
d.patch has no obvious style problems and is ready for submission.

Thanks,
Mingkai

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

* Re: [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
  2010-07-26  7:07     ` Zang Roy-R61911
@ 2010-07-26  7:45       ` Grant Likely
  0 siblings, 0 replies; 29+ messages in thread
From: Grant Likely @ 2010-07-26  7:45 UTC (permalink / raw)
  To: Zang Roy-R61911; +Cc: linuxppc-dev, Hu Mingkai-B21284

On Mon, Jul 26, 2010 at 1:07 AM, Zang Roy-R61911 <r61911@freescale.com> wro=
te:
>
>
>> -----Original Message-----
>> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of
>> Grant Likely
>> Sent: Monday, July 26, 2010 8:14 AM
>> To: Hu Mingkai-B21284; "@angua.secretlab.ca"@angua.secretlab.ca
>> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang
>> Roy-R61911
>> Subject: Re: [PATCH 1/6] spi/mpc8xxx: refactor the common
>> code for SPI/eSPI controller
>>
>> On Tue, Jul 20, 2010 at 10:08:20AM +0800, Mingkai Hu wrote:
>> > Refactor the common code to file spi_mpc8xxx.c used by SPI/eSPI
>> > controller driver, move the SPI controller driver to a new file
>> > fsl_spi.c, and leave the QE/CPM SPI controller code in this file.
>> >
>> > 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>
>> > ---
>> > =A0drivers/spi/Kconfig =A0 =A0 =A0 | =A0 13 +-
>> > =A0drivers/spi/Makefile =A0 =A0 =A0| =A0 =A01 +
>> > =A0drivers/spi/fsl_spi.c =A0 =A0 | 1118
>> ++++++++++++++++++++++++++++++++++++++++++
>> > =A0drivers/spi/spi_mpc8xxx.c | 1198
>> ++-------------------------------------------
>> > =A0drivers/spi/spi_mpc8xxx.h | =A0135 +++++
>>
>> Please name files spi-*.[ch]. =A0I'm going to start enforcing
>> this naming convention in the drivers/spi directory.
>>
>> > =A05 files changed, 1299 insertions(+), 1166 deletions(-)
>> > =A0create mode 100644 drivers/spi/fsl_spi.c
>> > =A0create mode 100644 drivers/spi/spi_mpc8xxx.h
>> >
>> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
>> > index 91c2f4f..cd564e2 100644
>> > --- a/drivers/spi/Kconfig
>> > +++ b/drivers/spi/Kconfig
>> > @@ -183,11 +183,18 @@ config SPI_MPC512x_PSC
>> > =A0 =A0 =A0 Controller in SPI master mode.
>> >
>> > =A0config SPI_MPC8xxx
>> > - =A0 tristate "Freescale MPC8xxx SPI controller"
>> > + =A0 bool
>>
>> This should be tristate so it can be loaded as a module.
>>
>> > =A0 =A0 depends on FSL_SOC
>> > =A0 =A0 help
>> > - =A0 =A0 This enables using the Freescale MPC8xxx SPI
>> controllers in master
>> > - =A0 =A0 mode.
>> > + =A0 =A0 This enables using the Freescale MPC8xxx SPI/eSPI controller=
s
>> > + =A0 =A0 driver library.
>>
>> Drop the help text entirely. =A0It isn't needed on
>> non-user-visible options.
>>
>> > +
>> > +config SPI_FSL_SPI
>> > + =A0 tristate "Freescale SPI controller"
>>
>> "Freescale SPI controller is rather generic and doesn't give any clues
>> as to which devices actually have this controller. =A0At the very least
>> the help text should state what parts contain this controller.
>>
>> On that note, the naming convention seems a little loose.
>> Since both the eSPI and SPI are using SPI_MPC8xxx, then
>> really the names should be:
>>
>> config SPI_MPC8xxx_SPI
>> and
>> config SPI_MPC8xxx_ESPI
>
> SPI_FSL_SPI and SPI_FSL_ESDP are better at this point.
> 83xx platforms and some of 85xx platforms use SPI controller.
> From mpc8536, 85xx use ESP controller, BUT currently all P10xx, P20xx,
> P40xx use ESPI controller.
> 8xxx will not cover pxxx serial processor.

Then the config item for the shared code should be renamed to reflect this.

g.

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

* Re: [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions
  2010-07-26  7:25         ` Hu Mingkai-B21284
@ 2010-07-26  7:52           ` Grant Likely
  2010-07-26  8:20             ` Hu Mingkai-B21284
  0 siblings, 1 reply; 29+ messages in thread
From: Grant Likely @ 2010-07-26  7:52 UTC (permalink / raw)
  To: Hu Mingkai-B21284; +Cc: linuxppc-dev, Zang Roy-R61911

On Mon, Jul 26, 2010 at 1:25 AM, Hu Mingkai-B21284 <B21284@freescale.com> w=
rote:
>
>
>> -----Original Message-----
>> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of
>> Grant Likely
>> Sent: Monday, July 26, 2010 8:28 AM
>> To: Hu Mingkai-B21284
>> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang
>> Roy-R61911
>> Subject: Re: [PATCH 3/6] of/spi: add support to parse the SPI
>> flash's partitions
>>
>> On Tue, Jul 20, 2010 at 10:08:22AM +0800, Mingkai Hu wrote:
>> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
>> > ---
>> > =A0drivers/of/of_spi.c =A0 =A0 =A0 | =A0 11 +++++++++++
>> > =A0drivers/spi/spi_mpc8xxx.c | =A0 =A01 +
>> > =A02 files changed, 12 insertions(+), 0 deletions(-)
>> >
>> > diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c index
>> > 5fed7e3..284ca0e 100644
>> > --- a/drivers/of/of_spi.c
>> > +++ b/drivers/of/of_spi.c
>> > @@ -10,6 +10,8 @@
>> > =A0#include <linux/device.h>
>> > =A0#include <linux/spi/spi.h>
>> > =A0#include <linux/of_spi.h>
>> > +#include <linux/spi/flash.h>
>> > +#include <linux/mtd/partitions.h>
>> >
>> > =A0/**
>> > =A0 * of_register_spi_devices - Register child devices onto
>> the SPI bus
>> > @@ -26,6 +28,7 @@ void of_register_spi_devices(struct
>> spi_master *master, struct device_node *np)
>> > =A0 =A0 const __be32 *prop;
>> > =A0 =A0 int rc;
>> > =A0 =A0 int len;
>> > + =A0 struct flash_platform_data *pdata;
>> >
>> > =A0 =A0 for_each_child_of_node(np, nc) {
>> > =A0 =A0 =A0 =A0 =A0 =A0 /* Alloc an spi_device */
>> > @@ -81,6 +84,14 @@ void of_register_spi_devices(struct
>> spi_master *master, struct device_node *np)
>> > =A0 =A0 =A0 =A0 =A0 =A0 of_node_get(nc);
>> > =A0 =A0 =A0 =A0 =A0 =A0 spi->dev.of_node =3D nc;
>> >
>> > + =A0 =A0 =A0 =A0 =A0 /* Parse the mtd partitions */
>> > + =A0 =A0 =A0 =A0 =A0 pdata =3D kzalloc(sizeof(*pdata), GFP_KERNEL);
>> > + =A0 =A0 =A0 =A0 =A0 if (!pdata)
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
>> > + =A0 =A0 =A0 =A0 =A0 pdata->nr_parts =3D of_mtd_parse_partitions(&mas=
ter->dev,
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 nc, &pdata->part=
s);
>> > + =A0 =A0 =A0 =A0 =A0 spi->dev.platform_data =3D pdata;
>> > +
>>
>> Nack. =A0Not all spi devices are mtd devices. =A0In fact, most are not.
>>
>> The spi driver itself should call the of_mtd_parse_partitions
>> code to get the partition map. =A0Do not use pdata in this case.
>>
>
> Yes, we can call of_mtd_parse_partitions to get the partiton map, but
> how can we
> pass this map to spi device to register to MTD layer?
>
> The spi device is created and registered when call
> of_register_spi_device in the
> spi controller probe function, then the spi device will traverse the spi
> device driver
> list to find the proper driver, if matched, then call the spi device
> driver probe code
> where the mtd partition info is registered to the mtd layer.
>
> so where is the proper place to put the of_mtd_parse_partitions code?

In the device driver probe code.

>> > diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c
>> > index efed70e..0fadaeb 100644
>> > --- a/drivers/spi/spi_mpc8xxx.c
>> > +++ b/drivers/spi/spi_mpc8xxx.c
>> > @@ -137,6 +137,7 @@ int mpc8xxx_spi_transfer(struct spi_device *spi,
>> >
>> > =A0void mpc8xxx_spi_cleanup(struct spi_device *spi) =A0{
>> > + =A0 kfree(spi->dev.platform_data);
>>
>> Irrelevant given the above comment, but how does this even
>> work? =A0What if a driver was detached and reattached to an
>> spi_device? =A0The platform_data would be freed. =A0Not to
>> mention that the pointer isn't cleared, so the driver would
>> have no idea that it has a freed pointer.
>>
>
> It works. If the driver detached, the spi device platform_data will be
> released,
> when reattached, the of_register_spi_devices will be called again, the
> platform_data
> will be allocated.

Ah right, I wasn't looking in the right place.  On that note however,
the cleanup of spi_device allocated by the OF code should also have a
reciprocal helper that frees them too.  It shouldn't be done in the
individual drivers.

g.

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

* Re: [PATCH 4/6] mtd: m25p80: change the read function to read page by page
  2010-07-26  7:33           ` Hu Mingkai-B21284
@ 2010-07-26  7:55             ` Grant Likely
  0 siblings, 0 replies; 29+ messages in thread
From: Grant Likely @ 2010-07-26  7:55 UTC (permalink / raw)
  To: Hu Mingkai-B21284; +Cc: linuxppc-dev, Zang Roy-R61911

On Mon, Jul 26, 2010 at 1:33 AM, Hu Mingkai-B21284 <B21284@freescale.com> w=
rote:
>
>
>> -----Original Message-----
>> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of
>> Grant Likely
>> Sent: Monday, July 26, 2010 8:30 AM
>> To: Hu Mingkai-B21284
>> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang
>> Roy-R61911
>> Subject: Re: [PATCH 4/6] mtd: m25p80: change the read
>> function to read page by page
>>
>> On Tue, Jul 20, 2010 at 10:08:23AM +0800, Mingkai Hu wrote:
>> > For Freescale's eSPI controller, the max transaction length
>> one time
>> > is limitted by the SPCOM[TRANSLEN] field which is 0x10000. 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 change the read
>> function if
>> > used the eSPI controller.
>> >
>> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
>> > ---
>> > =A0drivers/mtd/devices/m25p80.c | =A0 18 ++++++++++++++----
>> > =A01 files changed, 14 insertions(+), 4 deletions(-)
>> >
>> > diff --git a/drivers/mtd/devices/m25p80.c
>> > b/drivers/mtd/devices/m25p80.c index 81e49a9..6cbe6b1 100644
>> > --- a/drivers/mtd/devices/m25p80.c
>> > +++ b/drivers/mtd/devices/m25p80.c
>> > @@ -317,6 +317,7 @@ static int m25p80_read(struct mtd_info
>> *mtd, loff_t from, size_t len,
>> > =A0 =A0 struct m25p *flash =3D mtd_to_m25p(mtd);
>> > =A0 =A0 struct spi_transfer t[2];
>> > =A0 =A0 struct spi_message m;
>> > + =A0 u32 i, page_size =3D 0;
>> >
>> > =A0 =A0 DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_name(&flash->spi->dev), __=
func__,
>> "from", @@ -341,7 +342,6 @@
>> > static int m25p80_read(struct mtd_info *mtd, loff_t from,
>> size_t len,
>> > =A0 =A0 spi_message_add_tail(&t[0], &m);
>> >
>> > =A0 =A0 t[1].rx_buf =3D buf;
>> > - =A0 t[1].len =3D len;
>> > =A0 =A0 spi_message_add_tail(&t[1], &m);
>> >
>> > =A0 =A0 /* Byte count starts at zero. */
>> > @@ -364,11 +364,21 @@ static int m25p80_read(struct mtd_info *mtd,
>> > loff_t from, size_t len,
>> >
>> > =A0 =A0 /* Set up the write data buffer. */
>> > =A0 =A0 flash->command[0] =3D OPCODE_READ;
>> > - =A0 m25p_addr2cmd(flash, from, flash->command);
>> >
>> > - =A0 spi_sync(flash->spi, &m);
>> > + =A0 for (i =3D page_size; i < len; i +=3D page_size) {
>> > + =A0 =A0 =A0 =A0 =A0 page_size =3D len - i;
>> > + =A0 =A0 =A0 =A0 =A0 if (page_size > flash->page_size)
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 page_size =3D flash->page_size;
>> >
>> > - =A0 *retlen =3D m.actual_length - m25p_cmdsz(flash) -
>> FAST_READ_DUMMY_BYTE;
>> > + =A0 =A0 =A0 =A0 =A0 m25p_addr2cmd(flash, from + i, flash->command);
>> > + =A0 =A0 =A0 =A0 =A0 t[1].len =3D page_size;
>> > + =A0 =A0 =A0 =A0 =A0 t[1].rx_buf =3D buf + i;
>> > +
>> > + =A0 =A0 =A0 =A0 =A0 spi_sync(flash->spi, &m);
>> > +
>> > + =A0 =A0 =A0 =A0 =A0 *retlen +=3D m.actual_length - m25p_cmdsz(flash)
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 - FAST_READ_DUMMY_BYTE;
>> > + =A0 }
>>
>> This patch seems to cripple all users just because eSPI
>> cannot handle it. =A0Am I reading it wrong?
>>
>
> You're right, this will cripple all users.
>
> At first, I want to contain this specific code with CONFIG_SPI_FSL_ESPI
> option,
> or register a specific read function like:
>
> #ifdef CONFIG_SPI_FSL_ESPI
> =A0 =A0 =A0 =A0flash->mtd.read =3D m25p80_read_espi;
> #endif
>
> but this will make the code looks arguly,

And it is multiplatform-unfriendly.

> are there other ways?

You need to select the correct transfer behaviour at driver probe
time.  You'll need a way to indicate that the spi_master isn't able to
handle your transfer request.  I'd need to think about it more to come
up with a concrete suggestion.

g.

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

* Re: [PATCH 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board
  2010-07-26  7:39               ` Hu Mingkai-B21284
@ 2010-07-26  7:59                 ` Grant Likely
  0 siblings, 0 replies; 29+ messages in thread
From: Grant Likely @ 2010-07-26  7:59 UTC (permalink / raw)
  To: Hu Mingkai-B21284; +Cc: linuxppc-dev, Zang Roy-R61911

On Mon, Jul 26, 2010 at 1:39 AM, Hu Mingkai-B21284 <B21284@freescale.com> w=
rote:
>
>
>> -----Original Message-----
>> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf Of
>> Grant Likely
>> Sent: Monday, July 26, 2010 8:35 AM
>> To: Hu Mingkai-B21284
>> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang
>> Roy-R61911
>> Subject: Re: [PATCH 6/6] DTS: add SPI flash(s25fl128p01)
>> support on p4080ds and mpc8536ds board
>>
>> On Tue, Jul 20, 2010 at 10:08:25AM +0800, Mingkai Hu wrote:
>> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
>> > ---
>> > =A0arch/powerpc/boot/dts/mpc8536ds.dts | =A0 52
>> +++++++++++++++++++++++++++++++++++
>> > =A0arch/powerpc/boot/dts/p4080ds.dts =A0 | =A0 =A09 ++----
>> > =A02 files changed, 55 insertions(+), 6 deletions(-)
>> >
>> > diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts
>> > b/arch/powerpc/boot/dts/mpc8536ds.dts
>> > index 815cebb..e5d07ec 100644
>> > --- a/arch/powerpc/boot/dts/mpc8536ds.dts
>> > +++ b/arch/powerpc/boot/dts/mpc8536ds.dts
>> > @@ -108,6 +108,58 @@
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
>> > =A0 =A0 =A0 =A0 =A0 =A0 };
>> >
>> > + =A0 =A0 =A0 =A0 =A0 spi@7000 {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <0>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,espi";
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x7000 0x1000>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <59 0x2>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&mpic>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,espi-num-chipselects =3D <4>=
;
>> > +
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 flash@0 {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =
=3D <1>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D =
<1>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "=
spansion,s25sl12801";
>>
>> whitespace inconsitencies
>>
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 spi-max-frequenc=
y =3D <40000000>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 partition@u-boot=
 {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
label =3D "u-boot";
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
reg =3D <0x00000000 0x00100000>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
read-only;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 partition@kernel=
 {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
label =3D "kernel";
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
reg =3D <0x00100000 0x00500000>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
read-only;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 partition@dtb {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
label =3D "dtb";
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
reg =3D <0x00600000 0x00100000>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
read-only;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 partition@fs {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
label =3D "file system";
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
reg =3D <0x00700000 0x00900000>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 flash@1 {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "=
spansion,s25sl12801";
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <1>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 spi-max-frequenc=
y =3D <40000000>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 flash@2 {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "=
spansion,s25sl12801";
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <2>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 spi-max-frequenc=
y =3D <40000000>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 flash@3 {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "=
spansion,s25sl12801";
>>
>> whitespace inconsitencies
>>
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <3>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 spi-max-frequenc=
y =3D <40000000>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
>> > + =A0 =A0 =A0 =A0 =A0 };
>> > +
>> > =A0 =A0 =A0 =A0 =A0 =A0 dma@21300 {
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <1>;
>> > diff --git a/arch/powerpc/boot/dts/p4080ds.dts
>> > b/arch/powerpc/boot/dts/p4080ds.dts
>> > index 6b29eab..ac7dd23 100644
>> > --- a/arch/powerpc/boot/dts/p4080ds.dts
>> > +++ b/arch/powerpc/boot/dts/p4080ds.dts
>> > @@ -236,22 +236,19 @@
>> > =A0 =A0 =A0 =A0 =A0 =A0 };
>> >
>> > =A0 =A0 =A0 =A0 =A0 =A0 spi@110000 {
>> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cell-index =3D <0>;
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <0>;
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,espi";
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x110000 0x1000>;
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <53 0x2>;
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&mpic>;
>> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 espi,num-ss-bits =3D <4>;
>> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mode =3D "cpu";
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,espi-num-chipselects =3D <4>=
;
>> >
>> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl_m25p80@0 {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 flash@0 {
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells=
 =3D <1>;
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =
=3D <1>;
>> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "=
fsl,espi-flash";
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "=
spansion,s25sl12801";
>>
>> whitespace inconsistencies
>>
>
> I use checkpatch to check the patch, but don't find any warnings and
> errors.
> so what's the whitespace inconsistencies means?
>
> hmk@rock:~/public/linux-2.6$ ./scripts/checkpatch.pl
> patch/public/v1/0006-DTS-add-SPI-flash-s25fl128p01-support-on-p4080ds-an
> d.patch
> total: 0 errors, 0 warnings, 83 lines checked
>
> patch/public/v1/0006-DTS-add-SPI-flash-s25fl128p01-support-on-p4080ds-an
> d.patch has no obvious style problems and is ready for submission.

Configure your editor to show tab characters differently from spaces.
About a dozen lines have a single space at the beginning of the line
before the tab indentation.

g.

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

* RE: [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions
  2010-07-26  7:52           ` Grant Likely
@ 2010-07-26  8:20             ` Hu Mingkai-B21284
  2010-07-27 19:24               ` Grant Likely
  0 siblings, 1 reply; 29+ messages in thread
From: Hu Mingkai-B21284 @ 2010-07-26  8:20 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, Zang Roy-R61911

=20

> -----Original Message-----
> From: glikely@secretlab.ca [mailto:glikely@secretlab.ca] On=20
> Behalf Of Grant Likely
> Sent: Monday, July 26, 2010 3:53 PM
> To: Hu Mingkai-B21284
> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang=20
> Roy-R61911
> Subject: Re: [PATCH 3/6] of/spi: add support to parse the SPI=20
> flash's partitions
>=20
> On Mon, Jul 26, 2010 at 1:25 AM, Hu Mingkai-B21284=20
> <B21284@freescale.com> wrote:
> >
> >
> >> -----Original Message-----
> >> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf=20
> Of Grant=20
> >> Likely
> >> Sent: Monday, July 26, 2010 8:28 AM
> >> To: Hu Mingkai-B21284
> >> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang
> >> Roy-R61911
> >> Subject: Re: [PATCH 3/6] of/spi: add support to parse the=20
> SPI flash's=20
> >> partitions
> >>
> >> On Tue, Jul 20, 2010 at 10:08:22AM +0800, Mingkai Hu wrote:
> >> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> >> > ---
> >> > =A0drivers/of/of_spi.c =A0 =A0 =A0 | =A0 11 +++++++++++
> >> > =A0drivers/spi/spi_mpc8xxx.c | =A0 =A01 +
> >> > =A02 files changed, 12 insertions(+), 0 deletions(-)
> >> >
> >> > diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c index=20
> >> > 5fed7e3..284ca0e 100644
> >> > --- a/drivers/of/of_spi.c
> >> > +++ b/drivers/of/of_spi.c
> >> > @@ -10,6 +10,8 @@
> >> > =A0#include <linux/device.h>
> >> > =A0#include <linux/spi/spi.h>
> >> > =A0#include <linux/of_spi.h>
> >> > +#include <linux/spi/flash.h>
> >> > +#include <linux/mtd/partitions.h>
> >> >
> >> > =A0/**
> >> > =A0 * of_register_spi_devices - Register child devices onto
> >> the SPI bus
> >> > @@ -26,6 +28,7 @@ void of_register_spi_devices(struct
> >> spi_master *master, struct device_node *np)
> >> > =A0 =A0 const __be32 *prop;
> >> > =A0 =A0 int rc;
> >> > =A0 =A0 int len;
> >> > + =A0 struct flash_platform_data *pdata;
> >> >
> >> > =A0 =A0 for_each_child_of_node(np, nc) {
> >> > =A0 =A0 =A0 =A0 =A0 =A0 /* Alloc an spi_device */ @@ -81,6 +84,14 =
@@ void=20
> >> > of_register_spi_devices(struct
> >> spi_master *master, struct device_node *np)
> >> > =A0 =A0 =A0 =A0 =A0 =A0 of_node_get(nc);
> >> > =A0 =A0 =A0 =A0 =A0 =A0 spi->dev.of_node =3D nc;
> >> >
> >> > + =A0 =A0 =A0 =A0 =A0 /* Parse the mtd partitions */
> >> > + =A0 =A0 =A0 =A0 =A0 pdata =3D kzalloc(sizeof(*pdata), =
GFP_KERNEL);
> >> > + =A0 =A0 =A0 =A0 =A0 if (!pdata)
> >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
> >> > + =A0 =A0 =A0 =A0 =A0 pdata->nr_parts =3D=20
> of_mtd_parse_partitions(&master->dev,
> >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 nc, =
&pdata->parts);
> >> > + =A0 =A0 =A0 =A0 =A0 spi->dev.platform_data =3D pdata;
> >> > +
> >>
> >> Nack. =A0Not all spi devices are mtd devices. =A0In fact, most are =
not.
> >>
> >> The spi driver itself should call the=20
> of_mtd_parse_partitions code to=20
> >> get the partition map. =A0Do not use pdata in this case.
> >>
> >
> > Yes, we can call of_mtd_parse_partitions to get the=20
> partiton map, but=20
> > how can we pass this map to spi device to register to MTD layer?
> >
> > The spi device is created and registered when call=20
> > of_register_spi_device in the spi controller probe=20
> function, then the=20
> > spi device will traverse the spi device driver list to find=20
> the proper=20
> > driver, if matched, then call the spi device driver probe=20
> code where=20
> > the mtd partition info is registered to the mtd layer.
> >
> > so where is the proper place to put the=20
> of_mtd_parse_partitions code?
>=20
> In the device driver probe code.
>=20

This is the way that I did at first, thus we need to add the same code
in all the spi flash driver to get partition map info.

or we add the get partition map code to of_spi.c?

+/*
+ * of_parse_flash_partition - Parse the flash partition on the SPI bus
+ * @spi:       Pointer to spi_device device
+ */
+void of_parse_flash_partition(struct spi_device *spi)
+{
+       struct mtd_partition *parts;
+       struct flash_platform_data *spi_pdata;
+       int nr_parts =3D 0;
+       static int num_flash;
+       struct device_node *np =3D spi->dev.archdata.of_node;
+
+       nr_parts =3D of_mtd_parse_partitions(&spi->dev, np, &parts);
+       if (!nr_parts)
+               goto end;
+
+       spi_pdata =3D kzalloc(sizeof(*spi_pdata), GFP_KERNEL);
+       if (!spi_pdata)
+               goto end;
+       spi_pdata->name =3D kzalloc(10, GFP_KERNEL);
+       if (!spi_pdata->name)
+               goto free_flash;
+       snprintf(spi_pdata->name, 10, "SPIFLASH%d", num_flash++);
+
+       spi_pdata->parts =3D parts;
+       spi_pdata->nr_parts =3D nr_parts;
+
+       spi->dev.platform_data =3D spi_pdata;
+
+       return;
+
+free_flash:
+       kfree(spi_pdata);
+end:
+       return;
+}


> >> > diff --git a/drivers/spi/spi_mpc8xxx.c=20
> b/drivers/spi/spi_mpc8xxx.c=20
> >> > index efed70e..0fadaeb 100644
> >> > --- a/drivers/spi/spi_mpc8xxx.c
> >> > +++ b/drivers/spi/spi_mpc8xxx.c
> >> > @@ -137,6 +137,7 @@ int mpc8xxx_spi_transfer(struct spi_device=20
> >> > *spi,
> >> >
> >> > =A0void mpc8xxx_spi_cleanup(struct spi_device *spi) =A0{
> >> > + =A0 kfree(spi->dev.platform_data);
> >>
> >> Irrelevant given the above comment, but how does this even work? =
=A0
> >> What if a driver was detached and reattached to an=20
> spi_device? =A0The=20
> >> platform_data would be freed. =A0Not to mention that the=20
> pointer isn't=20
> >> cleared, so the driver would have no idea that it has a freed=20
> >> pointer.
> >>
> >
> > It works. If the driver detached, the spi device=20
> platform_data will be=20
> > released, when reattached, the of_register_spi_devices will=20
> be called=20
> > again, the platform_data will be allocated.
>=20
> Ah right, I wasn't looking in the right place.  On that note=20
> however, the cleanup of spi_device allocated by the OF code=20
> should also have a reciprocal helper that frees them too.  It=20
> shouldn't be done in the individual drivers.
>=20

We can define a helper to free the platform_data, but where it should be =
called?
Maybe spidev_release is a better place to call, after all the =
platfrom_data is allocated
when the spi device is created, so it should be freed when released.

Thanks,
Mingkai

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

* Re: [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions
  2010-07-26  8:20             ` Hu Mingkai-B21284
@ 2010-07-27 19:24               ` Grant Likely
  0 siblings, 0 replies; 29+ messages in thread
From: Grant Likely @ 2010-07-27 19:24 UTC (permalink / raw)
  To: Hu Mingkai-B21284; +Cc: linuxppc-dev, spi-devel-general, Zang Roy-R61911

[cc'ing spi-devel-general]

On Mon, Jul 26, 2010 at 2:20 AM, Hu Mingkai-B21284 <B21284@freescale.com> w=
rote:
>
>
>> -----Original Message-----
>> From: glikely@secretlab.ca [mailto:glikely@secretlab.ca] On
>> Behalf Of Grant Likely
>> Sent: Monday, July 26, 2010 3:53 PM
>> To: Hu Mingkai-B21284
>> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang
>> Roy-R61911
>> Subject: Re: [PATCH 3/6] of/spi: add support to parse the SPI
>> flash's partitions
>>
>> On Mon, Jul 26, 2010 at 1:25 AM, Hu Mingkai-B21284
>> <B21284@freescale.com> wrote:
>> >
>> >
>> >> -----Original Message-----
>> >> From: Grant Likely [mailto:glikely@secretlab.ca] On Behalf
>> Of Grant
>> >> Likely
>> >> Sent: Monday, July 26, 2010 8:28 AM
>> >> To: Hu Mingkai-B21284
>> >> Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Zang
>> >> Roy-R61911
>> >> Subject: Re: [PATCH 3/6] of/spi: add support to parse the
>> SPI flash's
>> >> partitions
>> >>
>> >> On Tue, Jul 20, 2010 at 10:08:22AM +0800, Mingkai Hu wrote:
>> >> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
>> >> > ---
>> >> > =A0drivers/of/of_spi.c =A0 =A0 =A0 | =A0 11 +++++++++++
>> >> > =A0drivers/spi/spi_mpc8xxx.c | =A0 =A01 +
>> >> > =A02 files changed, 12 insertions(+), 0 deletions(-)
>> >> >
>> >> > diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c index
>> >> > 5fed7e3..284ca0e 100644
>> >> > --- a/drivers/of/of_spi.c
>> >> > +++ b/drivers/of/of_spi.c
>> >> > @@ -10,6 +10,8 @@
>> >> > =A0#include <linux/device.h>
>> >> > =A0#include <linux/spi/spi.h>
>> >> > =A0#include <linux/of_spi.h>
>> >> > +#include <linux/spi/flash.h>
>> >> > +#include <linux/mtd/partitions.h>
>> >> >
>> >> > =A0/**
>> >> > =A0 * of_register_spi_devices - Register child devices onto
>> >> the SPI bus
>> >> > @@ -26,6 +28,7 @@ void of_register_spi_devices(struct
>> >> spi_master *master, struct device_node *np)
>> >> > =A0 =A0 const __be32 *prop;
>> >> > =A0 =A0 int rc;
>> >> > =A0 =A0 int len;
>> >> > + =A0 struct flash_platform_data *pdata;
>> >> >
>> >> > =A0 =A0 for_each_child_of_node(np, nc) {
>> >> > =A0 =A0 =A0 =A0 =A0 =A0 /* Alloc an spi_device */ @@ -81,6 +84,14 @=
@ void
>> >> > of_register_spi_devices(struct
>> >> spi_master *master, struct device_node *np)
>> >> > =A0 =A0 =A0 =A0 =A0 =A0 of_node_get(nc);
>> >> > =A0 =A0 =A0 =A0 =A0 =A0 spi->dev.of_node =3D nc;
>> >> >
>> >> > + =A0 =A0 =A0 =A0 =A0 /* Parse the mtd partitions */
>> >> > + =A0 =A0 =A0 =A0 =A0 pdata =3D kzalloc(sizeof(*pdata), GFP_KERNEL)=
;
>> >> > + =A0 =A0 =A0 =A0 =A0 if (!pdata)
>> >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
>> >> > + =A0 =A0 =A0 =A0 =A0 pdata->nr_parts =3D
>> of_mtd_parse_partitions(&master->dev,
>> >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 nc, &pdata->p=
arts);
>> >> > + =A0 =A0 =A0 =A0 =A0 spi->dev.platform_data =3D pdata;
>> >> > +
>> >>
>> >> Nack. =A0Not all spi devices are mtd devices. =A0In fact, most are no=
t.
>> >>
>> >> The spi driver itself should call the
>> of_mtd_parse_partitions code to
>> >> get the partition map. =A0Do not use pdata in this case.
>> >>
>> >
>> > Yes, we can call of_mtd_parse_partitions to get the
>> partiton map, but
>> > how can we pass this map to spi device to register to MTD layer?
>> >
>> > The spi device is created and registered when call
>> > of_register_spi_device in the spi controller probe
>> function, then the
>> > spi device will traverse the spi device driver list to find
>> the proper
>> > driver, if matched, then call the spi device driver probe
>> code where
>> > the mtd partition info is registered to the mtd layer.
>> >
>> > so where is the proper place to put the
>> of_mtd_parse_partitions code?
>>
>> In the device driver probe code.
>>
>
> This is the way that I did at first, thus we need to add the same code
> in all the spi flash driver to get partition map info.
>
> or we add the get partition map code to of_spi.c?

No, it really does not belong in of_spi.c because the spi code has no
knowledge about MTD devices.

I only see two valid options, to either:
a) add it to each MTD driver, or
b) add a hook to the core MTD code so that if an of_node pointer is
provided, and no partition data is provided, then it will parse the
partitions when the MTD device is registered.  You'd also need to code
it in a way that becomes a no-op when CONFIG_OF is not set.

>
> +/*
> + * of_parse_flash_partition - Parse the flash partition on the SPI bus
> + * @spi: =A0 =A0 =A0 Pointer to spi_device device
> + */
> +void of_parse_flash_partition(struct spi_device *spi)
> +{
> + =A0 =A0 =A0 struct mtd_partition *parts;
> + =A0 =A0 =A0 struct flash_platform_data *spi_pdata;
> + =A0 =A0 =A0 int nr_parts =3D 0;
> + =A0 =A0 =A0 static int num_flash;
> + =A0 =A0 =A0 struct device_node *np =3D spi->dev.archdata.of_node;
> +
> + =A0 =A0 =A0 nr_parts =3D of_mtd_parse_partitions(&spi->dev, np, &parts)=
;
> + =A0 =A0 =A0 if (!nr_parts)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto end;
> +
> + =A0 =A0 =A0 spi_pdata =3D kzalloc(sizeof(*spi_pdata), GFP_KERNEL);
> + =A0 =A0 =A0 if (!spi_pdata)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto end;
> + =A0 =A0 =A0 spi_pdata->name =3D kzalloc(10, GFP_KERNEL);
> + =A0 =A0 =A0 if (!spi_pdata->name)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto free_flash;
> + =A0 =A0 =A0 snprintf(spi_pdata->name, 10, "SPIFLASH%d", num_flash++);
> +
> + =A0 =A0 =A0 spi_pdata->parts =3D parts;
> + =A0 =A0 =A0 spi_pdata->nr_parts =3D nr_parts;
> +
> + =A0 =A0 =A0 spi->dev.platform_data =3D spi_pdata;
> +
> + =A0 =A0 =A0 return;
> +
> +free_flash:
> + =A0 =A0 =A0 kfree(spi_pdata);
> +end:
> + =A0 =A0 =A0 return;
> +}
>
>
>> >> > diff --git a/drivers/spi/spi_mpc8xxx.c
>> b/drivers/spi/spi_mpc8xxx.c
>> >> > index efed70e..0fadaeb 100644
>> >> > --- a/drivers/spi/spi_mpc8xxx.c
>> >> > +++ b/drivers/spi/spi_mpc8xxx.c
>> >> > @@ -137,6 +137,7 @@ int mpc8xxx_spi_transfer(struct spi_device
>> >> > *spi,
>> >> >
>> >> > =A0void mpc8xxx_spi_cleanup(struct spi_device *spi) =A0{
>> >> > + =A0 kfree(spi->dev.platform_data);
>> >>
>> >> Irrelevant given the above comment, but how does this even work?
>> >> What if a driver was detached and reattached to an
>> spi_device? =A0The
>> >> platform_data would be freed. =A0Not to mention that the
>> pointer isn't
>> >> cleared, so the driver would have no idea that it has a freed
>> >> pointer.
>> >>
>> >
>> > It works. If the driver detached, the spi device
>> platform_data will be
>> > released, when reattached, the of_register_spi_devices will
>> be called
>> > again, the platform_data will be allocated.
>>
>> Ah right, I wasn't looking in the right place. =A0On that note
>> however, the cleanup of spi_device allocated by the OF code
>> should also have a reciprocal helper that frees them too. =A0It
>> shouldn't be done in the individual drivers.
>>
>
> We can define a helper to free the platform_data, but where it should be =
called?
> Maybe spidev_release is a better place to call, after all the platfrom_da=
ta is allocated
> when the spi device is created, so it should be freed when released.

It would be called from the spi core code.  However, with two options
I gave above, platform_data shouldn't be needed at all.

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

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

end of thread, other threads:[~2010-07-27 19:24 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-20  2:08 [PATCH 0/6] refactor spi_mpc8xxx.c and add eSPI controller support Mingkai Hu
2010-07-20  2:08 ` [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Mingkai Hu
2010-07-20  2:08   ` [PATCH 2/6] eSPI: add eSPI controller support Mingkai Hu
2010-07-20  2:08     ` [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions Mingkai Hu
2010-07-20  2:08       ` [PATCH 4/6] mtd: m25p80: change the read function to read page by page Mingkai Hu
2010-07-20  2:08         ` [PATCH 5/6] powerpc/of: add eSPI controller dts bindings Mingkai Hu
2010-07-20  2:08           ` [PATCH 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board Mingkai Hu
2010-07-26  0:35             ` Grant Likely
2010-07-26  7:39               ` Hu Mingkai-B21284
2010-07-26  7:59                 ` Grant Likely
2010-07-26  0:33           ` [PATCH 5/6] powerpc/of: add eSPI controller dts bindings Grant Likely
2010-07-26  7:35             ` Hu Mingkai-B21284
2010-07-26  0:30         ` [PATCH 4/6] mtd: m25p80: change the read function to read page by page Grant Likely
2010-07-26  7:33           ` Hu Mingkai-B21284
2010-07-26  7:55             ` Grant Likely
2010-07-26  0:28       ` [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions Grant Likely
2010-07-26  7:25         ` Hu Mingkai-B21284
2010-07-26  7:52           ` Grant Likely
2010-07-26  8:20             ` Hu Mingkai-B21284
2010-07-27 19:24               ` Grant Likely
2010-07-26  0:25     ` [PATCH 2/6] eSPI: add eSPI controller support Grant Likely
2010-07-26  7:02       ` Hu Mingkai-B21284
2010-07-26  0:14   ` [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Grant Likely
2010-07-26  6:18     ` Hu Mingkai-B21284
2010-07-26  6:48       ` Grant Likely
2010-07-26  7:07     ` Zang Roy-R61911
2010-07-26  7:45       ` Grant Likely
2010-07-26  0:36 ` [PATCH 0/6] refactor spi_mpc8xxx.c and add eSPI controller support Grant Likely
2010-07-26  5:52   ` 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).