linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/6] refactor spi_mpc8xxx.c and add eSPI controller support
@ 2010-08-02  7:51 Mingkai Hu
       [not found] ` <1280735524-17547-1-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
  0 siblings, 1 reply; 26+ messages in thread
From: Mingkai Hu @ 2010-08-02  7:51 UTC (permalink / raw)
  To: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: kumar.gala-KZfg59tc24xl57MIdRCFDg, tie-fei.zang-KZfg59tc24xl57MIdRCFDg

In-Reply-To: 

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

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

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

Thanks,
Mingkai


------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share
of $1 Million in cash or HP Products. Visit us here for more details:
http://p.sf.net/sfu/dev2dev-palm

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

* [PATCH v2 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
       [not found] ` <1280735524-17547-1-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2010-08-02  7:51   ` Mingkai Hu
       [not found]     ` <1280735524-17547-2-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
  0 siblings, 1 reply; 26+ messages in thread
From: Mingkai Hu @ 2010-08-02  7:51 UTC (permalink / raw)
  To: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: kumar.gala-KZfg59tc24xl57MIdRCFDg,
	tie-fei.zang-KZfg59tc24xl57MIdRCFDg, Mingkai Hu

Refactor the common code in file spi_mpc8xxx.c to spi_fsl_lib.c
used by SPI/eSPI controller driver as a library, move the SPI
controller driver to a new file spi_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-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
v2:
 - Rename spi_mpc8xxx.c to spi_fsl_lib.c, also the config name
 - Rename fsl_spi.c to spi_fsl_spi.c, also the config name
 - Move register map definiton from spi_fsl_lib.c to spi_fsl_spi.c
 - Break some funcions line in the arguments instead of the declaration
 - Init bits_per_word to 0 to eliminate the else clause
 - Add brace for the else clause to match if clause
 - Drop the last entry's comma in the match table
 - move module_init() immediately after the init fsl_spi_init() function

 drivers/spi/Kconfig       |   20 +-
 drivers/spi/Makefile      |    3 +-
 drivers/spi/spi_fsl_lib.c |  237 ++++++++
 drivers/spi/spi_fsl_lib.h |  119 ++++
 drivers/spi/spi_fsl_spi.c | 1173 +++++++++++++++++++++++++++++++++++++
 drivers/spi/spi_mpc8xxx.c | 1421 ---------------------------------------------
 6 files changed, 1544 insertions(+), 1429 deletions(-)
 create mode 100644 drivers/spi/spi_fsl_lib.c
 create mode 100644 drivers/spi/spi_fsl_lib.h
 create mode 100644 drivers/spi/spi_fsl_spi.c
 delete mode 100644 drivers/spi/spi_mpc8xxx.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 91c2f4f..cd7f13b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -127,6 +127,19 @@ config SPI_EP93XX
 	  To compile this driver as a module, choose M here. The module will be
 	  called ep93xx_spi.
 
+config SPI_FSL_LIB
+	tristate
+	depends on FSL_SOC
+
+config SPI_FSL_SPI
+	tristate "Freescale SPI controller"
+	depends on FSL_SOC
+	select SPI_FSL_LIB
+	help
+	  This enables using the Freescale SPI controllers in master mode.
+	  MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
+	  MPC8569 uses the controller in QE mode, MPC8610 in cpu mode.
+
 config SPI_GPIO
 	tristate "GPIO-based bitbanging SPI Master"
 	depends on GENERIC_GPIO
@@ -182,13 +195,6 @@ config SPI_MPC512x_PSC
 	  This enables using the Freescale MPC5121 Programmable Serial
 	  Controller in SPI master mode.
 
-config SPI_MPC8xxx
-	tristate "Freescale MPC8xxx SPI controller"
-	depends on FSL_SOC
-	help
-	  This enables using the Freescale MPC8xxx SPI 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 e9cbd18..cf8d9be 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -22,6 +22,8 @@ obj-$(CONFIG_SPI_DESIGNWARE)		+= dw_spi.o
 obj-$(CONFIG_SPI_DW_PCI)		+= dw_spi_pci.o
 obj-$(CONFIG_SPI_DW_MMIO)		+= dw_spi_mmio.o
 obj-$(CONFIG_SPI_EP93XX)		+= ep93xx_spi.o
+obj-$(CONFIG_SPI_FSL_LIB)		+= spi_fsl_lib.o
+obj-$(CONFIG_SPI_FSL_SPI)		+= spi_fsl_spi.o
 obj-$(CONFIG_SPI_GPIO)			+= spi_gpio.o
 obj-$(CONFIG_SPI_IMX)			+= spi_imx.o
 obj-$(CONFIG_SPI_LM70_LLP)		+= spi_lm70llp.o
@@ -34,7 +36,6 @@ obj-$(CONFIG_SPI_PL022)			+= amba-pl022.o
 obj-$(CONFIG_SPI_MPC512x_PSC)		+= mpc512x_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx)		+= mpc52xx_spi.o
-obj-$(CONFIG_SPI_MPC8xxx)		+= spi_mpc8xxx.o
 obj-$(CONFIG_SPI_PPC4xx)		+= spi_ppc4xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx_hw.o
diff --git a/drivers/spi/spi_fsl_lib.c b/drivers/spi/spi_fsl_lib.c
new file mode 100644
index 0000000..23b1b2f
--- /dev/null
+++ b/drivers/spi/spi_fsl_lib.c
@@ -0,0 +1,237 @@
+/*
+ * Freescale SPI/eSPI controller driver library.
+ *
+ * Maintainer: Kumar Gala
+ *
+ * Copyright (C) 2006 Polycom, Inc.
+ *
+ * CPM SPI and QE buffer descriptors mode support:
+ * Copyright (c) 2009  MontaVista Software, Inc.
+ * Author: Anton Vorontsov <avorontsov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/fsl_devices.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/of_platform.h>
+#include <linux/of_spi.h>
+#include <sysdev/fsl_soc.h>
+
+#include "spi_fsl_lib.h"
+
+#define MPC8XXX_SPI_RX_BUF(type) 					  \
+void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
+{									  \
+	type *rx = mpc8xxx_spi->rx;					  \
+	*rx++ = (type)(data >> mpc8xxx_spi->rx_shift);			  \
+	mpc8xxx_spi->rx = rx;						  \
+}
+
+#define MPC8XXX_SPI_TX_BUF(type)				\
+u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
+{								\
+	u32 data;						\
+	const type *tx = mpc8xxx_spi->tx;			\
+	if (!tx)						\
+		return 0;					\
+	data = *tx++ << mpc8xxx_spi->tx_shift;			\
+	mpc8xxx_spi->tx = tx;					\
+	return data;						\
+}
+
+MPC8XXX_SPI_RX_BUF(u8)
+MPC8XXX_SPI_RX_BUF(u16)
+MPC8XXX_SPI_RX_BUF(u32)
+MPC8XXX_SPI_TX_BUF(u8)
+MPC8XXX_SPI_TX_BUF(u16)
+MPC8XXX_SPI_TX_BUF(u32)
+
+struct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata)
+{
+	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
+}
+
+void mpc8xxx_spi_work(struct work_struct *work)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
+						       work);
+
+	spin_lock_irq(&mpc8xxx_spi->lock);
+	while (!list_empty(&mpc8xxx_spi->queue)) {
+		struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
+						   struct spi_message, queue);
+
+		list_del_init(&m->queue);
+		spin_unlock_irq(&mpc8xxx_spi->lock);
+
+		if (mpc8xxx_spi->spi_do_one_msg)
+			mpc8xxx_spi->spi_do_one_msg(m);
+
+		spin_lock_irq(&mpc8xxx_spi->lock);
+	}
+	spin_unlock_irq(&mpc8xxx_spi->lock);
+}
+
+int mpc8xxx_spi_transfer(struct spi_device *spi,
+				struct spi_message *m)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+	unsigned long flags;
+
+	m->actual_length = 0;
+	m->status = -EINPROGRESS;
+
+	spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
+	list_add_tail(&m->queue, &mpc8xxx_spi->queue);
+	queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
+	spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
+
+	return 0;
+}
+
+
+void mpc8xxx_spi_cleanup(struct spi_device *spi)
+{
+	kfree(spi->controller_state);
+}
+
+const char *mpc8xxx_spi_strmode(unsigned int flags)
+{
+	if (flags & SPI_QE_CPU_MODE) {
+		return "QE CPU";
+	} else if (flags & SPI_CPM_MODE) {
+		if (flags & SPI_QE)
+			return "QE";
+		else if (flags & SPI_CPM2)
+			return "CPM2";
+		else
+			return "CPM1";
+	}
+	return "CPU";
+}
+
+int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
+			unsigned int irq)
+{
+	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct spi_master *master;
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	int ret = 0;
+
+	master = dev_get_drvdata(dev);
+
+	/* the spi->mode bits understood by this driver: */
+	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
+			| SPI_LSB_FIRST | SPI_LOOP;
+
+	master->transfer = mpc8xxx_spi_transfer;
+	master->cleanup = mpc8xxx_spi_cleanup;
+
+	mpc8xxx_spi = spi_master_get_devdata(master);
+	mpc8xxx_spi->dev = dev;
+	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
+	mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
+	mpc8xxx_spi->flags = pdata->flags;
+	mpc8xxx_spi->spibrg = pdata->sysclk;
+	mpc8xxx_spi->irq = irq;
+
+	mpc8xxx_spi->rx_shift = 0;
+	mpc8xxx_spi->tx_shift = 0;
+
+	init_completion(&mpc8xxx_spi->done);
+
+	master->bus_num = pdata->bus_num;
+	master->num_chipselect = pdata->max_chipselect;
+
+	spin_lock_init(&mpc8xxx_spi->lock);
+	init_completion(&mpc8xxx_spi->done);
+	INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
+	INIT_LIST_HEAD(&mpc8xxx_spi->queue);
+
+	mpc8xxx_spi->workqueue = create_singlethread_workqueue(
+		dev_name(master->dev.parent));
+	if (mpc8xxx_spi->workqueue == NULL) {
+		ret = -EBUSY;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+}
+
+int __devexit mpc8xxx_spi_remove(struct device *dev)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	struct spi_master *master;
+
+	master = dev_get_drvdata(dev);
+	mpc8xxx_spi = spi_master_get_devdata(master);
+
+	flush_workqueue(mpc8xxx_spi->workqueue);
+	destroy_workqueue(mpc8xxx_spi->workqueue);
+	spi_unregister_master(master);
+
+	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
+
+	if (mpc8xxx_spi->spi_remove)
+		mpc8xxx_spi->spi_remove(mpc8xxx_spi);
+
+	return 0;
+}
+
+int __devinit of_mpc8xxx_spi_probe(struct 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;
+	const void *prop;
+	int ret = -ENOMEM;
+
+	pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+	if (!pinfo)
+		return -ENOMEM;
+
+	pdata = &pinfo->pdata;
+	dev->platform_data = pdata;
+
+	/* Allocate bus num dynamically. */
+	pdata->bus_num = -1;
+
+	/* SPI controller is either clocked from QE or SoC clock. */
+	pdata->sysclk = get_brgfreq();
+	if (pdata->sysclk == -1) {
+		pdata->sysclk = fsl_get_sys_freq();
+		if (pdata->sysclk == -1) {
+			ret = -ENODEV;
+			goto err;
+		}
+	}
+
+	prop = of_get_property(np, "mode", NULL);
+	if (prop && !strcmp(prop, "cpu-qe"))
+		pdata->flags = SPI_QE_CPU_MODE;
+	else if (prop && !strcmp(prop, "qe"))
+		pdata->flags = SPI_CPM_MODE | SPI_QE;
+	else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
+		pdata->flags = SPI_CPM_MODE | SPI_CPM2;
+	else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
+		pdata->flags = SPI_CPM_MODE | SPI_CPM1;
+
+	return 0;
+
+err:
+	kfree(pinfo);
+	return ret;
+}
diff --git a/drivers/spi/spi_fsl_lib.h b/drivers/spi/spi_fsl_lib.h
new file mode 100644
index 0000000..774e1c8
--- /dev/null
+++ b/drivers/spi/spi_fsl_lib.h
@@ -0,0 +1,119 @@
+/*
+ * Freescale SPI/eSPI controller driver library.
+ *
+ * Maintainer: Kumar Gala
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2006 Polycom, Inc.
+ *
+ * CPM SPI and QE buffer descriptors mode support:
+ * Copyright (c) 2009  MontaVista Software, Inc.
+ * Author: Anton Vorontsov <avorontsov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef __SPI_FSL_LIB_H__
+#define __SPI_FSL_LIB_H__
+
+/* SPI/eSPI Controller driver's private data. */
+struct mpc8xxx_spi {
+	struct device *dev;
+	struct fsl_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);
+
+	unsigned int count;
+	unsigned int irq;
+
+	unsigned nsecs;		/* (clock cycle time)/2 */
+
+	u32 spibrg;		/* SPIBRG input clock */
+	u32 rx_shift;		/* RX data reg shift when in qe mode */
+	u32 tx_shift;		/* TX data reg shift when in qe mode */
+
+	unsigned int flags;
+
+	struct workqueue_struct *workqueue;
+	struct work_struct work;
+
+	struct list_head queue;
+	spinlock_t lock;
+
+	struct completion done;
+};
+
+struct spi_mpc8xxx_cs {
+	/* functions to deal with different sized buffers */
+	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
+	u32 (*get_tx) (struct mpc8xxx_spi *);
+	u32 rx_shift;		/* RX data reg shift when in qe mode */
+	u32 tx_shift;		/* TX data reg shift when in qe mode */
+	u32 hw_mode;		/* Holds HW mode register settings */
+};
+
+static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
+{
+	out_be32(reg, val);
+}
+
+static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
+{
+	return in_be32(reg);
+}
+
+struct mpc8xxx_spi_probe_info {
+	struct fsl_spi_platform_data pdata;
+	int *gpios;
+	bool *alow_flags;
+};
+
+extern u32 mpc8xxx_spi_tx_buf_u8(struct mpc8xxx_spi *mpc8xxx_spi);
+extern u32 mpc8xxx_spi_tx_buf_u16(struct mpc8xxx_spi *mpc8xxx_spi);
+extern u32 mpc8xxx_spi_tx_buf_u32(struct mpc8xxx_spi *mpc8xxx_spi);
+extern void mpc8xxx_spi_rx_buf_u8(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
+extern void mpc8xxx_spi_rx_buf_u16(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
+extern void mpc8xxx_spi_rx_buf_u32(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
+
+extern struct mpc8xxx_spi_probe_info *to_of_pinfo(
+		struct fsl_spi_platform_data *pdata);
+extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi,
+		struct spi_transfer *t, unsigned int len);
+extern int mpc8xxx_spi_transfer(struct spi_device *spi, struct spi_message *m);
+extern void mpc8xxx_spi_cleanup(struct spi_device *spi);
+extern const char *mpc8xxx_spi_strmode(unsigned int flags);
+extern int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
+		unsigned int irq);
+extern int mpc8xxx_spi_remove(struct device *dev);
+extern int of_mpc8xxx_spi_probe(struct of_device *ofdev,
+		const struct of_device_id *ofid);
+
+#endif /* __SPI_FSL_LIB_H__ */
diff --git a/drivers/spi/spi_fsl_spi.c b/drivers/spi/spi_fsl_spi.c
new file mode 100644
index 0000000..06b0590
--- /dev/null
+++ b/drivers/spi/spi_fsl_spi.c
@@ -0,0 +1,1173 @@
+/*
+ * Freescale 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-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+ *
+ * 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 <linux/interrupt.h>
+
+#include <sysdev/fsl_soc.h>
+#include <asm/cpm.h>
+#include <asm/qe.h>
+
+#include "spi_fsl_lib.h"
+
+/* SPI Controller registers */
+struct fsl_spi_reg {
+	u8 res1[0x20];
+	__be32 mode;
+	__be32 event;
+	__be32 mask;
+	__be32 command;
+	__be32 transmit;
+	__be32 receive;
+};
+
+/* 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 = 0;
+	u8 pm;
+	u32 hz = 0;
+	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
+
+	mpc8xxx_spi = spi_master_get_devdata(spi->master);
+
+	if (t) {
+		bits_per_word = t->bits_per_word;
+		hz = t->speed_hz;
+	}
+
+	/* spi_transfer level calls that work per-word */
+	if (!bits_per_word)
+		bits_per_word = spi->bits_per_word;
+
+	/* Make sure its a bit width we support [4..16, 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;
+}
+
+int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t,
+		unsigned int len)
+{
+	u32 word;
+
+	mspi->count = len;
+
+	/* enable rx ints */
+	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIM_NE);
+
+	/* transmit word */
+	word = mspi->get_tx(mspi);
+	mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
+
+	return 0;
+}
+
+static int 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 = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len);
+	if (ret)
+		return ret;
+
+	wait_for_completion(&mpc8xxx_spi->done);
+
+	/* disable rx ints */
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
+
+	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);
+	}
+}
+
+irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
+{
+	struct mpc8xxx_spi *mspi = context_data;
+	irqreturn_t ret = IRQ_NONE;
+	u32 events;
+
+	/* Get interrupt events(tx/rx) */
+	events = mpc8xxx_spi_read_reg(&mspi->base->event);
+	if (events)
+		ret = IRQ_HANDLED;
+
+	dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);
+
+	if (mspi->flags & SPI_CPM_MODE)
+		fsl_spi_cpm_irq(mspi, events);
+	else
+		fsl_spi_cpu_irq(mspi, events);
+
+	return ret;
+}
+
+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)
+{
+	iounmap(mspi->base);
+	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->base = ioremap(mem->start, resource_size(mem));
+	if (mpc8xxx_spi->base == NULL) {
+		ret = -ENOMEM;
+		goto err_probe;
+	}
+
+	/* Register for SPI Interrupt */
+	ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq,
+			  0, "fsl_spi", mpc8xxx_spi);
+
+	if (ret != 0)
+		goto err_free_irq;
+
+	/* CPM init */
+	ret = fsl_spi_cpm_init(mpc8xxx_spi);
+	if (ret)
+		goto err_cpm_init;
+
+	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_cpm_init:
+	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
+err_free_irq:
+	iounmap(mpc8xxx_spi->base);
+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);
+}
+module_init(fsl_spi_init);
+
+static void __exit fsl_spi_exit(void)
+{
+	of_unregister_platform_driver(&of_fsl_spi_driver);
+	legacy_driver_unregister();
+}
+module_exit(fsl_spi_exit);
+
+MODULE_AUTHOR("Kumar Gala");
+MODULE_DESCRIPTION("Simple Freescale SPI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c
deleted file mode 100644
index 97ab0a8..0000000
--- a/drivers/spi/spi_mpc8xxx.c
+++ /dev/null
@@ -1,1421 +0,0 @@
-/*
- * MPC8xxx SPI controller driver.
- *
- * Maintainer: Kumar Gala
- *
- * Copyright (C) 2006 Polycom, Inc.
- *
- * CPM SPI and QE buffer descriptors mode support:
- * Copyright (c) 2009  MontaVista Software, Inc.
- * Author: Anton Vorontsov <avorontsov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
- *
- * 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 */
-
-	unsigned int flags;
-
-	struct workqueue_struct *workqueue;
-	struct work_struct work;
-
-	struct list_head queue;
-	spinlock_t lock;
-
-	struct completion done;
-};
-
-static void *mpc8xxx_dummy_rx;
-static DEFINE_MUTEX(mpc8xxx_dummy_rx_lock);
-static int mpc8xxx_dummy_rx_refcnt;
-
-struct spi_mpc8xxx_cs {
-	/* functions to deal with different sized buffers */
-	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
-	u32 (*get_tx) (struct mpc8xxx_spi *);
-	u32 rx_shift;		/* RX data reg shift when in qe mode */
-	u32 tx_shift;		/* TX data reg shift when in qe mode */
-	u32 hw_mode;		/* Holds HW mode register settings */
-};
-
-static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
-{
-	out_be32(reg, val);
-}
-
-static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
-{
-	return in_be32(reg);
-}
-
-#define MPC83XX_SPI_RX_BUF(type) 					  \
-static									  \
-void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
-{									  \
-	type *rx = mpc8xxx_spi->rx;					  \
-	*rx++ = (type)(data >> mpc8xxx_spi->rx_shift);			  \
-	mpc8xxx_spi->rx = rx;						  \
-}
-
-#define MPC83XX_SPI_TX_BUF(type)				\
-static								\
-u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
-{								\
-	u32 data;						\
-	const type *tx = mpc8xxx_spi->tx;			\
-	if (!tx)						\
-		return 0;					\
-	data = *tx++ << mpc8xxx_spi->tx_shift;			\
-	mpc8xxx_spi->tx = tx;					\
-	return data;						\
-}
-
-MPC83XX_SPI_RX_BUF(u8)
-MPC83XX_SPI_RX_BUF(u16)
-MPC83XX_SPI_RX_BUF(u32)
-MPC83XX_SPI_TX_BUF(u8)
-MPC83XX_SPI_TX_BUF(u16)
-MPC83XX_SPI_TX_BUF(u32)
-
-static void mpc8xxx_spi_change_mode(struct spi_device *spi)
-{
-	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
-	struct spi_mpc8xxx_cs *cs = spi->controller_state;
-	__be32 __iomem *mode = &mspi->base->mode;
-	unsigned long flags;
-
-	if (cs->hw_mode == mpc8xxx_spi_read_reg(mode))
-		return;
-
-	/* Turn off IRQs locally to minimize time that SPI is disabled. */
-	local_irq_save(flags);
-
-	/* Turn off SPI unit prior changing mode */
-	mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE);
-
-	/* When in CPM mode, we need to reinit tx and rx. */
-	if (mspi->flags & SPI_CPM_MODE) {
-		if (mspi->flags & SPI_QE) {
-			qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock,
-				     QE_CR_PROTOCOL_UNSPECIFIED, 0);
-		} else {
-			cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
-			if (mspi->flags & SPI_CPM1) {
-				out_be16(&mspi->pram->rbptr,
-					 in_be16(&mspi->pram->rbase));
-				out_be16(&mspi->pram->tbptr,
-					 in_be16(&mspi->pram->tbase));
-			}
-		}
-	}
-	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
-	local_irq_restore(flags);
-}
-
-static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
-	struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
-	bool pol = spi->mode & SPI_CS_HIGH;
-	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
-
-	if (value == BITBANG_CS_INACTIVE) {
-		if (pdata->cs_control)
-			pdata->cs_control(spi, !pol);
-	}
-
-	if (value == BITBANG_CS_ACTIVE) {
-		mpc8xxx_spi->rx_shift = cs->rx_shift;
-		mpc8xxx_spi->tx_shift = cs->tx_shift;
-		mpc8xxx_spi->get_rx = cs->get_rx;
-		mpc8xxx_spi->get_tx = cs->get_tx;
-
-		mpc8xxx_spi_change_mode(spi);
-
-		if (pdata->cs_control)
-			pdata->cs_control(spi, pol);
-	}
-}
-
-static int
-mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
-			   struct spi_device *spi,
-			   struct mpc8xxx_spi *mpc8xxx_spi,
-			   int bits_per_word)
-{
-	cs->rx_shift = 0;
-	cs->tx_shift = 0;
-	if (bits_per_word <= 8) {
-		cs->get_rx = mpc8xxx_spi_rx_buf_u8;
-		cs->get_tx = mpc8xxx_spi_tx_buf_u8;
-		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
-			cs->rx_shift = 16;
-			cs->tx_shift = 24;
-		}
-	} else if (bits_per_word <= 16) {
-		cs->get_rx = mpc8xxx_spi_rx_buf_u16;
-		cs->get_tx = mpc8xxx_spi_tx_buf_u16;
-		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
-			cs->rx_shift = 16;
-			cs->tx_shift = 16;
-		}
-	} else if (bits_per_word <= 32) {
-		cs->get_rx = mpc8xxx_spi_rx_buf_u32;
-		cs->get_tx = mpc8xxx_spi_tx_buf_u32;
-	} else
-		return -EINVAL;
-
-	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE &&
-	    spi->mode & SPI_LSB_FIRST) {
-		cs->tx_shift = 0;
-		if (bits_per_word <= 8)
-			cs->rx_shift = 8;
-		else
-			cs->rx_shift = 0;
-	}
-	mpc8xxx_spi->rx_shift = cs->rx_shift;
-	mpc8xxx_spi->tx_shift = cs->tx_shift;
-	mpc8xxx_spi->get_rx = cs->get_rx;
-	mpc8xxx_spi->get_tx = cs->get_tx;
-
-	return bits_per_word;
-}
-
-static int
-mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
-			  struct spi_device *spi,
-			  int bits_per_word)
-{
-	/* QE uses Little Endian for words > 8
-	 * so transform all words > 8 into 8 bits
-	 * Unfortnatly that doesn't work for LSB so
-	 * reject these for now */
-	/* Note: 32 bits word, LSB works iff
-	 * tfcr/rfcr is set to CPMFCR_GBL */
-	if (spi->mode & SPI_LSB_FIRST &&
-	    bits_per_word > 8)
-		return -EINVAL;
-	if (bits_per_word > 8)
-		return 8; /* pretend its 8 bits */
-	return bits_per_word;
-}
-
-static
-int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi;
-	int bits_per_word;
-	u8 pm;
-	u32 hz;
-	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
-
-	mpc8xxx_spi = spi_master_get_devdata(spi->master);
-
-	if (t) {
-		bits_per_word = t->bits_per_word;
-		hz = t->speed_hz;
-	} else {
-		bits_per_word = 0;
-		hz = 0;
-	}
-
-	/* spi_transfer level calls that work per-word */
-	if (!bits_per_word)
-		bits_per_word = spi->bits_per_word;
-
-	/* Make sure its a bit width we support [4..16, 32] */
-	if ((bits_per_word < 4)
-	    || ((bits_per_word > 16) && (bits_per_word != 32)))
-		return -EINVAL;
-
-	if (!hz)
-		hz = spi->max_speed_hz;
-
-	if (!(mpc8xxx_spi->flags & SPI_CPM_MODE))
-		bits_per_word = mspi_apply_cpu_mode_quirks(cs, spi,
-							   mpc8xxx_spi,
-							   bits_per_word);
-	else if (mpc8xxx_spi->flags & SPI_QE)
-		bits_per_word = mspi_apply_qe_mode_quirks(cs, spi,
-							  bits_per_word);
-
-	if (bits_per_word < 0)
-		return bits_per_word;
-
-	if (bits_per_word == 32)
-		bits_per_word = 0;
-	else
-		bits_per_word = bits_per_word - 1;
-
-	/* mask out bits we are going to set */
-	cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16
-				  | SPMODE_PM(0xF));
-
-	cs->hw_mode |= SPMODE_LEN(bits_per_word);
-
-	if ((mpc8xxx_spi->spibrg / hz) > 64) {
-		cs->hw_mode |= SPMODE_DIV16;
-		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
-
-		WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
-			  "Will use %d Hz instead.\n", dev_name(&spi->dev),
-			  hz, mpc8xxx_spi->spibrg / 1024);
-		if (pm > 16)
-			pm = 16;
-	} else
-		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
-	if (pm)
-		pm--;
-
-	cs->hw_mode |= SPMODE_PM(pm);
-
-	mpc8xxx_spi_change_mode(spi);
-	return 0;
-}
-
-static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
-{
-	struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd;
-	struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
-	unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
-	unsigned int xfer_ofs;
-
-	xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
-
-	out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
-	out_be16(&rx_bd->cbd_datlen, 0);
-	out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
-
-	out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
-	out_be16(&tx_bd->cbd_datlen, xfer_len);
-	out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
-				 BD_SC_LAST);
-
-	/* start transfer */
-	mpc8xxx_spi_write_reg(&mspi->base->command, SPCOM_STR);
-}
-
-static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
-				struct spi_transfer *t, bool is_dma_mapped)
-{
-	struct device *dev = mspi->dev;
-
-	if (is_dma_mapped) {
-		mspi->map_tx_dma = 0;
-		mspi->map_rx_dma = 0;
-	} else {
-		mspi->map_tx_dma = 1;
-		mspi->map_rx_dma = 1;
-	}
-
-	if (!t->tx_buf) {
-		mspi->tx_dma = mspi->dma_dummy_tx;
-		mspi->map_tx_dma = 0;
-	}
-
-	if (!t->rx_buf) {
-		mspi->rx_dma = mspi->dma_dummy_rx;
-		mspi->map_rx_dma = 0;
-	}
-
-	if (mspi->map_tx_dma) {
-		void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */
-
-		mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len,
-					      DMA_TO_DEVICE);
-		if (dma_mapping_error(dev, mspi->tx_dma)) {
-			dev_err(dev, "unable to map tx dma\n");
-			return -ENOMEM;
-		}
-	} else if (t->tx_buf) {
-		mspi->tx_dma = t->tx_dma;
-	}
-
-	if (mspi->map_rx_dma) {
-		mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len,
-					      DMA_FROM_DEVICE);
-		if (dma_mapping_error(dev, mspi->rx_dma)) {
-			dev_err(dev, "unable to map rx dma\n");
-			goto err_rx_dma;
-		}
-	} else if (t->rx_buf) {
-		mspi->rx_dma = t->rx_dma;
-	}
-
-	/* enable rx ints */
-	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIE_RXB);
-
-	mspi->xfer_in_progress = t;
-	mspi->count = t->len;
-
-	/* start CPM transfers */
-	mpc8xxx_spi_cpm_bufs_start(mspi);
-
-	return 0;
-
-err_rx_dma:
-	if (mspi->map_tx_dma)
-		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
-	return -ENOMEM;
-}
-
-static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
-{
-	struct device *dev = mspi->dev;
-	struct spi_transfer *t = mspi->xfer_in_progress;
-
-	if (mspi->map_tx_dma)
-		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
-	if (mspi->map_rx_dma)
-		dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
-	mspi->xfer_in_progress = NULL;
-}
-
-static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
-				struct spi_transfer *t, unsigned int len)
-{
-	u32 word;
-
-	mspi->count = len;
-
-	/* enable rx ints */
-	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIM_NE);
-
-	/* transmit word */
-	word = mspi->get_tx(mspi);
-	mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
-
-	return 0;
-}
-
-static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
-			    bool is_dma_mapped)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
-	unsigned int len = t->len;
-	u8 bits_per_word;
-	int ret;
-
-	bits_per_word = spi->bits_per_word;
-	if (t->bits_per_word)
-		bits_per_word = t->bits_per_word;
-
-	if (bits_per_word > 8) {
-		/* invalid length? */
-		if (len & 1)
-			return -EINVAL;
-		len /= 2;
-	}
-	if (bits_per_word > 16) {
-		/* invalid length? */
-		if (len & 1)
-			return -EINVAL;
-		len /= 2;
-	}
-
-	mpc8xxx_spi->tx = t->tx_buf;
-	mpc8xxx_spi->rx = t->rx_buf;
-
-	INIT_COMPLETION(mpc8xxx_spi->done);
-
-	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
-		ret = mpc8xxx_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
-	else
-		ret = mpc8xxx_spi_cpu_bufs(mpc8xxx_spi, t, len);
-	if (ret)
-		return ret;
-
-	wait_for_completion(&mpc8xxx_spi->done);
-
-	/* disable rx ints */
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
-
-	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
-		mpc8xxx_spi_cpm_bufs_complete(mpc8xxx_spi);
-
-	return mpc8xxx_spi->count;
-}
-
-static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
-{
-	struct spi_device *spi = m->spi;
-	struct spi_transfer *t;
-	unsigned int cs_change;
-	const int nsecs = 50;
-	int status;
-
-	cs_change = 1;
-	status = 0;
-	list_for_each_entry(t, &m->transfers, transfer_list) {
-		if (t->bits_per_word || t->speed_hz) {
-			/* Don't allow changes if CS is active */
-			status = -EINVAL;
-
-			if (cs_change)
-				status = mpc8xxx_spi_setup_transfer(spi, t);
-			if (status < 0)
-				break;
-		}
-
-		if (cs_change) {
-			mpc8xxx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
-			ndelay(nsecs);
-		}
-		cs_change = t->cs_change;
-		if (t->len)
-			status = mpc8xxx_spi_bufs(spi, t, m->is_dma_mapped);
-		if (status) {
-			status = -EMSGSIZE;
-			break;
-		}
-		m->actual_length += t->len;
-
-		if (t->delay_usecs)
-			udelay(t->delay_usecs);
-
-		if (cs_change) {
-			ndelay(nsecs);
-			mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
-			ndelay(nsecs);
-		}
-	}
-
-	m->status = status;
-	m->complete(m->context);
-
-	if (status || !cs_change) {
-		ndelay(nsecs);
-		mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
-	}
-
-	mpc8xxx_spi_setup_transfer(spi, NULL);
-}
-
-static void mpc8xxx_spi_work(struct work_struct *work)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
-						       work);
-
-	spin_lock_irq(&mpc8xxx_spi->lock);
-	while (!list_empty(&mpc8xxx_spi->queue)) {
-		struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
-						   struct spi_message, queue);
-
-		list_del_init(&m->queue);
-		spin_unlock_irq(&mpc8xxx_spi->lock);
-
-		mpc8xxx_spi_do_one_msg(m);
-
-		spin_lock_irq(&mpc8xxx_spi->lock);
-	}
-	spin_unlock_irq(&mpc8xxx_spi->lock);
-}
-
-static int mpc8xxx_spi_setup(struct spi_device *spi)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi;
-	int retval;
-	u32 hw_mode;
-	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
-
-	if (!spi->max_speed_hz)
-		return -EINVAL;
-
-	if (!cs) {
-		cs = kzalloc(sizeof *cs, GFP_KERNEL);
-		if (!cs)
-			return -ENOMEM;
-		spi->controller_state = cs;
-	}
-	mpc8xxx_spi = spi_master_get_devdata(spi->master);
-
-	hw_mode = cs->hw_mode; /* Save original settings */
-	cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
-	/* mask out bits we are going to set */
-	cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
-			 | SPMODE_REV | SPMODE_LOOP);
-
-	if (spi->mode & SPI_CPHA)
-		cs->hw_mode |= SPMODE_CP_BEGIN_EDGECLK;
-	if (spi->mode & SPI_CPOL)
-		cs->hw_mode |= SPMODE_CI_INACTIVEHIGH;
-	if (!(spi->mode & SPI_LSB_FIRST))
-		cs->hw_mode |= SPMODE_REV;
-	if (spi->mode & SPI_LOOP)
-		cs->hw_mode |= SPMODE_LOOP;
-
-	retval = mpc8xxx_spi_setup_transfer(spi, NULL);
-	if (retval < 0) {
-		cs->hw_mode = hw_mode; /* Restore settings */
-		return retval;
-	}
-	return 0;
-}
-
-static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
-{
-	u16 len;
-
-	dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
-		in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
-
-	len = in_be16(&mspi->rx_bd->cbd_datlen);
-	if (len > mspi->count) {
-		WARN_ON(1);
-		len = mspi->count;
-	}
-
-	/* Clear the events */
-	mpc8xxx_spi_write_reg(&mspi->base->event, events);
-
-	mspi->count -= len;
-	if (mspi->count)
-		mpc8xxx_spi_cpm_bufs_start(mspi);
-	else
-		complete(&mspi->done);
-}
-
-static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
-{
-	/* We need handle RX first */
-	if (events & SPIE_NE) {
-		u32 rx_data = mpc8xxx_spi_read_reg(&mspi->base->receive);
-
-		if (mspi->rx)
-			mspi->get_rx(rx_data, mspi);
-	}
-
-	if ((events & SPIE_NF) == 0)
-		/* spin until TX is done */
-		while (((events =
-			mpc8xxx_spi_read_reg(&mspi->base->event)) &
-						SPIE_NF) == 0)
-			cpu_relax();
-
-	/* Clear the events */
-	mpc8xxx_spi_write_reg(&mspi->base->event, events);
-
-	mspi->count -= 1;
-	if (mspi->count) {
-		u32 word = mspi->get_tx(mspi);
-
-		mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
-	} else {
-		complete(&mspi->done);
-	}
-}
-
-static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
-{
-	struct mpc8xxx_spi *mspi = context_data;
-	irqreturn_t ret = IRQ_NONE;
-	u32 events;
-
-	/* Get interrupt events(tx/rx) */
-	events = mpc8xxx_spi_read_reg(&mspi->base->event);
-	if (events)
-		ret = IRQ_HANDLED;
-
-	dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);
-
-	if (mspi->flags & SPI_CPM_MODE)
-		mpc8xxx_spi_cpm_irq(mspi, events);
-	else
-		mpc8xxx_spi_cpu_irq(mspi, events);
-
-	return ret;
-}
-
-static int mpc8xxx_spi_transfer(struct spi_device *spi,
-				struct spi_message *m)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
-	unsigned long flags;
-
-	m->actual_length = 0;
-	m->status = -EINPROGRESS;
-
-	spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
-	list_add_tail(&m->queue, &mpc8xxx_spi->queue);
-	queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
-	spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
-
-	return 0;
-}
-
-
-static void mpc8xxx_spi_cleanup(struct spi_device *spi)
-{
-	kfree(spi->controller_state);
-}
-
-static void *mpc8xxx_spi_alloc_dummy_rx(void)
-{
-	mutex_lock(&mpc8xxx_dummy_rx_lock);
-
-	if (!mpc8xxx_dummy_rx)
-		mpc8xxx_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
-	if (mpc8xxx_dummy_rx)
-		mpc8xxx_dummy_rx_refcnt++;
-
-	mutex_unlock(&mpc8xxx_dummy_rx_lock);
-
-	return mpc8xxx_dummy_rx;
-}
-
-static void mpc8xxx_spi_free_dummy_rx(void)
-{
-	mutex_lock(&mpc8xxx_dummy_rx_lock);
-
-	switch (mpc8xxx_dummy_rx_refcnt) {
-	case 0:
-		WARN_ON(1);
-		break;
-	case 1:
-		kfree(mpc8xxx_dummy_rx);
-		mpc8xxx_dummy_rx = NULL;
-		/* fall through */
-	default:
-		mpc8xxx_dummy_rx_refcnt--;
-		break;
-	}
-
-	mutex_unlock(&mpc8xxx_dummy_rx_lock);
-}
-
-static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
-{
-	struct device *dev = mspi->dev;
-	struct device_node *np = dev->of_node;
-	const u32 *iprop;
-	int size;
-	unsigned long spi_base_ofs;
-	unsigned long pram_ofs = -ENOMEM;
-
-	/* Can't use of_address_to_resource(), QE muram isn't at 0. */
-	iprop = of_get_property(np, "reg", &size);
-
-	/* QE with a fixed pram location? */
-	if (mspi->flags & SPI_QE && iprop && size == sizeof(*iprop) * 4)
-		return cpm_muram_alloc_fixed(iprop[2], SPI_PRAM_SIZE);
-
-	/* QE but with a dynamic pram location? */
-	if (mspi->flags & SPI_QE) {
-		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
-		qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, mspi->subblock,
-				QE_CR_PROTOCOL_UNSPECIFIED, pram_ofs);
-		return pram_ofs;
-	}
-
-	/* CPM1 and CPM2 pram must be at a fixed addr. */
-	if (!iprop || size != sizeof(*iprop) * 4)
-		return -ENOMEM;
-
-	spi_base_ofs = cpm_muram_alloc_fixed(iprop[2], 2);
-	if (IS_ERR_VALUE(spi_base_ofs))
-		return -ENOMEM;
-
-	if (mspi->flags & SPI_CPM2) {
-		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
-		if (!IS_ERR_VALUE(pram_ofs)) {
-			u16 __iomem *spi_base = cpm_muram_addr(spi_base_ofs);
-
-			out_be16(spi_base, pram_ofs);
-		}
-	} else {
-		struct spi_pram __iomem *pram = cpm_muram_addr(spi_base_ofs);
-		u16 rpbase = in_be16(&pram->rpbase);
-
-		/* Microcode relocation patch applied? */
-		if (rpbase)
-			pram_ofs = rpbase;
-		else
-			return spi_base_ofs;
-	}
-
-	cpm_muram_free(spi_base_ofs);
-	return pram_ofs;
-}
-
-static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
-{
-	struct device *dev = mspi->dev;
-	struct device_node *np = dev->of_node;
-	const u32 *iprop;
-	int size;
-	unsigned long pram_ofs;
-	unsigned long bds_ofs;
-
-	if (!(mspi->flags & SPI_CPM_MODE))
-		return 0;
-
-	if (!mpc8xxx_spi_alloc_dummy_rx())
-		return -ENOMEM;
-
-	if (mspi->flags & SPI_QE) {
-		iprop = of_get_property(np, "cell-index", &size);
-		if (iprop && size == sizeof(*iprop))
-			mspi->subblock = *iprop;
-
-		switch (mspi->subblock) {
-		default:
-			dev_warn(dev, "cell-index unspecified, assuming SPI1");
-			/* fall through */
-		case 0:
-			mspi->subblock = QE_CR_SUBBLOCK_SPI1;
-			break;
-		case 1:
-			mspi->subblock = QE_CR_SUBBLOCK_SPI2;
-			break;
-		}
-	}
-
-	pram_ofs = mpc8xxx_spi_cpm_get_pram(mspi);
-	if (IS_ERR_VALUE(pram_ofs)) {
-		dev_err(dev, "can't allocate spi parameter ram\n");
-		goto err_pram;
-	}
-
-	bds_ofs = cpm_muram_alloc(sizeof(*mspi->tx_bd) +
-				  sizeof(*mspi->rx_bd), 8);
-	if (IS_ERR_VALUE(bds_ofs)) {
-		dev_err(dev, "can't allocate bds\n");
-		goto err_bds;
-	}
-
-	mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE,
-					    DMA_TO_DEVICE);
-	if (dma_mapping_error(dev, mspi->dma_dummy_tx)) {
-		dev_err(dev, "unable to map dummy tx buffer\n");
-		goto err_dummy_tx;
-	}
-
-	mspi->dma_dummy_rx = dma_map_single(dev, mpc8xxx_dummy_rx, SPI_MRBLR,
-					    DMA_FROM_DEVICE);
-	if (dma_mapping_error(dev, mspi->dma_dummy_rx)) {
-		dev_err(dev, "unable to map dummy rx buffer\n");
-		goto err_dummy_rx;
-	}
-
-	mspi->pram = cpm_muram_addr(pram_ofs);
-
-	mspi->tx_bd = cpm_muram_addr(bds_ofs);
-	mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
-
-	/* Initialize parameter ram. */
-	out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd));
-	out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd));
-	out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL);
-	out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL);
-	out_be16(&mspi->pram->mrblr, SPI_MRBLR);
-	out_be32(&mspi->pram->rstate, 0);
-	out_be32(&mspi->pram->rdp, 0);
-	out_be16(&mspi->pram->rbptr, 0);
-	out_be16(&mspi->pram->rbc, 0);
-	out_be32(&mspi->pram->rxtmp, 0);
-	out_be32(&mspi->pram->tstate, 0);
-	out_be32(&mspi->pram->tdp, 0);
-	out_be16(&mspi->pram->tbptr, 0);
-	out_be16(&mspi->pram->tbc, 0);
-	out_be32(&mspi->pram->txtmp, 0);
-
-	return 0;
-
-err_dummy_rx:
-	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
-err_dummy_tx:
-	cpm_muram_free(bds_ofs);
-err_bds:
-	cpm_muram_free(pram_ofs);
-err_pram:
-	mpc8xxx_spi_free_dummy_rx();
-	return -ENOMEM;
-}
-
-static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi)
-{
-	struct device *dev = mspi->dev;
-
-	dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
-	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
-	cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
-	cpm_muram_free(cpm_muram_offset(mspi->pram));
-	mpc8xxx_spi_free_dummy_rx();
-}
-
-static const char *mpc8xxx_spi_strmode(unsigned int flags)
-{
-	if (flags & SPI_QE_CPU_MODE) {
-		return "QE CPU";
-	} else if (flags & SPI_CPM_MODE) {
-		if (flags & SPI_QE)
-			return "QE";
-		else if (flags & SPI_CPM2)
-			return "CPM2";
-		else
-			return "CPM1";
-	}
-	return "CPU";
-}
-
-static struct spi_master * __devinit
-mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
-{
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
-	struct spi_master *master;
-	struct mpc8xxx_spi *mpc8xxx_spi;
-	u32 regval;
-	int ret = 0;
-
-	master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
-	if (master == NULL) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	dev_set_drvdata(dev, master);
-
-	/* the spi->mode bits understood by this driver: */
-	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
-			| SPI_LSB_FIRST | SPI_LOOP;
-
-	master->setup = mpc8xxx_spi_setup;
-	master->transfer = mpc8xxx_spi_transfer;
-	master->cleanup = mpc8xxx_spi_cleanup;
-
-	mpc8xxx_spi = spi_master_get_devdata(master);
-	mpc8xxx_spi->dev = dev;
-	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
-	mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
-	mpc8xxx_spi->flags = pdata->flags;
-	mpc8xxx_spi->spibrg = pdata->sysclk;
-
-	ret = mpc8xxx_spi_cpm_init(mpc8xxx_spi);
-	if (ret)
-		goto err_cpm_init;
-
-	mpc8xxx_spi->rx_shift = 0;
-	mpc8xxx_spi->tx_shift = 0;
-	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
-		mpc8xxx_spi->rx_shift = 16;
-		mpc8xxx_spi->tx_shift = 24;
-	}
-
-	init_completion(&mpc8xxx_spi->done);
-
-	mpc8xxx_spi->base = ioremap(mem->start, resource_size(mem));
-	if (mpc8xxx_spi->base == NULL) {
-		ret = -ENOMEM;
-		goto err_ioremap;
-	}
-
-	mpc8xxx_spi->irq = irq;
-
-	/* Register for SPI Interrupt */
-	ret = request_irq(mpc8xxx_spi->irq, mpc8xxx_spi_irq,
-			  0, "mpc8xxx_spi", mpc8xxx_spi);
-
-	if (ret != 0)
-		goto unmap_io;
-
-	master->bus_num = pdata->bus_num;
-	master->num_chipselect = pdata->max_chipselect;
-
-	/* SPI controller initializations */
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0);
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0);
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff);
-
-	/* Enable SPI interface */
-	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
-	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
-		regval |= SPMODE_OP;
-
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
-	spin_lock_init(&mpc8xxx_spi->lock);
-	init_completion(&mpc8xxx_spi->done);
-	INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
-	INIT_LIST_HEAD(&mpc8xxx_spi->queue);
-
-	mpc8xxx_spi->workqueue = create_singlethread_workqueue(
-		dev_name(master->dev.parent));
-	if (mpc8xxx_spi->workqueue == NULL) {
-		ret = -EBUSY;
-		goto free_irq;
-	}
-
-	ret = spi_register_master(master);
-	if (ret < 0)
-		goto unreg_master;
-
-	dev_info(dev, "at 0x%p (irq = %d), %s mode\n", mpc8xxx_spi->base,
-		 mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
-
-	return master;
-
-unreg_master:
-	destroy_workqueue(mpc8xxx_spi->workqueue);
-free_irq:
-	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
-unmap_io:
-	iounmap(mpc8xxx_spi->base);
-err_ioremap:
-	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
-err_cpm_init:
-	spi_master_put(master);
-err:
-	return ERR_PTR(ret);
-}
-
-static int __devexit mpc8xxx_spi_remove(struct device *dev)
-{
-	struct mpc8xxx_spi *mpc8xxx_spi;
-	struct spi_master *master;
-
-	master = dev_get_drvdata(dev);
-	mpc8xxx_spi = spi_master_get_devdata(master);
-
-	flush_workqueue(mpc8xxx_spi->workqueue);
-	destroy_workqueue(mpc8xxx_spi->workqueue);
-	spi_unregister_master(master);
-
-	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
-	iounmap(mpc8xxx_spi->base);
-	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
-
-	return 0;
-}
-
-struct mpc8xxx_spi_probe_info {
-	struct fsl_spi_platform_data pdata;
-	int *gpios;
-	bool *alow_flags;
-};
-
-static struct mpc8xxx_spi_probe_info *
-to_of_pinfo(struct fsl_spi_platform_data *pdata)
-{
-	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
-}
-
-static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
-{
-	struct device *dev = spi->dev.parent;
-	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
-	u16 cs = spi->chip_select;
-	int gpio = pinfo->gpios[cs];
-	bool alow = pinfo->alow_flags[cs];
-
-	gpio_set_value(gpio, on ^ alow);
-}
-
-static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
-{
-	struct device_node *np = dev->of_node;
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
-	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
-	unsigned int ngpios;
-	int i = 0;
-	int ret;
-
-	ngpios = of_gpio_count(np);
-	if (!ngpios) {
-		/*
-		 * SPI w/o chip-select line. One SPI device is still permitted
-		 * though.
-		 */
-		pdata->max_chipselect = 1;
-		return 0;
-	}
-
-	pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
-	if (!pinfo->gpios)
-		return -ENOMEM;
-	memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
-
-	pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
-				    GFP_KERNEL);
-	if (!pinfo->alow_flags) {
-		ret = -ENOMEM;
-		goto err_alloc_flags;
-	}
-
-	for (; i < ngpios; i++) {
-		int gpio;
-		enum of_gpio_flags flags;
-
-		gpio = of_get_gpio_flags(np, i, &flags);
-		if (!gpio_is_valid(gpio)) {
-			dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
-			ret = gpio;
-			goto err_loop;
-		}
-
-		ret = gpio_request(gpio, dev_name(dev));
-		if (ret) {
-			dev_err(dev, "can't request gpio #%d: %d\n", i, ret);
-			goto err_loop;
-		}
-
-		pinfo->gpios[i] = gpio;
-		pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW;
-
-		ret = gpio_direction_output(pinfo->gpios[i],
-					    pinfo->alow_flags[i]);
-		if (ret) {
-			dev_err(dev, "can't set output direction for gpio "
-				"#%d: %d\n", i, ret);
-			goto err_loop;
-		}
-	}
-
-	pdata->max_chipselect = ngpios;
-	pdata->cs_control = mpc8xxx_spi_cs_control;
-
-	return 0;
-
-err_loop:
-	while (i >= 0) {
-		if (gpio_is_valid(pinfo->gpios[i]))
-			gpio_free(pinfo->gpios[i]);
-		i--;
-	}
-
-	kfree(pinfo->alow_flags);
-	pinfo->alow_flags = NULL;
-err_alloc_flags:
-	kfree(pinfo->gpios);
-	pinfo->gpios = NULL;
-	return ret;
-}
-
-static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
-{
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
-	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
-	int i;
-
-	if (!pinfo->gpios)
-		return 0;
-
-	for (i = 0; i < pdata->max_chipselect; i++) {
-		if (gpio_is_valid(pinfo->gpios[i]))
-			gpio_free(pinfo->gpios[i]);
-	}
-
-	kfree(pinfo->gpios);
-	kfree(pinfo->alow_flags);
-	return 0;
-}
-
-static int __devinit of_mpc8xxx_spi_probe(struct 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;
-
-	pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
-	if (!pinfo)
-		return -ENOMEM;
-
-	pdata = &pinfo->pdata;
-	dev->platform_data = pdata;
-
-	/* Allocate bus num dynamically. */
-	pdata->bus_num = -1;
-
-	/* SPI controller is either clocked from QE or SoC clock. */
-	pdata->sysclk = get_brgfreq();
-	if (pdata->sysclk == -1) {
-		pdata->sysclk = fsl_get_sys_freq();
-		if (pdata->sysclk == -1) {
-			ret = -ENODEV;
-			goto err_clk;
-		}
-	}
-
-	prop = of_get_property(np, "mode", NULL);
-	if (prop && !strcmp(prop, "cpu-qe"))
-		pdata->flags = SPI_QE_CPU_MODE;
-	else if (prop && !strcmp(prop, "qe"))
-		pdata->flags = SPI_CPM_MODE | SPI_QE;
-	else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
-		pdata->flags = SPI_CPM_MODE | SPI_CPM2;
-	else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
-		pdata->flags = SPI_CPM_MODE | SPI_CPM1;
-
-	ret = of_mpc8xxx_spi_get_chipselects(dev);
-	if (ret)
-		goto err;
-
-	ret = of_address_to_resource(np, 0, &mem);
-	if (ret)
-		goto err;
-
-	ret = of_irq_to_resource(np, 0, &irq);
-	if (!ret) {
-		ret = -EINVAL;
-		goto err;
-	}
-
-	master = mpc8xxx_spi_probe(dev, &mem, irq.start);
-	if (IS_ERR(master)) {
-		ret = PTR_ERR(master);
-		goto err;
-	}
-
-	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");
-- 
1.6.4



------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share
of $1 Million in cash or HP Products. Visit us here for more details:
http://p.sf.net/sfu/dev2dev-palm

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

* [PATCH v2 2/6] eSPI: add eSPI controller support
       [not found]     ` <1280735524-17547-2-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2010-08-02  7:52       ` Mingkai Hu
       [not found]         ` <1280735524-17547-3-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
  2010-08-10  6:40       ` [PATCH v2 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Grant Likely
  1 sibling, 1 reply; 26+ messages in thread
From: Mingkai Hu @ 2010-08-02  7:52 UTC (permalink / raw)
  To: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: kumar.gala-KZfg59tc24xl57MIdRCFDg,
	tie-fei.zang-KZfg59tc24xl57MIdRCFDg, Mingkai Hu

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

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

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

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

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

Signed-off-by: Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---

v2:
 - Rename fsl_espi.c to spi_fsl_espi.c, also the config name
 - Move register map definiton from spi_fsl_lib.c to spi_fsl_espi.c
 - Break some funcions line in the arguments instead of the declaration
 - Inconsistent whitespacing in the macro definition
 - Init bits_per_word to 0 to eliminate the else clause
 - Add brace for the else clause to match if clause
 - Add chip name mpc8536 to the compatible value
 - Drop the last entry's comma in the match table
 - move module_init() immediately after the init fsl_espi_init() function

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

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index cd7f13b..a379363 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -140,6 +140,15 @@ config SPI_FSL_SPI
 	  MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
 	  MPC8569 uses the controller in QE mode, MPC8610 in cpu mode.
 
+config SPI_FSL_ESPI
+	tristate "Freescale eSPI controller"
+	depends on FSL_SOC
+	select SPI_FSL_LIB
+	help
+	  This enables using the Freescale eSPI controllers in master mode.
+	  From MPC8536, 85xx platform uses the controller, and all P10xx,
+	  P20xx, P40xx uses this controller.
+
 config SPI_GPIO
 	tristate "GPIO-based bitbanging SPI Master"
 	depends on GENERIC_GPIO
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index cf8d9be..dd86ba7 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_SPI_DW_MMIO)		+= dw_spi_mmio.o
 obj-$(CONFIG_SPI_EP93XX)		+= ep93xx_spi.o
 obj-$(CONFIG_SPI_FSL_LIB)		+= spi_fsl_lib.o
 obj-$(CONFIG_SPI_FSL_SPI)		+= spi_fsl_spi.o
+obj-$(CONFIG_SPI_FSL_ESPI)		+= spi_fsl_espi.o
 obj-$(CONFIG_SPI_GPIO)			+= spi_gpio.o
 obj-$(CONFIG_SPI_IMX)			+= spi_imx.o
 obj-$(CONFIG_SPI_LM70_LLP)		+= spi_lm70llp.o
diff --git a/drivers/spi/spi_fsl_espi.c b/drivers/spi/spi_fsl_espi.c
new file mode 100644
index 0000000..61987cf
--- /dev/null
+++ b/drivers/spi/spi_fsl_espi.c
@@ -0,0 +1,633 @@
+/*
+ * Freescale eSPI controller driver.
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_spi.h>
+#include <sysdev/fsl_soc.h>
+#include <linux/interrupt.h>
+
+#include "spi_fsl_lib.h"
+
+/* eSPI Controller registers */
+struct fsl_espi_reg {
+	__be32 mode;		/* 0x000 - eSPI mode register */
+	__be32 event;		/* 0x004 - eSPI event register */
+	__be32 mask;		/* 0x008 - eSPI mask register */
+	__be32 command;		/* 0x00c - eSPI command register */
+	__be32 transmit;	/* 0x010 - eSPI transmit FIFO access register*/
+	__be32 receive;		/* 0x014 - eSPI receive FIFO access register*/
+	u8 res[8];		/* 0x018 - 0x01c reserved */
+	__be32 csmode[4];	/* 0x020 - 0x02c eSPI cs mode register */
+};
+
+/* eSPI Controller mode register definitions */
+#define SPMODE_ENABLE		(1 << 31)
+#define SPMODE_LOOP		(1 << 30)
+#define SPMODE_TXTHR(x)		((x) << 8)
+#define SPMODE_RXTHR(x)		((x) << 0)
+
+/* eSPI Controller CS mode register definitions */
+#define CSMODE_CI_INACTIVEHIGH	(1 << 31)
+#define CSMODE_CP_BEGIN_EDGECLK	(1 << 30)
+#define CSMODE_REV		(1 << 29)
+#define CSMODE_DIV16		(1 << 28)
+#define CSMODE_PM(x)		((x) << 24)
+#define CSMODE_POL_1		(1 << 20)
+#define CSMODE_LEN(x)		((x) << 16)
+#define CSMODE_BEF(x)		((x) << 12)
+#define CSMODE_AFT(x)		((x) << 8)
+#define CSMODE_CG(x)		((x) << 3)
+
+/* Default mode/csmode for eSPI controller */
+#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3))
+#define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \
+		| CSMODE_AFT(0) | CSMODE_CG(1))
+
+/* SPIE register values */
+#define	SPIE_NE		0x00000200	/* Not empty */
+#define	SPIE_NF		0x00000100	/* Not full */
+
+/* SPIM register values */
+#define	SPIM_NE		0x00000200	/* Not empty */
+#define	SPIM_NF		0x00000100	/* Not full */
+#define SPIE_RXCNT(reg)     ((reg >> 24) & 0x3F)
+#define SPIE_TXCNT(reg)     ((reg >> 16) & 0x3F)
+
+/* SPCOM register values */
+#define SPCOM_CS(x)		((x) << 30)
+#define SPCOM_TRANLEN(x)	((x) << 0)
+#define	SPCOM_TRANLEN_MAX	0xFFFF	/* Max transaction length */
+
+static void fsl_espi_change_mode(struct spi_device *spi)
+{
+	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
+	struct spi_mpc8xxx_cs *cs = spi->controller_state;
+	__be32 __iomem *mode;
+	__be32 __iomem *espi_mode = NULL;
+	u32 tmp;
+	unsigned long flags;
+
+	espi_mode = &mspi->espi_base->mode;
+	mode = &mspi->espi_base->csmode[spi->chip_select];
+
+	/* Turn off IRQs locally to minimize time that SPI is disabled. */
+	local_irq_save(flags);
+
+	/* Turn off SPI unit prior changing mode */
+	tmp = mpc8xxx_spi_read_reg(espi_mode);
+	mpc8xxx_spi_write_reg(espi_mode, tmp & ~SPMODE_ENABLE);
+	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
+	mpc8xxx_spi_write_reg(espi_mode, tmp);
+
+	local_irq_restore(flags);
+}
+
+static u32 fsl_espi_tx_buf_lsb(struct mpc8xxx_spi *mpc8xxx_spi)
+{
+	u32 data;
+	u16 data_h, data_l;
+
+	const u32 *tx = mpc8xxx_spi->tx;
+	if (!tx)
+		return 0;
+
+	data = *tx++ << mpc8xxx_spi->tx_shift;
+	data_l = data & 0xffff;
+	data_h = (data >> 16) & 0xffff;
+	swab16s(&data_l);
+	swab16s(&data_h);
+	data = data_h | data_l;
+
+	mpc8xxx_spi->tx = tx;
+	return data;
+}
+
+static int fsl_espi_setup_transfer(struct spi_device *spi,
+					struct spi_transfer *t)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	int bits_per_word = 0;
+	u8 pm;
+	u32 hz = 0;
+	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
+
+	mpc8xxx_spi = spi_master_get_devdata(spi->master);
+
+	if (t) {
+		bits_per_word = t->bits_per_word;
+		hz = t->speed_hz;
+	}
+
+	/* spi_transfer level calls that work per-word */
+	if (!bits_per_word)
+		bits_per_word = spi->bits_per_word;
+
+	/* Make sure its a bit width we support [4..16] */
+	if ((bits_per_word < 4) || (bits_per_word > 16))
+		return -EINVAL;
+
+	if (!hz)
+		hz = spi->max_speed_hz;
+
+	cs->rx_shift = 0;
+	cs->tx_shift = 0;
+	cs->get_rx = mpc8xxx_spi_rx_buf_u32;
+	cs->get_tx = mpc8xxx_spi_tx_buf_u32;
+	if (bits_per_word <= 8) {
+		cs->rx_shift = 8 - bits_per_word;
+	} else if (bits_per_word <= 16) {
+		cs->rx_shift = 16 - bits_per_word;
+		if (spi->mode & SPI_LSB_FIRST)
+			cs->get_tx = fsl_espi_tx_buf_lsb;
+	} else
+		return -EINVAL;
+
+	mpc8xxx_spi->rx_shift = cs->rx_shift;
+	mpc8xxx_spi->tx_shift = cs->tx_shift;
+	mpc8xxx_spi->get_rx = cs->get_rx;
+	mpc8xxx_spi->get_tx = cs->get_tx;
+
+	bits_per_word = bits_per_word - 1;
+
+	/* mask out bits we are going to set */
+	cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16
+				  | CSMODE_PM(0xF));
+
+	cs->hw_mode |= CSMODE_LEN(bits_per_word);
+
+	if ((mpc8xxx_spi->spibrg / hz) > 64) {
+		cs->hw_mode |= CSMODE_DIV16;
+		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
+
+		WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
+			  "Will use %d Hz instead.\n", dev_name(&spi->dev),
+			  hz, mpc8xxx_spi->spibrg / 1024);
+		if (pm > 16)
+			pm = 16;
+	} else {
+		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
+	}
+	if (pm)
+		pm--;
+
+	cs->hw_mode |= CSMODE_PM(pm);
+
+	fsl_espi_change_mode(spi);
+	return 0;
+}
+
+int fsl_espi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t,
+		unsigned int len)
+{
+	u32 word;
+
+	mspi->count = len;
+
+	/* enable rx ints */
+	mpc8xxx_spi_write_reg(&mspi->espi_base->mask, SPIM_NE);
+
+	/* transmit word */
+	word = mspi->get_tx(mspi);
+	mpc8xxx_spi_write_reg(&mspi->espi_base->transmit, word);
+
+	return 0;
+}
+
+static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t,
+			    bool is_dma_mapped)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+	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->espi_base->command,
+		(SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
+
+	ret = fsl_espi_cpu_bufs(mpc8xxx_spi, t, len);
+	if (ret)
+		return ret;
+
+	wait_for_completion(&mpc8xxx_spi->done);
+
+	/* disable rx ints */
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->espi_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->espi_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->espi_base->mode);
+	loop_mode &= ~SPMODE_LOOP;
+	if (spi->mode & SPI_LOOP)
+		loop_mode |= SPMODE_LOOP;
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->espi_base->mode, loop_mode);
+
+	retval = fsl_espi_setup_transfer(spi, NULL);
+	if (retval < 0) {
+		cs->hw_mode = hw_mode; /* Restore settings */
+		return retval;
+	}
+	return 0;
+}
+
+static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
+{
+	/* 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->espi_base->event);
+		}
+		mspi->len -= 4;
+
+		rx_data = mpc8xxx_spi_read_reg(&mspi->espi_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->espi_base->event)) &
+						SPIE_NF) == 0)
+			cpu_relax();
+
+	/* Clear the events */
+	mpc8xxx_spi_write_reg(&mspi->espi_base->event, events);
+
+	mspi->count -= 1;
+	if (mspi->count) {
+		u32 word = mspi->get_tx(mspi);
+
+		mpc8xxx_spi_write_reg(&mspi->espi_base->transmit, word);
+	} else {
+		complete(&mspi->done);
+	}
+}
+
+irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
+{
+	struct mpc8xxx_spi *mspi = context_data;
+	irqreturn_t ret = IRQ_NONE;
+	u32 events;
+
+	/* Get interrupt events(tx/rx) */
+	events = mpc8xxx_spi_read_reg(&mspi->espi_base->event);
+	if (events)
+		ret = IRQ_HANDLED;
+
+	dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);
+
+	fsl_espi_cpu_irq(mspi, events);
+
+	return ret;
+}
+
+static void fsl_espi_remove(struct mpc8xxx_spi *mspi)
+{
+	iounmap(mspi->espi_base);
+}
+
+static struct spi_master * __devinit fsl_espi_probe(struct device *dev,
+		struct resource *mem, unsigned int irq)
+{
+	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct spi_master *master;
+	struct mpc8xxx_spi *mpc8xxx_spi;
+	u32 regval;
+	int i, ret = 0;
+
+	master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
+	if (master == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	dev_set_drvdata(dev, master);
+
+	ret = mpc8xxx_spi_probe(dev, mem, irq);
+	if (ret)
+		goto err_probe;
+
+	master->setup = fsl_espi_setup;
+
+	mpc8xxx_spi = spi_master_get_devdata(master);
+	mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg;
+	mpc8xxx_spi->spi_remove = fsl_espi_remove;
+
+	mpc8xxx_spi->espi_base = ioremap(mem->start, resource_size(mem));
+	if (mpc8xxx_spi->espi_base == NULL) {
+		ret = -ENOMEM;
+		goto err_probe;
+	}
+
+	/* Register for SPI Interrupt */
+	ret = request_irq(mpc8xxx_spi->irq, fsl_espi_irq,
+			  0, "fsl_espi", mpc8xxx_spi);
+
+	if (ret != 0)
+		goto err_free_irq;
+
+	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
+		mpc8xxx_spi->rx_shift = 16;
+		mpc8xxx_spi->tx_shift = 24;
+	}
+
+	/* SPI controller initializations */
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->espi_base->mode, 0);
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->espi_base->mask, 0);
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->espi_base->command, 0);
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->espi_base->event, 0xffffffff);
+
+	/* Init eSPI CS mode register */
+	for (i = 0; i < pdata->max_chipselect; i++)
+		mpc8xxx_spi_write_reg(&mpc8xxx_spi->espi_base->csmode[i],
+				CSMODE_INIT_VAL);
+
+	/* Enable SPI interface */
+	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
+
+	mpc8xxx_spi_write_reg(&mpc8xxx_spi->espi_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->espi_base,
+			mpc8xxx_spi->irq);
+
+	return master;
+
+unreg_master:
+	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
+err_free_irq:
+	iounmap(mpc8xxx_spi->espi_base);
+err_probe:
+	spi_master_put(master);
+err:
+	return ERR_PTR(ret);
+}
+
+static int of_fsl_espi_get_chipselects(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	const u32 *prop;
+	int len;
+
+	prop = of_get_property(np, "fsl,espi-num-chipselects", &len);
+	if (!prop || len < sizeof(*prop)) {
+		dev_err(dev, "No 'fsl,espi-num-chipselects' property\n");
+		return -EINVAL;
+	}
+
+	pdata->max_chipselect = *prop;
+	pdata->cs_control = NULL;
+
+	return 0;
+}
+
+static int __devinit of_fsl_espi_probe(struct 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,mpc8536-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);
+}
+module_init(fsl_espi_init);
+
+static void __exit fsl_espi_exit(void)
+{
+	of_unregister_platform_driver(&of_fsl_espi_driver);
+}
+module_exit(fsl_espi_exit);
+
+MODULE_AUTHOR("Mingkai Hu");
+MODULE_DESCRIPTION("Enhanced Freescale SPI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_fsl_lib.h b/drivers/spi/spi_fsl_lib.h
index 774e1c8..0772c98 100644
--- a/drivers/spi/spi_fsl_lib.h
+++ b/drivers/spi/spi_fsl_lib.h
@@ -22,10 +22,12 @@
 struct mpc8xxx_spi {
 	struct device *dev;
 	struct fsl_spi_reg __iomem *base;
+	struct fsl_espi_reg __iomem *espi_base;
 
 	/* rx & tx bufs from the spi_transfer */
 	const void *tx;
 	void *rx;
+	int len;
 
 	int subblock;
 	struct spi_pram __iomem *pram;
-- 
1.6.4



------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share
of $1 Million in cash or HP Products. Visit us here for more details:
http://p.sf.net/sfu/dev2dev-palm

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

* [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions
       [not found]         ` <1280735524-17547-3-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2010-08-02  7:52           ` Mingkai Hu
       [not found]             ` <1280735524-17547-4-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
  2010-08-10  6:44           ` [PATCH v2 2/6] eSPI: add eSPI controller support Grant Likely
  1 sibling, 1 reply; 26+ messages in thread
From: Mingkai Hu @ 2010-08-02  7:52 UTC (permalink / raw)
  To: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: kumar.gala-KZfg59tc24xl57MIdRCFDg,
	tie-fei.zang-KZfg59tc24xl57MIdRCFDg, Mingkai Hu

Signed-off-by: Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---

v2:
 - Move the flash partition function from of_spi.c to MTD driver

 drivers/mtd/devices/m25p80.c |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 81e49a9..5f00075 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -752,6 +752,31 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
 	return NULL;
 }
 
+/*
+ * parse_flash_partition - Parse the flash partition on the SPI bus
+ * @spi: Pointer to spi_device device
+ */
+void parse_flash_partition(struct spi_device *spi)
+{
+	struct mtd_partition *parts;
+	struct flash_platform_data *pdata;
+	int nr_parts = 0;
+	struct device_node *np = spi->dev.of_node;
+
+	nr_parts = of_mtd_parse_partitions(&spi->dev, np, &parts);
+	if (!nr_parts)
+		return;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return;
+
+	pdata->parts = parts;
+	pdata->nr_parts = nr_parts;
+	spi->dev.platform_data = pdata;
+
+	return;
+}
 
 /*
  * board specific setup should have ensured the SPI clock used here
@@ -771,6 +796,10 @@ static int __devinit m25p_probe(struct spi_device *spi)
 	 * a chip ID, try the JEDEC id commands; they'll work for most
 	 * newer chips, even if we don't recognize the particular chip.
 	 */
+
+	/* Parse the flash partition */
+	parse_flash_partition(spi);
+
 	data = spi->dev.platform_data;
 	if (data && data->type) {
 		const struct spi_device_id *plat_id;
-- 
1.6.4



------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share
of $1 Million in cash or HP Products. Visit us here for more details:
http://p.sf.net/sfu/dev2dev-palm

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

* [PATCH v2 4/6] mtd: m25p80: add a read function to read page by page
       [not found]             ` <1280735524-17547-4-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2010-08-02  7:52               ` Mingkai Hu
       [not found]                 ` <1280735524-17547-5-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
  2010-08-10  6:56               ` [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions Grant Likely
  1 sibling, 1 reply; 26+ messages in thread
From: Mingkai Hu @ 2010-08-02  7:52 UTC (permalink / raw)
  To: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: kumar.gala-KZfg59tc24xl57MIdRCFDg,
	tie-fei.zang-KZfg59tc24xl57MIdRCFDg, Mingkai Hu

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

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

Signed-off-by: Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---

v2:
 - Add SPI_MASTER_TRANS_LIMIT flag to indicate the master's trans length
   limitation, so the MTD driver can select the correct transfer behaviour
   at driver probe time

 drivers/mtd/devices/m25p80.c |   78 ++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/spi_fsl_espi.c   |    1 +
 include/linux/spi/spi.h      |    1 +
 3 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 5f00075..30e4568 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -376,6 +376,81 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
 }
 
 /*
+ * Read an address range from the flash chip page by page.
+ * Some controller has transaction length limitation such as the
+ * Freescale's eSPI controller can only trasmit 0xFFFF bytes one
+ * time, so we have to read page by page if the len is more than
+ * the limitation.
+ */
+static int m25p80_page_read(struct mtd_info *mtd, loff_t from, size_t len,
+	size_t *retlen, u_char *buf)
+{
+	struct m25p *flash = mtd_to_m25p(mtd);
+	struct spi_transfer t[2];
+	struct spi_message m;
+	u32 i, page_size = 0;
+
+	DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
+			dev_name(&flash->spi->dev), __func__, "from",
+			(u32)from, len);
+
+	/* sanity checks */
+	if (!len)
+		return 0;
+
+	if (from + len > flash->mtd.size)
+		return -EINVAL;
+
+	spi_message_init(&m);
+	memset(t, 0, (sizeof t));
+
+	/* NOTE:
+	 * OPCODE_FAST_READ (if available) is faster.
+	 * Should add 1 byte DUMMY_BYTE.
+	 */
+	t[0].tx_buf = flash->command;
+	t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].rx_buf = buf;
+	spi_message_add_tail(&t[1], &m);
+
+	/* Byte count starts at zero. */
+	if (retlen)
+		*retlen = 0;
+
+	mutex_lock(&flash->lock);
+
+	/* Wait till previous write/erase is done. */
+	if (wait_till_ready(flash)) {
+		/* REVISIT status return?? */
+		mutex_unlock(&flash->lock);
+		return 1;
+	}
+
+	/* Set up the write data buffer. */
+	flash->command[0] = OPCODE_READ;
+
+	for (i = page_size; i < len; i += page_size) {
+		page_size = len - i;
+		if (page_size > flash->page_size)
+			page_size = flash->page_size;
+		m25p_addr2cmd(flash, from + i, flash->command);
+		t[1].len = page_size;
+		t[1].rx_buf = buf + i;
+
+		spi_sync(flash->spi, &m);
+
+		*retlen += m.actual_length - m25p_cmdsz(flash)
+			- FAST_READ_DUMMY_BYTE;
+	}
+
+	mutex_unlock(&flash->lock);
+
+	return 0;
+}
+
+/*
  * Write an address range to the flash chip.  Data must be written in
  * FLASH_PAGESIZE chunks.  The address range may be any size provided
  * it is within the physical boundaries.
@@ -877,6 +952,9 @@ static int __devinit m25p_probe(struct spi_device *spi)
 	flash->mtd.erase = m25p80_erase;
 	flash->mtd.read = m25p80_read;
 
+	if (spi->master->flags & SPI_MASTER_TRANS_LIMIT)
+		flash->mtd.read = m25p80_page_read;
+
 	/* sst flash chips use AAI word program */
 	if (info->jedec_id >> 16 == 0xbf)
 		flash->mtd.write = sst_write;
diff --git a/drivers/spi/spi_fsl_espi.c b/drivers/spi/spi_fsl_espi.c
index 61987cf..e15b7dc 100644
--- a/drivers/spi/spi_fsl_espi.c
+++ b/drivers/spi/spi_fsl_espi.c
@@ -470,6 +470,7 @@ static struct spi_master * __devinit fsl_espi_probe(struct device *dev,
 		goto err_probe;
 
 	master->setup = fsl_espi_setup;
+	master->flags = SPI_MASTER_TRANS_LIMIT;
 
 	mpc8xxx_spi = spi_master_get_devdata(master);
 	mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index af56071..0729cbd 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -261,6 +261,7 @@ struct spi_master {
 #define SPI_MASTER_HALF_DUPLEX	BIT(0)		/* can't do full duplex */
 #define SPI_MASTER_NO_RX	BIT(1)		/* can't do buffer read */
 #define SPI_MASTER_NO_TX	BIT(2)		/* can't do buffer write */
+#define SPI_MASTER_TRANS_LIMIT	BIT(3)		/* have trans length limit */
 
 	/* Setup mode and clock, etc (spi driver may call many times).
 	 *
-- 
1.6.4



------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share
of $1 Million in cash or HP Products. Visit us here for more details:
http://p.sf.net/sfu/dev2dev-palm

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

* [PATCH v2 5/6] powerpc/of: add eSPI controller dts bindings
       [not found]                 ` <1280735524-17547-5-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2010-08-02  7:52                   ` Mingkai Hu
       [not found]                     ` <1280735524-17547-6-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
  2010-08-10  7:00                   ` [PATCH v2 4/6] mtd: m25p80: add a read function to read page by page Grant Likely
  1 sibling, 1 reply; 26+ messages in thread
From: Mingkai Hu @ 2010-08-02  7:52 UTC (permalink / raw)
  To: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: kumar.gala-KZfg59tc24xl57MIdRCFDg,
	tie-fei.zang-KZfg59tc24xl57MIdRCFDg, Mingkai Hu

Also modifiy the document of cell-index in SPI controller.

Signed-off-by: Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---

v2:
 - Add cell-index clarification
 - Add mpc8536 chip name to the compatible value

 Documentation/powerpc/dts-bindings/fsl/spi.txt |   24 +++++++++++++++++++++++-
 1 files changed, 23 insertions(+), 1 deletions(-)

diff --git a/Documentation/powerpc/dts-bindings/fsl/spi.txt b/Documentation/powerpc/dts-bindings/fsl/spi.txt
index 80510c0..01543ca 100644
--- a/Documentation/powerpc/dts-bindings/fsl/spi.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/spi.txt
@@ -1,7 +1,9 @@
 * SPI (Serial Peripheral Interface)
 
 Required properties:
-- cell-index : SPI controller index.
+- cell-index : QE SPI subblock index.
+ 	       0: QE subblock SPI1
+ 	       1: QE subblock SPI2
 - compatible : should be "fsl,spi".
 - mode : the SPI operation mode, it can be "cpu" or "cpu-qe".
 - reg : Offset and length of the register set for the device
@@ -29,3 +31,23 @@ Example:
 		gpios = <&gpio 18 1	// device reg=<0>
 			 &gpio 19 1>;	// device reg=<1>
 	};
+
+
+* eSPI (Enhanced Serial Peripheral Interface)
+
+Required properties:
+- compatible : should be "fsl,mpc8536-espi".
+- reg : Offset and length of the register set for the device.
+- interrupts : should contain eSPI interrupt, the device has one interrupt.
+- fsl,espi-num-chipselects : the number of the chipselect signals.
+
+Example:
+	spi@110000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "fsl,espi";
+		reg = <0x110000 0x1000>;
+		interrupts = <53 0x2>;
+		interrupt-parent = <&mpic>;
+		fsl,espi-num-chipselects = <4>;
+	};
-- 
1.6.4



------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share
of $1 Million in cash or HP Products. Visit us here for more details:
http://p.sf.net/sfu/dev2dev-palm

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

* [PATCH v2 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board
       [not found]                     ` <1280735524-17547-6-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2010-08-02  7:52                       ` Mingkai Hu
       [not found]                         ` <1280735524-17547-7-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
  0 siblings, 1 reply; 26+ messages in thread
From: Mingkai Hu @ 2010-08-02  7:52 UTC (permalink / raw)
  To: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: kumar.gala-KZfg59tc24xl57MIdRCFDg,
	tie-fei.zang-KZfg59tc24xl57MIdRCFDg, Mingkai Hu

Signed-off-by: Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---

v2:
 - Remove the whitespace inconsitencies

 arch/powerpc/boot/dts/mpc8536ds.dts |   52 +++++++++++++++++++++++++++++++++++
 arch/powerpc/boot/dts/p4080ds.dts   |   11 +++-----
 2 files changed, 56 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts
index 815cebb..a75c10e 100644
--- a/arch/powerpc/boot/dts/mpc8536ds.dts
+++ b/arch/powerpc/boot/dts/mpc8536ds.dts
@@ -108,6 +108,58 @@
 			};
 		};
 
+		spi@7000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,mpc8536-espi";
+			reg = <0x7000 0x1000>;
+			interrupts = <59 0x2>;
+			interrupt-parent = <&mpic>;
+			fsl,espi-num-chipselects = <4>;
+
+			flash@0 {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "spansion,s25sl12801";
+				reg = <0>;
+				spi-max-frequency = <40000000>;
+				partition@u-boot {
+					label = "u-boot";
+					reg = <0x00000000 0x00100000>;
+					read-only;
+				};
+				partition@kernel {
+					label = "kernel";
+					reg = <0x00100000 0x00500000>;
+					read-only;
+				};
+				partition@dtb {
+					label = "dtb";
+					reg = <0x00600000 0x00100000>;
+					read-only;
+				};
+				partition@fs {
+					label = "file system";
+					reg = <0x00700000 0x00900000>;
+				};
+			};
+			flash@1 {
+				compatible = "spansion,s25sl12801";
+				reg = <1>;
+				spi-max-frequency = <40000000>;
+			};
+			flash@2 {
+				compatible = "spansion,s25sl12801";
+				reg = <2>;
+				spi-max-frequency = <40000000>;
+			};
+			flash@3 {
+				compatible = "spansion,s25sl12801";
+				reg = <3>;
+				spi-max-frequency = <40000000>;
+			};
+		};
+
 		dma@21300 {
 			#address-cells = <1>;
 			#size-cells = <1>;
diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts
index 6b29eab..48437ad 100644
--- a/arch/powerpc/boot/dts/p4080ds.dts
+++ b/arch/powerpc/boot/dts/p4080ds.dts
@@ -236,22 +236,19 @@
 		};
 
 		spi@110000 {
-			cell-index = <0>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			compatible = "fsl,espi";
+			compatible = "fsl,mpc8536-espi";
 			reg = <0x110000 0x1000>;
 			interrupts = <53 0x2>;
 			interrupt-parent = <&mpic>;
-			espi,num-ss-bits = <4>;
-			mode = "cpu";
+			fsl,espi-num-chipselects = <4>;
 
-			fsl_m25p80@0 {
+			flash@0 {
 				#address-cells = <1>;
 				#size-cells = <1>;
-				compatible = "fsl,espi-flash";
+				compatible = "spansion,s25sl12801";
 				reg = <0>;
-				linux,modalias = "fsl_m25p80";
 				spi-max-frequency = <40000000>; /* input clock */
 				partition@u-boot {
 					label = "u-boot";
-- 
1.6.4



------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share
of $1 Million in cash or HP Products. Visit us here for more details:
http://p.sf.net/sfu/dev2dev-palm

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

* Re: [PATCH v2 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
       [not found]     ` <1280735524-17547-2-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
  2010-08-02  7:52       ` [PATCH v2 2/6] eSPI: add eSPI controller support Mingkai Hu
@ 2010-08-10  6:40       ` Grant Likely
  2010-09-02  8:27         ` Hu Mingkai-B21284
  1 sibling, 1 reply; 26+ messages in thread
From: Grant Likely @ 2010-08-10  6:40 UTC (permalink / raw)
  To: Mingkai Hu
  Cc: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A,
	kumar.gala-KZfg59tc24xl57MIdRCFDg,
	tie-fei.zang-KZfg59tc24xl57MIdRCFDg,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Mon, Aug 2, 2010 at 1:51 AM, Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org> wrote:
> Refactor the common code in file spi_mpc8xxx.c to spi_fsl_lib.c
> used by SPI/eSPI controller driver as a library, move the SPI
> controller driver to a new file spi_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-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
> ---
> v2:
>  - Rename spi_mpc8xxx.c to spi_fsl_lib.c, also the config name
>  - Rename fsl_spi.c to spi_fsl_spi.c, also the config name
>  - Move register map definiton from spi_fsl_lib.c to spi_fsl_spi.c
>  - Break some funcions line in the arguments instead of the declaration
>  - Init bits_per_word to 0 to eliminate the else clause
>  - Add brace for the else clause to match if clause
>  - Drop the last entry's comma in the match table
>  - move module_init() immediately after the init fsl_spi_init() function
>
>  drivers/spi/Kconfig       |   20 +-
>  drivers/spi/Makefile      |    3 +-
>  drivers/spi/spi_fsl_lib.c |  237 ++++++++
>  drivers/spi/spi_fsl_lib.h |  119 ++++
>  drivers/spi/spi_fsl_spi.c | 1173 +++++++++++++++++++++++++++++++++++++
>  drivers/spi/spi_mpc8xxx.c | 1421 ---------------------------------------------

This patch seems pretty good now.  However, the rename from
spi_mpc8xxx.c to spi_fsl_lib.c should be done in a separate patch.  It
is too difficult to track what has changed, when the file gets moved
at the same time.  Move the file in one patch verbatim (with the
required Makefile change), and then move out the fsl_spi specific bits
in a second patch.

g.

------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev 

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

* Re: [PATCH v2 2/6] eSPI: add eSPI controller support
       [not found]         ` <1280735524-17547-3-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
  2010-08-02  7:52           ` [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions Mingkai Hu
@ 2010-08-10  6:44           ` Grant Likely
       [not found]             ` <AANLkTin3W4++cAFcksVBX3QxeV8QF3d5T2tGy_KbEkRs-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  1 sibling, 1 reply; 26+ messages in thread
From: Grant Likely @ 2010-08-10  6:44 UTC (permalink / raw)
  To: Mingkai Hu
  Cc: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A,
	kumar.gala-KZfg59tc24xl57MIdRCFDg,
	tie-fei.zang-KZfg59tc24xl57MIdRCFDg,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Mon, Aug 2, 2010 at 1:52 AM, Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org> wrote:
> Add eSPI controller support based on the library code spi_fsl_lib.c.
>
> The eSPI controller is newer controller 85xx/Pxxx devices supported.
> There're some differences comparing to the SPI controller:
>
> 1. Has different register map and different bit definition
>   So leave the code operated the register to the driver code, not
>   the common code.
>
> 2. Support 4 dedicated chip selects
>   The software can't controll the chip selects directly, The SPCOM[CS]
>   field is used to select which chip selects is used, and the
>   SPCOM[TRANLEN] field is set to tell the controller how long the CS
>   signal need to be asserted. So the driver doesn't need the chipselect
>   related function when transfering data, just set corresponding register
>   fields to controll the chipseclect.
>
> 3. Different Transmit/Receive FIFO access register behavior
>   For SPI controller, the Tx/Rx FIFO access register can hold only
>   one character regardless of the character length, but for eSPI
>   controller, the register can hold 4 or 2 characters according to
>   the character lengths. Access the Tx/Rx FIFO access register of the
>   eSPI controller will shift out/in 4/2 characters one time. For SPI
>   subsystem, the command and data are put into different transfers, so
>   we need to combine all the transfers to one transfer in order to pass
>   the transfer to eSPI controller.
>
> Signed-off-by: Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

I've not dug deep into this patch, but it seems pretty good.  I did
notice one thing below...
[...]

> diff --git a/drivers/spi/spi_fsl_lib.h b/drivers/spi/spi_fsl_lib.h
> index 774e1c8..0772c98 100644
> --- a/drivers/spi/spi_fsl_lib.h
> +++ b/drivers/spi/spi_fsl_lib.h
> @@ -22,10 +22,12 @@
>  struct mpc8xxx_spi {
>        struct device *dev;
>        struct fsl_spi_reg __iomem *base;
> +       struct fsl_espi_reg __iomem *espi_base;

There's got to be a cleaner way to do this.  Rather than putting both
pointers into mpc8xxx_spi, I suggest each driver use its own
fsl_spi_priv and fsl_espi_priv wrapper structures that contain the
controller specific properties.

cheers,
g.

------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev 

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

* Re: [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions
       [not found]             ` <1280735524-17547-4-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
  2010-08-02  7:52               ` [PATCH v2 4/6] mtd: m25p80: add a read function to read page by page Mingkai Hu
@ 2010-08-10  6:56               ` Grant Likely
  2010-08-10  7:14                 ` [spi-devel-general] " David Brownell
  1 sibling, 1 reply; 26+ messages in thread
From: Grant Likely @ 2010-08-10  6:56 UTC (permalink / raw)
  To: Mingkai Hu
  Cc: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A,
	kumar.gala-KZfg59tc24xl57MIdRCFDg,
	tie-fei.zang-KZfg59tc24xl57MIdRCFDg,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Mon, Aug 2, 2010 at 1:52 AM, Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org> wrote:
> Signed-off-by: Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
> ---
>
> v2:
>  - Move the flash partition function from of_spi.c to MTD driver
>
>  drivers/mtd/devices/m25p80.c |   29 +++++++++++++++++++++++++++++
>  1 files changed, 29 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index 81e49a9..5f00075 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -752,6 +752,31 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
>        return NULL;
>  }
>
> +/*
> + * parse_flash_partition - Parse the flash partition on the SPI bus
> + * @spi: Pointer to spi_device device
> + */
> +void parse_flash_partition(struct spi_device *spi)
> +{
> +       struct mtd_partition *parts;
> +       struct flash_platform_data *pdata;
> +       int nr_parts = 0;
> +       struct device_node *np = spi->dev.of_node;
> +
> +       nr_parts = of_mtd_parse_partitions(&spi->dev, np, &parts);
> +       if (!nr_parts)
> +               return;
> +
> +       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
> +       if (!pdata)
> +               return;
> +
> +       pdata->parts = parts;
> +       pdata->nr_parts = nr_parts;
> +       spi->dev.platform_data = pdata;

The driver is not allowed to write to the platform_data pointer in the
device structure because it leaves an absolute mess in trying to
figure out who owns the pdata pointer.  Should it be freed when the
driver is unbound?  Is it statically allocated? etc.  There is a safer
way to get the data (see below).

> +
> +       return;
> +}
>
>  /*
>  * board specific setup should have ensured the SPI clock used here
> @@ -771,6 +796,10 @@ static int __devinit m25p_probe(struct spi_device *spi)
>         * a chip ID, try the JEDEC id commands; they'll work for most
>         * newer chips, even if we don't recognize the particular chip.
>         */
> +
> +       /* Parse the flash partition */
> +       parse_flash_partition(spi);
> +

Doing this unconditionally is dangerous, and if a platform_data
structure is provided, then it must alwasy take precedence over the
device tree data (because the platform code has gone to extra lengths
to add a pdata structure; that must mean it is important!)  :-)

Instead what can be done is to call of_mtd_parse_partitions() directly
from the probe routine after checking to see if the pdata structure
exists and has partition information.  If it doesn't, then call
of_mtd_parse_partitions() to get values for parts and nr_parts.  Doing
it that way completely eliminates the uncertainty over pdata pointer
ownership, and eliminates having an anonymous pointer buried in the
driver.

Cheers,
g.

------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev 

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

* Re: [PATCH v2 4/6] mtd: m25p80: add a read function to read page by page
       [not found]                 ` <1280735524-17547-5-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
  2010-08-02  7:52                   ` [PATCH v2 5/6] powerpc/of: add eSPI controller dts bindings Mingkai Hu
@ 2010-08-10  7:00                   ` Grant Likely
  2010-08-10 13:44                     ` [spi-devel-general] " David Brownell
  2010-09-02  9:04                     ` Hu Mingkai-B21284
  1 sibling, 2 replies; 26+ messages in thread
From: Grant Likely @ 2010-08-10  7:00 UTC (permalink / raw)
  To: Mingkai Hu, David Woodhouse
  Cc: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A,
	kumar.gala-KZfg59tc24xl57MIdRCFDg,
	tie-fei.zang-KZfg59tc24xl57MIdRCFDg,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

[adding David Woodhouse]

(Btw, you should cc: David Woodhouse and the mtd list on the MTD patches).

On Mon, Aug 2, 2010 at 1:52 AM, Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org> wrote:
> For Freescale's eSPI controller, the max transaction length one time
> is limitted by the SPCOM[TRANSLEN] field which is 0xFFFF. When used
> mkfs.ext2 command to create ext2 filesystem on the flash, the read
> length will exceed the max value of the SPCOM[TRANSLEN] field, so
> change the read function to read page by page.
>
> For other SPI flash driver, also needed to supply the read function
> if used the eSPI controller.
>
> Signed-off-by: Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

This one bothers me, but I can't put my finger on it.  The flag feels
like a controller specific hack.  David, can you take a look at this
patch?

g.

> ---
>
> v2:
>  - Add SPI_MASTER_TRANS_LIMIT flag to indicate the master's trans length
>   limitation, so the MTD driver can select the correct transfer behaviour
>   at driver probe time
>
>  drivers/mtd/devices/m25p80.c |   78 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/spi/spi_fsl_espi.c   |    1 +
>  include/linux/spi/spi.h      |    1 +
>  3 files changed, 80 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index 5f00075..30e4568 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -376,6 +376,81 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
>  }
>
>  /*
> + * Read an address range from the flash chip page by page.
> + * Some controller has transaction length limitation such as the
> + * Freescale's eSPI controller can only trasmit 0xFFFF bytes one
> + * time, so we have to read page by page if the len is more than
> + * the limitation.
> + */
> +static int m25p80_page_read(struct mtd_info *mtd, loff_t from, size_t len,
> +       size_t *retlen, u_char *buf)
> +{
> +       struct m25p *flash = mtd_to_m25p(mtd);
> +       struct spi_transfer t[2];
> +       struct spi_message m;
> +       u32 i, page_size = 0;
> +
> +       DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
> +                       dev_name(&flash->spi->dev), __func__, "from",
> +                       (u32)from, len);
> +
> +       /* sanity checks */
> +       if (!len)
> +               return 0;
> +
> +       if (from + len > flash->mtd.size)
> +               return -EINVAL;
> +
> +       spi_message_init(&m);
> +       memset(t, 0, (sizeof t));
> +
> +       /* NOTE:
> +        * OPCODE_FAST_READ (if available) is faster.
> +        * Should add 1 byte DUMMY_BYTE.
> +        */
> +       t[0].tx_buf = flash->command;
> +       t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
> +       spi_message_add_tail(&t[0], &m);
> +
> +       t[1].rx_buf = buf;
> +       spi_message_add_tail(&t[1], &m);
> +
> +       /* Byte count starts at zero. */
> +       if (retlen)
> +               *retlen = 0;
> +
> +       mutex_lock(&flash->lock);
> +
> +       /* Wait till previous write/erase is done. */
> +       if (wait_till_ready(flash)) {
> +               /* REVISIT status return?? */
> +               mutex_unlock(&flash->lock);
> +               return 1;
> +       }
> +
> +       /* Set up the write data buffer. */
> +       flash->command[0] = OPCODE_READ;
> +
> +       for (i = page_size; i < len; i += page_size) {
> +               page_size = len - i;
> +               if (page_size > flash->page_size)
> +                       page_size = flash->page_size;
> +               m25p_addr2cmd(flash, from + i, flash->command);
> +               t[1].len = page_size;
> +               t[1].rx_buf = buf + i;
> +
> +               spi_sync(flash->spi, &m);
> +
> +               *retlen += m.actual_length - m25p_cmdsz(flash)
> +                       - FAST_READ_DUMMY_BYTE;
> +       }
> +
> +       mutex_unlock(&flash->lock);
> +
> +       return 0;
> +}
> +
> +/*
>  * Write an address range to the flash chip.  Data must be written in
>  * FLASH_PAGESIZE chunks.  The address range may be any size provided
>  * it is within the physical boundaries.
> @@ -877,6 +952,9 @@ static int __devinit m25p_probe(struct spi_device *spi)
>        flash->mtd.erase = m25p80_erase;
>        flash->mtd.read = m25p80_read;
>
> +       if (spi->master->flags & SPI_MASTER_TRANS_LIMIT)
> +               flash->mtd.read = m25p80_page_read;
> +
>        /* sst flash chips use AAI word program */
>        if (info->jedec_id >> 16 == 0xbf)
>                flash->mtd.write = sst_write;
> diff --git a/drivers/spi/spi_fsl_espi.c b/drivers/spi/spi_fsl_espi.c
> index 61987cf..e15b7dc 100644
> --- a/drivers/spi/spi_fsl_espi.c
> +++ b/drivers/spi/spi_fsl_espi.c
> @@ -470,6 +470,7 @@ static struct spi_master * __devinit fsl_espi_probe(struct device *dev,
>                goto err_probe;
>
>        master->setup = fsl_espi_setup;
> +       master->flags = SPI_MASTER_TRANS_LIMIT;
>
>        mpc8xxx_spi = spi_master_get_devdata(master);
>        mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg;
> diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
> index af56071..0729cbd 100644
> --- a/include/linux/spi/spi.h
> +++ b/include/linux/spi/spi.h
> @@ -261,6 +261,7 @@ struct spi_master {
>  #define SPI_MASTER_HALF_DUPLEX BIT(0)          /* can't do full duplex */
>  #define SPI_MASTER_NO_RX       BIT(1)          /* can't do buffer read */
>  #define SPI_MASTER_NO_TX       BIT(2)          /* can't do buffer write */
> +#define SPI_MASTER_TRANS_LIMIT BIT(3)          /* have trans length limit */
>
>        /* Setup mode and clock, etc (spi driver may call many times).
>         *
> --
> 1.6.4
>
>
>



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

------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev 

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

* Re: [PATCH v2 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board
       [not found]                         ` <1280735524-17547-7-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2010-08-10  7:10                           ` Grant Likely
       [not found]                             ` <AANLkTinzea7-k3Wd6EsAy+ipThHMhkpMF3pCP7g_6O6J-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 26+ messages in thread
From: Grant Likely @ 2010-08-10  7:10 UTC (permalink / raw)
  To: Mingkai Hu
  Cc: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A,
	kumar.gala-KZfg59tc24xl57MIdRCFDg,
	tie-fei.zang-KZfg59tc24xl57MIdRCFDg,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

Hi Mingkai,

one comment below.  Otherwise this patch looks good, and so does patch 5.

g.

On Mon, Aug 2, 2010 at 1:52 AM, Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org> wrote:
> Signed-off-by: Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
> ---
>
> v2:
>  - Remove the whitespace inconsitencies
>
>  arch/powerpc/boot/dts/mpc8536ds.dts |   52 +++++++++++++++++++++++++++++++++++
>  arch/powerpc/boot/dts/p4080ds.dts   |   11 +++-----
>  2 files changed, 56 insertions(+), 7 deletions(-)
>
> diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts
> index 815cebb..a75c10e 100644
> --- a/arch/powerpc/boot/dts/mpc8536ds.dts
> +++ b/arch/powerpc/boot/dts/mpc8536ds.dts
> @@ -108,6 +108,58 @@
>                        };
>                };
>
> +               spi@7000 {
> +                       #address-cells = <1>;
> +                       #size-cells = <0>;
> +                       compatible = "fsl,mpc8536-espi";
> +                       reg = <0x7000 0x1000>;
> +                       interrupts = <59 0x2>;
> +                       interrupt-parent = <&mpic>;
> +                       fsl,espi-num-chipselects = <4>;
> +
> +                       flash@0 {
> +                               #address-cells = <1>;
> +                               #size-cells = <1>;
> +                               compatible = "spansion,s25sl12801";
> +                               reg = <0>;
> +                               spi-max-frequency = <40000000>;
> +                               partition@u-boot {
> +                                       label = "u-boot";
> +                                       reg = <0x00000000 0x00100000>;
> +                                       read-only;
> +                               };
> +                               partition@kernel {
> +                                       label = "kernel";
> +                                       reg = <0x00100000 0x00500000>;
> +                                       read-only;
> +                               };
> +                               partition@dtb {
> +                                       label = "dtb";
> +                                       reg = <0x00600000 0x00100000>;
> +                                       read-only;
> +                               };
> +                               partition@fs {
> +                                       label = "file system";
> +                                       reg = <0x00700000 0x00900000>;
> +                               };
> +                       };
> +                       flash@1 {
> +                               compatible = "spansion,s25sl12801";
> +                               reg = <1>;
> +                               spi-max-frequency = <40000000>;
> +                       };
> +                       flash@2 {
> +                               compatible = "spansion,s25sl12801";
> +                               reg = <2>;
> +                               spi-max-frequency = <40000000>;
> +                       };
> +                       flash@3 {
> +                               compatible = "spansion,s25sl12801";
> +                               reg = <3>;
> +                               spi-max-frequency = <40000000>;
> +                       };
> +               };
> +
>                dma@21300 {
>                        #address-cells = <1>;
>                        #size-cells = <1>;
> diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts
> index 6b29eab..48437ad 100644
> --- a/arch/powerpc/boot/dts/p4080ds.dts
> +++ b/arch/powerpc/boot/dts/p4080ds.dts
> @@ -236,22 +236,19 @@
>                };
>
>                spi@110000 {
> -                       cell-index = <0>;
>                        #address-cells = <1>;
>                        #size-cells = <0>;
> -                       compatible = "fsl,espi";
> +                       compatible = "fsl,mpc8536-espi";

Should be more specific here by specifying the exact device; plus a
list of what it is compatible with.  For example:

compatible = "fsl,p4080-espi", "fsl,mpc5836-espi";

the reason for this is that the driver for the existing part is still
able to bind against the node, but if it ever needs it, then
information about the specific device is available which can be used
to (for example) figure out when to enable silicon bug workarounds.

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



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev 

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

* Re: [spi-devel-general] [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions
  2010-08-10  6:56               ` [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions Grant Likely
@ 2010-08-10  7:14                 ` David Brownell
       [not found]                   ` <796604.30863.qm-g47maUHHHF9eqboJWQvT7/u2YVrzzGjVVpNB7YpNyf8@public.gmane.org>
  0 siblings, 1 reply; 26+ messages in thread
From: David Brownell @ 2010-08-10  7:14 UTC (permalink / raw)
  To: Mingkai Hu, Grant Likely; +Cc: linuxppc-dev, kumar.gala, spi-devel-general



--- On Mon, 8/9/10, Grant Likely <grant.likely@secretlab.ca> wrote:


> > +       nr_parts =
> of_mtd_parse_partitions(&spi->dev, np, &parts);

Let's keep OF-specific logic out of drivers like
this one ...  intended to work without OF.

NAK on adding dependencies like OF to drivers
and other infrastructure that starts generic.

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

* Re: [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions
       [not found]                   ` <796604.30863.qm-g47maUHHHF9eqboJWQvT7/u2YVrzzGjVVpNB7YpNyf8@public.gmane.org>
@ 2010-08-10  7:16                     ` Grant Likely
       [not found]                       ` <AANLkTi=FGf9gbWDkO4qs01Z+qkip+Zm11=Jc4wHu3G8b-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 26+ messages in thread
From: Grant Likely @ 2010-08-10  7:16 UTC (permalink / raw)
  To: David Brownell
  Cc: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A, Mingkai Hu,
	tie-fei.zang-KZfg59tc24xl57MIdRCFDg,
	kumar.gala-KZfg59tc24xl57MIdRCFDg,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Tue, Aug 10, 2010 at 1:14 AM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote:
>
>
> --- On Mon, 8/9/10, Grant Likely <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org> wrote:
>
>
>> > +       nr_parts =
>> of_mtd_parse_partitions(&spi->dev, np, &parts);
>
> Let's keep OF-specific logic out of drivers like
> this one ...  intended to work without OF.
>
> NAK on adding dependencies like OF to drivers
> and other infrastructure that starts generic.

The OF hooks compile to no-ops when CONFIG_OF is disabled.  I've been
very careful about that.

g.

------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev 

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

* Re: [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions
       [not found]                       ` <AANLkTi=FGf9gbWDkO4qs01Z+qkip+Zm11=Jc4wHu3G8b-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2010-08-10  8:29                         ` Joakim Tjernlund
       [not found]                           ` <OF0D24DC16.E1FE65D2-ONC125777B.002E544A-C125777B.002EA7C2-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org>
  0 siblings, 1 reply; 26+ messages in thread
From: Joakim Tjernlund @ 2010-08-10  8:29 UTC (permalink / raw)
  To: Grant Likely
  Cc: David Brownell,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	kumar.gala-KZfg59tc24xl57MIdRCFDg,
	Mingkai.hu-KZfg59tc24xl57MIdRCFDg,
	linuxppc-dev-mnsaURCQ41uSOrVYXZrec+piUIM3Gm7n

> On Tue, Aug 10, 2010 at 1:14 AM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote:
> >
> >
> > --- On Mon, 8/9/10, Grant Likely <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org> wrote:
> >
> >
> >> > +       nr_parts =
> >> of_mtd_parse_partitions(&spi->dev, np, &parts);
> >
> > Let's keep OF-specific logic out of drivers like
> > this one ...  intended to work without OF.
> >
> > NAK on adding dependencies like OF to drivers
> > and other infrastructure that starts generic.

Agreed.

>
> The OF hooks compile to no-ops when CONFIG_OF is disabled.  I've been
> very careful about that.

OF should not be in the drivers, one should be able use some other method
than OF.


------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev 

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

* Re: [spi-devel-general] [PATCH v2 4/6] mtd: m25p80: add a read function to read page by page
  2010-08-10  7:00                   ` [PATCH v2 4/6] mtd: m25p80: add a read function to read page by page Grant Likely
@ 2010-08-10 13:44                     ` David Brownell
  2010-09-02  9:04                     ` Hu Mingkai-B21284
  1 sibling, 0 replies; 26+ messages in thread
From: David Brownell @ 2010-08-10 13:44 UTC (permalink / raw)
  To: Mingkai Hu, David Woodhouse, Grant Likely
  Cc: linuxppc-dev, kumar.gala, spi-devel-general



--- On Tue, 8/10/10, Grant Likely <grant.likely@secretlab.ca> wrote:

> This one bothers me, but I can't put my
> finger on it. The flag feels
> like a controller specific hack.

That's because it *IS* ...

Not clear what a good fix would look like.
But in general, SPI master controllers are
responsible for returning all bytes requested,
instead of (as with this one) a subset.

Suggesting the real issue is a buggy SPI
master controller and/or driver.  Can't it
issue multiple reads to collect all the data
requested?? 

- Dave

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

* Re: [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions
       [not found]                           ` <OF0D24DC16.E1FE65D2-ONC125777B.002E544A-C125777B.002EA7C2-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org>
@ 2010-08-10 14:56                             ` Grant Likely
       [not found]                               ` <AANLkTinYYTj+dR6ckPoShHKZTUmENEA1O-DYP9mjnWrs-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 26+ messages in thread
From: Grant Likely @ 2010-08-10 14:56 UTC (permalink / raw)
  To: Joakim Tjernlund
  Cc: kumar.gala-KZfg59tc24xl57MIdRCFDg, David Brownell,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linuxppc-dev-mnsaURCQ41sdnm+yROfE0A@public.gmane.org Mingkai Hu,
	David Woodhouse

On Tue, Aug 10, 2010 at 2:29 AM, Joakim Tjernlund
<joakim.tjernlund-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org> wrote:
>> On Tue, Aug 10, 2010 at 1:14 AM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote:
>> >
>> >
>> > --- On Mon, 8/9/10, Grant Likely <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org> wrote:
>> >
>> >
>> >> > +       nr_parts =
>> >> of_mtd_parse_partitions(&spi->dev, np, &parts);
>> >
>> > Let's keep OF-specific logic out of drivers like
>> > this one ...  intended to work without OF.
>> >
>> > NAK on adding dependencies like OF to drivers
>> > and other infrastructure that starts generic.
>
> Agreed.
>
>>
>> The OF hooks compile to no-ops when CONFIG_OF is disabled.  I've been
>> very careful about that.
>
> OF should not be in the drivers, one should be able use some other method
> than OF.

If a device is described in the device tree, then the code has to live
*somewhere* to translate the data from the device tree into a form the
driver can use.  If not the driver, then where should that code live?

If it is in the machine support code, then that requires foreknowledge
about all the device specific data that needs to be translated out of
the device tree at device registration time, which also means that the
translation code cannot be a module and it nullifies some of the
advantages of the device tree.  Not to mention the fact that it is
just plain ugly!  :-)

Some of it can go into the infrastructure code, but only for parsing
common properties like irqs, address ranges, and some common bindings
like registering spi and i2c bus child nodes as devices.  (This
*particular* case may fall into this category if add_mtd_device() was
able to call the OF partition parsing hook if a device node pointer
was present; which does make a certain amount of sense, but I defer to
dwmw2 in this case).  However, device-specific properties cannot be
parsed in the infrastructure code because the infrastructure has no
knowledge of device specific bits.

The suggestion has been raised to use something like bus notifiers to
get a hook onto the device registration before the driver is probed so
that the platform_data can be translated in an separate chuck of code,
but down that path lies insanity.  There are all kinds of ordering
issues (like making sure the translation code is called before the
driver probe code), and it is a lot of complexity for what is really a
simple thing.

I've yet to be convinced that device-specific OF calls belongs
anywhere in the kernel other than in the driver that uses the data.

That being said, I completely agree that OF calls do not belong in the
vast majority of the driver code.  Using OF calls after the driver is
bound to the device is generally wrong.  However, they make perfect
sense in the probe hook who's whole purpose is to obtain data about
the device and register it.  The model is actually very simple:

if (dev->platform_data)
      get_platform_data();
else if (dev->of_node)
      get_of_data();

For the actual implementation in this case, my comments reflect what I
think is the clearest implementation.  However, if you'd prefer a
single function call at the start of the probe() hook to return a
flash_partition_data pointer, then I'm okay with that too.

Cheers,
g.

------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev 

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

* Re: [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions
       [not found]                               ` <AANLkTinYYTj+dR6ckPoShHKZTUmENEA1O-DYP9mjnWrs-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2010-08-10 16:01                                 ` Anton Vorontsov
  2010-09-02  8:57                                   ` [spi-devel-general] " Hu Mingkai-B21284
  2010-08-10 17:23                                 ` Joakim Tjernlund
  1 sibling, 1 reply; 26+ messages in thread
From: Anton Vorontsov @ 2010-08-10 16:01 UTC (permalink / raw)
  To: Grant Likely
  Cc: Joakim Tjernlund, kumar.gala-KZfg59tc24xl57MIdRCFDg,
	David Brownell, linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linuxppc-dev-mnsaURCQ41sdnm+yROfE0A@public.gmane.org Mingkai Hu,
	David Woodhouse

On Tue, Aug 10, 2010 at 08:56:42AM -0600, Grant Likely wrote:
[...] 
> The suggestion has been raised to use something like bus notifiers to
> get a hook onto the device registration before the driver is probed so
> that the platform_data can be translated in an separate chuck of code,
> but down that path lies insanity.  There are all kinds of ordering
> issues (like making sure the translation code is called before the
> driver probe code), and it is a lot of complexity for what is really a
> simple thing.

There's another option: platform data handlers (they could be
chained, in case if we want to use several methods of obtaining
platform data, i.e. "try raw data, then ACPI, then OF").

See include/linux/spi/mmc_spi.h (mmc_spi_get_pdata)
and drivers/mmc/host/of_mmc_spi.c.

I think we might implement some library to make these handlers
more generic, but even the simple implementation as in mmc_spi
case proves that it is possible to separate OF/ACPI/DMI/whatever
handling from the generic code.

-- 
Anton Vorontsov
email: cbouatmailru-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
irc://irc.freenode.net/bd2

------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev 

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

* Re: [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions
       [not found]                               ` <AANLkTinYYTj+dR6ckPoShHKZTUmENEA1O-DYP9mjnWrs-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2010-08-10 16:01                                 ` Anton Vorontsov
@ 2010-08-10 17:23                                 ` Joakim Tjernlund
       [not found]                                   ` <OFF5EA512A.075E51C6-ONC125777B.005D9750-C125777B.005F8CAF-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org>
  1 sibling, 1 reply; 26+ messages in thread
From: Joakim Tjernlund @ 2010-08-10 17:23 UTC (permalink / raw)
  To: Grant Likely
  Cc: glikely-s3s/WqlpOiPyB63q8FvJNQ,
	kumar.gala-KZfg59tc24xl57MIdRCFDg, David Brownell,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linuxppc-dev-mnsaURCQ41sdnm+yROfE0A@public.gmane.org Mingkai Hu,
	David Woodhouse

glikely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org wrote on 2010/08/10 16:56:42:
>
> On Tue, Aug 10, 2010 at 2:29 AM, Joakim Tjernlund
> <joakim.tjernlund-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org> wrote:
> >> On Tue, Aug 10, 2010 at 1:14 AM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote:
> >> >
> >> >
> >> > --- On Mon, 8/9/10, Grant Likely <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org> wrote:
> >> >
> >> >
> >> >> > +       nr_parts =
> >> >> of_mtd_parse_partitions(&spi->dev, np, &parts);
> >> >
> >> > Let's keep OF-specific logic out of drivers like
> >> > this one ...  intended to work without OF.
> >> >
> >> > NAK on adding dependencies like OF to drivers
> >> > and other infrastructure that starts generic.
> >
> > Agreed.
> >
> >>
> >> The OF hooks compile to no-ops when CONFIG_OF is disabled.  I've been
> >> very careful about that.
> >
> > OF should not be in the drivers, one should be able use some other method
> > than OF.
>
> If a device is described in the device tree, then the code has to live
> *somewhere* to translate the data from the device tree into a form the
> driver can use.  If not the driver, then where should that code live?
>
> If it is in the machine support code, then that requires foreknowledge
> about all the device specific data that needs to be translated out of
> the device tree at device registration time, which also means that the
> translation code cannot be a module and it nullifies some of the
> advantages of the device tree.  Not to mention the fact that it is
> just plain ugly!  :-)
>
> Some of it can go into the infrastructure code, but only for parsing
> common properties like irqs, address ranges, and some common bindings
> like registering spi and i2c bus child nodes as devices.  (This
> *particular* case may fall into this category if add_mtd_device() was
> able to call the OF partition parsing hook if a device node pointer
> was present; which does make a certain amount of sense, but I defer to
> dwmw2 in this case).  However, device-specific properties cannot be
> parsed in the infrastructure code because the infrastructure has no
> knowledge of device specific bits.

I am no expert at this at all, but I can give you an example what I don't
want. Look at spi_mpc8xxx.c, earlier it was possible to define your own
CS functions and register them from board code. After OF:ication one can
not and the current OF methods aren't expressive enough to do what I need.
The spi subsystem has a general framework for dealing with SPI devices
and I think OF should be built on top of the native methods, at the
very least not disable those methods like spi_mpc8xxx.c does.

I will shut up now :)

  Regards
         Jocke


------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev 

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

* Re: [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions
       [not found]                                   ` <OFF5EA512A.075E51C6-ONC125777B.005D9750-C125777B.005F8CAF-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org>
@ 2010-08-10 18:27                                     ` Grant Likely
       [not found]                                       ` <AANLkTi=EpjPC8Hf6dM1att8Mjg5vmfQxs2=4aUTYTrUL-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 26+ messages in thread
From: Grant Likely @ 2010-08-10 18:27 UTC (permalink / raw)
  To: Joakim Tjernlund
  Cc: kumar.gala-KZfg59tc24xl57MIdRCFDg, David Brownell,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linuxppc-dev-mnsaURCQ41sdnm+yROfE0A@public.gmane.org Mingkai Hu,
	David Woodhouse

On Tue, Aug 10, 2010 at 11:23 AM, Joakim Tjernlund
<joakim.tjernlund-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org> wrote:
> glikely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org wrote on 2010/08/10 16:56:42:
>>
>> On Tue, Aug 10, 2010 at 2:29 AM, Joakim Tjernlund
>> <joakim.tjernlund-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org> wrote:
>> >> On Tue, Aug 10, 2010 at 1:14 AM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote:
>> >> >
>> >> >
>> >> > --- On Mon, 8/9/10, Grant Likely <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org> wrote:
>> >> >
>> >> >
>> >> >> > +       nr_parts =
>> >> >> of_mtd_parse_partitions(&spi->dev, np, &parts);
>> >> >
>> >> > Let's keep OF-specific logic out of drivers like
>> >> > this one ...  intended to work without OF.
>> >> >
>> >> > NAK on adding dependencies like OF to drivers
>> >> > and other infrastructure that starts generic.
>> >
>> > Agreed.
>> >
>> >>
>> >> The OF hooks compile to no-ops when CONFIG_OF is disabled.  I've been
>> >> very careful about that.
>> >
>> > OF should not be in the drivers, one should be able use some other method
>> > than OF.
>>
>> If a device is described in the device tree, then the code has to live
>> *somewhere* to translate the data from the device tree into a form the
>> driver can use.  If not the driver, then where should that code live?
>>
>> If it is in the machine support code, then that requires foreknowledge
>> about all the device specific data that needs to be translated out of
>> the device tree at device registration time, which also means that the
>> translation code cannot be a module and it nullifies some of the
>> advantages of the device tree.  Not to mention the fact that it is
>> just plain ugly!  :-)
>>
>> Some of it can go into the infrastructure code, but only for parsing
>> common properties like irqs, address ranges, and some common bindings
>> like registering spi and i2c bus child nodes as devices.  (This
>> *particular* case may fall into this category if add_mtd_device() was
>> able to call the OF partition parsing hook if a device node pointer
>> was present; which does make a certain amount of sense, but I defer to
>> dwmw2 in this case).  However, device-specific properties cannot be
>> parsed in the infrastructure code because the infrastructure has no
>> knowledge of device specific bits.
>
> I am no expert at this at all, but I can give you an example what I don't
> want. Look at spi_mpc8xxx.c, earlier it was possible to define your own
> CS functions and register them from board code. After OF:ication one can
> not and the current OF methods aren't expressive enough to do what I need.
> The spi subsystem has a general framework for dealing with SPI devices
> and I think OF should be built on top of the native methods, at the
> very least not disable those methods like spi_mpc8xxx.c does.

You're right and it's a problem.  There wasn't a good way to handle
this when powerpc first moved over to use OF.  I think we've got a
good solution now.  See the use of a bus notifier in
arch/powerpc/platforms/512x/pdm360ng.c in Linus' current tree.  Most
of the time that won't be needed, but when a platform specific
callback is required, this seems to be a clean solution.

g.

------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev 

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

* RE: [PATCH v2 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
  2010-08-10  6:40       ` [PATCH v2 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Grant Likely
@ 2010-09-02  8:27         ` Hu Mingkai-B21284
  0 siblings, 0 replies; 26+ messages in thread
From: Hu Mingkai-B21284 @ 2010-09-02  8:27 UTC (permalink / raw)
  To: Grant Likely
  Cc: linuxppc-dev, Gala Kumar-B11780, Zang Roy-R61911, spi-devel-general

Hi Grant and all,

Sorry for the delay, I'm on business trip some weeks ago.

> -----Original Message-----
> From: glikely@secretlab.ca [mailto:glikely@secretlab.ca] On Behalf Of Grant
> Likely
> Sent: Tuesday, August 10, 2010 2:40 PM
> To: Hu Mingkai-B21284
> Cc: linuxppc-dev@ozlabs.org; spi-devel-general@lists.sourceforge.net; Gala
> Kumar-B11780; Zang Roy-R61911
> Subject: Re: [PATCH v2 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI
> controller
> 
> On Mon, Aug 2, 2010 at 1:51 AM, Mingkai Hu <Mingkai.hu@freescale.com> wrote:
> > Refactor the common code in file spi_mpc8xxx.c to spi_fsl_lib.c used
> > by SPI/eSPI controller driver as a library, move the SPI controller
> > driver to a new file spi_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>
> > ---
> > v2:
> >  - Rename spi_mpc8xxx.c to spi_fsl_lib.c, also the config name
> >  - Rename fsl_spi.c to spi_fsl_spi.c, also the config name
> >  - Move register map definiton from spi_fsl_lib.c to spi_fsl_spi.c
> >  - Break some funcions line in the arguments instead of the
> > declaration
> >  - Init bits_per_word to 0 to eliminate the else clause
> >  - Add brace for the else clause to match if clause
> >  - Drop the last entry's comma in the match table
> >  - move module_init() immediately after the init fsl_spi_init()
> > function
> >
> >  drivers/spi/Kconfig       |   20 +-
> >  drivers/spi/Makefile      |    3 +-
> >  drivers/spi/spi_fsl_lib.c |  237 ++++++++
> >  drivers/spi/spi_fsl_lib.h |  119 ++++
> >  drivers/spi/spi_fsl_spi.c | 1173
> > +++++++++++++++++++++++++++++++++++++
> >  drivers/spi/spi_mpc8xxx.c | 1421
> > ---------------------------------------------
> 
> This patch seems pretty good now.  However, the rename from spi_mpc8xxx.c to
> spi_fsl_lib.c should be done in a separate patch.  It is too difficult to track
> what has changed, when the file gets moved at the same time.  Move the file in
> one patch verbatim (with the required Makefile change), and then move out the
> fsl_spi specific bits in a second patch.
> 

Ok, I'll spilt this patch.

Thanks,
Mingkai

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

* RE: [PATCH v2 2/6] eSPI: add eSPI controller support
       [not found]             ` <AANLkTin3W4++cAFcksVBX3QxeV8QF3d5T2tGy_KbEkRs-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2010-09-02  8:28               ` Hu Mingkai-B21284
  0 siblings, 0 replies; 26+ messages in thread
From: Hu Mingkai-B21284 @ 2010-09-02  8:28 UTC (permalink / raw)
  To: Grant Likely
  Cc: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A, Gala Kumar-B11780,
	Zang Roy-R61911,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f



> -----Original Message-----
> From: glikely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org [mailto:glikely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org] On Behalf Of Grant
> Likely
> Sent: Tuesday, August 10, 2010 2:45 PM
> To: Hu Mingkai-B21284
> Cc: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A@public.gmane.org; spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org; Gala
> Kumar-B11780; Zang Roy-R61911
> Subject: Re: [PATCH v2 2/6] eSPI: add eSPI controller support
> 
> On Mon, Aug 2, 2010 at 1:52 AM, Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org> wrote:
> > Add eSPI controller support based on the library code spi_fsl_lib.c.
> >
> > The eSPI controller is newer controller 85xx/Pxxx devices supported.
> > There're some differences comparing to the SPI controller:
> >
> > 1. Has different register map and different bit definition
> >   So leave the code operated the register to the driver code, not
> >   the common code.
> >
> > 2. Support 4 dedicated chip selects
> >   The software can't controll the chip selects directly, The SPCOM[CS]
> >   field is used to select which chip selects is used, and the
> >   SPCOM[TRANLEN] field is set to tell the controller how long the CS
> >   signal need to be asserted. So the driver doesn't need the
> > chipselect
> >   related function when transfering data, just set corresponding
> > register
> >   fields to controll the chipseclect.
> >
> > 3. Different Transmit/Receive FIFO access register behavior
> >   For SPI controller, the Tx/Rx FIFO access register can hold only
> >   one character regardless of the character length, but for eSPI
> >   controller, the register can hold 4 or 2 characters according to
> >   the character lengths. Access the Tx/Rx FIFO access register of the
> >   eSPI controller will shift out/in 4/2 characters one time. For SPI
> >   subsystem, the command and data are put into different transfers, so
> >   we need to combine all the transfers to one transfer in order to
> > pass
> >   the transfer to eSPI controller.
> >
> > Signed-off-by: Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
> 
> I've not dug deep into this patch, but it seems pretty good.  I did notice one
> thing below...
> [...]
> 
> > diff --git a/drivers/spi/spi_fsl_lib.h b/drivers/spi/spi_fsl_lib.h
> > index 774e1c8..0772c98 100644
> > --- a/drivers/spi/spi_fsl_lib.h
> > +++ b/drivers/spi/spi_fsl_lib.h
> > @@ -22,10 +22,12 @@
> >  struct mpc8xxx_spi {
> >        struct device *dev;
> >        struct fsl_spi_reg __iomem *base;
> > +       struct fsl_espi_reg __iomem *espi_base;
> 
> There's got to be a cleaner way to do this.  Rather than putting both pointers
> into mpc8xxx_spi, I suggest each driver use its own fsl_spi_priv and
> fsl_espi_priv wrapper structures that contain the controller specific properties.
> 

Make sense, I'll change it.

Thanks,
Mingkai


------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd

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

* RE: [PATCH v2 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board
       [not found]                             ` <AANLkTinzea7-k3Wd6EsAy+ipThHMhkpMF3pCP7g_6O6J-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2010-09-02  8:30                               ` Hu Mingkai-B21284
  0 siblings, 0 replies; 26+ messages in thread
From: Hu Mingkai-B21284 @ 2010-09-02  8:30 UTC (permalink / raw)
  To: Grant Likely
  Cc: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A, Gala Kumar-B11780,
	Zang Roy-R61911,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f



> -----Original Message-----
> From: glikely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org [mailto:glikely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org] On Behalf Of Grant
> Likely
> Sent: Tuesday, August 10, 2010 3:11 PM
> To: Hu Mingkai-B21284
> Cc: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A@public.gmane.org; spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org; Gala
> Kumar-B11780; Zang Roy-R61911
> Subject: Re: [PATCH v2 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds
> and mpc8536ds board
> 
> Hi Mingkai,
> 
> one comment below.  Otherwise this patch looks good, and so does patch 5.
> 
> g.
> 
> On Mon, Aug 2, 2010 at 1:52 AM, Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org> wrote:
> > Signed-off-by: Mingkai Hu <Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
> > ---
> >
> > v2:
> >  - Remove the whitespace inconsitencies
> >
> >  arch/powerpc/boot/dts/mpc8536ds.dts |   52
> > +++++++++++++++++++++++++++++++++++
> >  arch/powerpc/boot/dts/p4080ds.dts   |   11 +++-----
> >  2 files changed, 56 insertions(+), 7 deletions(-)
> >
> > diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts
> > b/arch/powerpc/boot/dts/mpc8536ds.dts
> > index 815cebb..a75c10e 100644
> > --- a/arch/powerpc/boot/dts/mpc8536ds.dts
> > +++ b/arch/powerpc/boot/dts/mpc8536ds.dts
> > @@ -108,6 +108,58 @@
> >                        };
> >                };
> >
> > +               spi@7000 {
> > +                       #address-cells = <1>;
> > +                       #size-cells = <0>;
> > +                       compatible = "fsl,mpc8536-espi";
> > +                       reg = <0x7000 0x1000>;
> > +                       interrupts = <59 0x2>;
> > +                       interrupt-parent = <&mpic>;
> > +                       fsl,espi-num-chipselects = <4>;
> > +
> > +                       flash@0 {
> > +                               #address-cells = <1>;
> > +                               #size-cells = <1>;
> > +                               compatible = "spansion,s25sl12801";
> > +                               reg = <0>;
> > +                               spi-max-frequency = <40000000>;
> > +                               partition@u-boot {
> > +                                       label = "u-boot";
> > +                                       reg = <0x00000000 0x00100000>;
> > +                                       read-only;
> > +                               };
> > +                               partition@kernel {
> > +                                       label = "kernel";
> > +                                       reg = <0x00100000 0x00500000>;
> > +                                       read-only;
> > +                               };
> > +                               partition@dtb {
> > +                                       label = "dtb";
> > +                                       reg = <0x00600000 0x00100000>;
> > +                                       read-only;
> > +                               };
> > +                               partition@fs {
> > +                                       label = "file system";
> > +                                       reg = <0x00700000 0x00900000>;
> > +                               };
> > +                       };
> > +                       flash@1 {
> > +                               compatible = "spansion,s25sl12801";
> > +                               reg = <1>;
> > +                               spi-max-frequency = <40000000>;
> > +                       };
> > +                       flash@2 {
> > +                               compatible = "spansion,s25sl12801";
> > +                               reg = <2>;
> > +                               spi-max-frequency = <40000000>;
> > +                       };
> > +                       flash@3 {
> > +                               compatible = "spansion,s25sl12801";
> > +                               reg = <3>;
> > +                               spi-max-frequency = <40000000>;
> > +                       };
> > +               };
> > +
> >                dma@21300 {
> >                        #address-cells = <1>;
> >                        #size-cells = <1>; diff --git
> > a/arch/powerpc/boot/dts/p4080ds.dts
> > b/arch/powerpc/boot/dts/p4080ds.dts
> > index 6b29eab..48437ad 100644
> > --- a/arch/powerpc/boot/dts/p4080ds.dts
> > +++ b/arch/powerpc/boot/dts/p4080ds.dts
> > @@ -236,22 +236,19 @@
> >                };
> >
> >                spi@110000 {
> > -                       cell-index = <0>;
> >                        #address-cells = <1>;
> >                        #size-cells = <0>;
> > -                       compatible = "fsl,espi";
> > +                       compatible = "fsl,mpc8536-espi";
> 
> Should be more specific here by specifying the exact device; plus a list of what
> it is compatible with.  For example:
> 
> compatible = "fsl,p4080-espi", "fsl,mpc5836-espi";
> 
> the reason for this is that the driver for the existing part is still able to
> bind against the node, but if it ever needs it, then information about the
> specific device is available which can be used to (for example) figure out when
> to enable silicon bug workarounds.
> 

Make sense, I'll add it.

Thanks,
Mingkai


------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd

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

* RE: [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions
       [not found]                                       ` <AANLkTi=EpjPC8Hf6dM1att8Mjg5vmfQxs2=4aUTYTrUL-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2010-09-02  8:46                                         ` Hu Mingkai-B21284
  0 siblings, 0 replies; 26+ messages in thread
From: Hu Mingkai-B21284 @ 2010-09-02  8:46 UTC (permalink / raw)
  To: Grant Likely, Joakim Tjernlund
  Cc: David Brownell, linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Gala Kumar-B11780, David Woodhouse,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f



> -----Original Message-----
> From: glikely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org [mailto:glikely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org] On Behalf Of Grant
> Likely
> Sent: Wednesday, August 11, 2010 2:27 AM
> To: Joakim Tjernlund
> Cc: David Brownell; David Woodhouse; Gala Kumar-B11780; linux-
> mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org; Hu Mingkai-B21284; spi-devel-
> general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
> Subject: Re: [spi-devel-general] [PATCH v2 3/6] mtd: m25p80: add support to
> parse the SPI flash's partitions
> 
> On Tue, Aug 10, 2010 at 11:23 AM, Joakim Tjernlund
> <joakim.tjernlund-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org> wrote:
> > glikely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org wrote on 2010/08/10 16:56:42:
> >>
> >> On Tue, Aug 10, 2010 at 2:29 AM, Joakim Tjernlund
> >> <joakim.tjernlund-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org> wrote:
> >> >> On Tue, Aug 10, 2010 at 1:14 AM, David Brownell <david-b-yBeKhBN/0LBNg+MwTxZMZA@public.gmane.orgt>
> wrote:
> >> >> >
> >> >> >
> >> >> > --- On Mon, 8/9/10, Grant Likely <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org> wrote:
> >> >> >
> >> >> >
> >> >> >> > +       nr_parts =
> >> >> >> of_mtd_parse_partitions(&spi->dev, np, &parts);
> >> >> >
> >> >> > Let's keep OF-specific logic out of drivers like this one ...
> >> >> > intended to work without OF.
> >> >> >
> >> >> > NAK on adding dependencies like OF to drivers and other
> >> >> > infrastructure that starts generic.
> >> >
> >> > Agreed.
> >> >
> >> >>
> >> >> The OF hooks compile to no-ops when CONFIG_OF is disabled.  I've
> >> >> been very careful about that.
> >> >
> >> > OF should not be in the drivers, one should be able use some other
> >> > method than OF.
> >>
> >> If a device is described in the device tree, then the code has to
> >> live
> >> *somewhere* to translate the data from the device tree into a form
> >> the driver can use.  If not the driver, then where should that code live?
> >>
> >> If it is in the machine support code, then that requires
> >> foreknowledge about all the device specific data that needs to be
> >> translated out of the device tree at device registration time, which
> >> also means that the translation code cannot be a module and it
> >> nullifies some of the advantages of the device tree.  Not to mention
> >> the fact that it is just plain ugly!  :-)
> >>
> >> Some of it can go into the infrastructure code, but only for parsing
> >> common properties like irqs, address ranges, and some common bindings
> >> like registering spi and i2c bus child nodes as devices.  (This
> >> *particular* case may fall into this category if add_mtd_device() was
> >> able to call the OF partition parsing hook if a device node pointer
> >> was present; which does make a certain amount of sense, but I defer
> >> to
> >> dwmw2 in this case).  However, device-specific properties cannot be
> >> parsed in the infrastructure code because the infrastructure has no
> >> knowledge of device specific bits.
> >
> > I am no expert at this at all, but I can give you an example what I
> > don't want. Look at spi_mpc8xxx.c, earlier it was possible to define
> > your own CS functions and register them from board code. After
> > OF:ication one can not and the current OF methods aren't expressive enough to
> do what I need.
> > The spi subsystem has a general framework for dealing with SPI devices
> > and I think OF should be built on top of the native methods, at the
> > very least not disable those methods like spi_mpc8xxx.c does.
> 
> You're right and it's a problem.  There wasn't a good way to handle this when
> powerpc first moved over to use OF.  I think we've got a good solution now.  See
> the use of a bus notifier in arch/powerpc/platforms/512x/pdm360ng.c in Linus'
> current tree.  Most of the time that won't be needed, but when a platform
> specific callback is required, this seems to be a clean solution.
> 

Thanks for your valuable suggestion, but where should I put the bus_register_notifier?
On the drivers/mtd/devices/m25p80.c or drivers/spi/spi.c? I think it should add in the 
flash driver m25p80.c, but it looks like the notifier function will be called many times.
How does it happen?

Here is my demo code patch:
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -753,6 +753,34 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
 }

+static int m25p80_notifier_call(struct notifier_block *nb,
+                                       unsigned long event, void *__dev)
+{
+       printk("%s %d event = 0x%x:\n", __func__, __LINE__, event);
+       switch (event) {
+       case BUS_NOTIFY_ADD_DEVICE:
+               printk("BUS_NOTIFY_ADD_DEVICE\n");
+               break;
+       case BUS_NOTIFY_DEL_DEVICE:
+               printk("BUS_NOTIFY_DEL_DEVICE\n");
+               break;
+       case BUS_NOTIFY_BOUND_DRIVER:
+               printk("BUS_NOTIFY_BOUND_DRIVER\n");
+               break;
+       case BUS_NOTIFY_UNBIND_DRIVER:
+               printk("BUS_NOTIFY_UNBIND_DRIVER\n");
+               break;
+       case BUS_NOTIFY_UNBOUND_DRIVER:
+               printk("BUS_NOTIFY_UNBOUND_DRIVER\n");
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block m25p80_nb = {
+       .notifier_call = m25p80_notifier_call,
+};
+
 /*
  * board specific setup should have ensured the SPI clock used here
  * matches what the READ command supports, at least until this driver
@@ -766,6 +794,8 @@ static int __devinit m25p_probe(struct spi_device *spi)
        struct flash_info               *info;
        unsigned                        i;

+       bus_register_notifier(&spi_bus_type, &m25p80_nb);
+


Thanks,
Mingkai


------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd

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

* RE: [spi-devel-general] [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions
  2010-08-10 16:01                                 ` Anton Vorontsov
@ 2010-09-02  8:57                                   ` Hu Mingkai-B21284
  0 siblings, 0 replies; 26+ messages in thread
From: Hu Mingkai-B21284 @ 2010-09-02  8:57 UTC (permalink / raw)
  To: Anton Vorontsov, Grant Likely
  Cc: Joakim Tjernlund, David Brownell, linux-mtd, spi-devel-general,
	Gala Kumar-B11780, David Woodhouse



> -----Original Message-----
> From: Anton Vorontsov [mailto:cbouatmailru@gmail.com]
> Sent: Wednesday, August 11, 2010 12:02 AM
> To: Grant Likely
> Cc: Joakim Tjernlund; Gala Kumar-B11780; David Brownell; linux-
> mtd@lists.infradead.org; spi-devel-general@lists.sourceforge.net; Hu Mingkai-
> B21284; David Woodhouse
> Subject: Re: [spi-devel-general] [PATCH v2 3/6] mtd: m25p80: add support to
> parse the SPI flash's partitions
> 
> On Tue, Aug 10, 2010 at 08:56:42AM -0600, Grant Likely wrote:
> [...]
> > The suggestion has been raised to use something like bus notifiers to
> > get a hook onto the device registration before the driver is probed so
> > that the platform_data can be translated in an separate chuck of code,
> > but down that path lies insanity.  There are all kinds of ordering
> > issues (like making sure the translation code is called before the
> > driver probe code), and it is a lot of complexity for what is really a
> > simple thing.
> 
> There's another option: platform data handlers (they could be chained, in case
> if we want to use several methods of obtaining platform data, i.e. "try raw data,
> then ACPI, then OF").
> 
> See include/linux/spi/mmc_spi.h (mmc_spi_get_pdata) and
> drivers/mmc/host/of_mmc_spi.c.
> 
> I think we might implement some library to make these handlers more generic, but
> even the simple implementation as in mmc_spi case proves that it is possible to
> separate OF/ACPI/DMI/whatever handling from the generic code.
> 

It's also a good suggestion, I'll try it.

Thanks,
Mingkai
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* RE: [PATCH v2 4/6] mtd: m25p80: add a read function to read page by page
  2010-08-10  7:00                   ` [PATCH v2 4/6] mtd: m25p80: add a read function to read page by page Grant Likely
  2010-08-10 13:44                     ` [spi-devel-general] " David Brownell
@ 2010-09-02  9:04                     ` Hu Mingkai-B21284
  1 sibling, 0 replies; 26+ messages in thread
From: Hu Mingkai-B21284 @ 2010-09-02  9:04 UTC (permalink / raw)
  To: Grant Likely, David Woodhouse
  Cc: linuxppc-dev, Gala Kumar-B11780, linux-mtd, Zang Roy-R61911,
	spi-devel-general

[adding mtd list]

Hi guys,

Could you please take a look at this patch and give some suggestion?

Thanks,
Mingkai

> -----Original Message-----
> From: glikely@secretlab.ca [mailto:glikely@secretlab.ca] On Behalf Of Grant
> Likely
> Sent: Tuesday, August 10, 2010 3:00 PM
> To: Hu Mingkai-B21284; David Woodhouse
> Cc: linuxppc-dev@ozlabs.org; spi-devel-general@lists.sourceforge.net; Gala
> Kumar-B11780; Zang Roy-R61911
> Subject: Re: [PATCH v2 4/6] mtd: m25p80: add a read function to read page by
> page
> 
> [adding David Woodhouse]
> 
> (Btw, you should cc: David Woodhouse and the mtd list on the MTD patches).
> 
> On Mon, Aug 2, 2010 at 1:52 AM, Mingkai Hu <Mingkai.hu@freescale.com> wrote:
> > For Freescale's eSPI controller, the max transaction length one time
> > is limitted by the SPCOM[TRANSLEN] field which is 0xFFFF. When used
> > mkfs.ext2 command to create ext2 filesystem on the flash, the read
> > length will exceed the max value of the SPCOM[TRANSLEN] field, so
> > change the read function to read page by page.
> >
> > For other SPI flash driver, also needed to supply the read function if
> > used the eSPI controller.
> >
> > Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> 
> This one bothers me, but I can't put my finger on it.  The flag feels like a
> controller specific hack.  David, can you take a look at this patch?
> 
> g.
> 
> > ---
> >
> > v2:
> >  - Add SPI_MASTER_TRANS_LIMIT flag to indicate the master's trans
> > length
> >   limitation, so the MTD driver can select the correct transfer
> > behaviour
> >   at driver probe time
> >
> >  drivers/mtd/devices/m25p80.c |   78
> > ++++++++++++++++++++++++++++++++++++++++++
> >  drivers/spi/spi_fsl_espi.c   |    1 +
> >  include/linux/spi/spi.h      |    1 +
> >  3 files changed, 80 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/mtd/devices/m25p80.c
> > b/drivers/mtd/devices/m25p80.c index 5f00075..30e4568 100644
> > --- a/drivers/mtd/devices/m25p80.c
> > +++ b/drivers/mtd/devices/m25p80.c
> > @@ -376,6 +376,81 @@ static int m25p80_read(struct mtd_info *mtd,
> > loff_t from, size_t len,
> >  }
> >
> >  /*
> > + * Read an address range from the flash chip page by page.
> > + * Some controller has transaction length limitation such as the
> > + * Freescale's eSPI controller can only trasmit 0xFFFF bytes one
> > + * time, so we have to read page by page if the len is more than
> > + * the limitation.
> > + */
> > +static int m25p80_page_read(struct mtd_info *mtd, loff_t from, size_t
> > +len,
> > +       size_t *retlen, u_char *buf)
> > +{
> > +       struct m25p *flash = mtd_to_m25p(mtd);
> > +       struct spi_transfer t[2];
> > +       struct spi_message m;
> > +       u32 i, page_size = 0;
> > +
> > +       DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
> > +                       dev_name(&flash->spi->dev), __func__, "from",
> > +                       (u32)from, len);
> > +
> > +       /* sanity checks */
> > +       if (!len)
> > +               return 0;
> > +
> > +       if (from + len > flash->mtd.size)
> > +               return -EINVAL;
> > +
> > +       spi_message_init(&m);
> > +       memset(t, 0, (sizeof t));
> > +
> > +       /* NOTE:
> > +        * OPCODE_FAST_READ (if available) is faster.
> > +        * Should add 1 byte DUMMY_BYTE.
> > +        */
> > +       t[0].tx_buf = flash->command;
> > +       t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
> > +       spi_message_add_tail(&t[0], &m);
> > +
> > +       t[1].rx_buf = buf;
> > +       spi_message_add_tail(&t[1], &m);
> > +
> > +       /* Byte count starts at zero. */
> > +       if (retlen)
> > +               *retlen = 0;
> > +
> > +       mutex_lock(&flash->lock);
> > +
> > +       /* Wait till previous write/erase is done. */
> > +       if (wait_till_ready(flash)) {
> > +               /* REVISIT status return?? */
> > +               mutex_unlock(&flash->lock);
> > +               return 1;
> > +       }
> > +
> > +       /* Set up the write data buffer. */
> > +       flash->command[0] = OPCODE_READ;
> > +
> > +       for (i = page_size; i < len; i += page_size) {
> > +               page_size = len - i;
> > +               if (page_size > flash->page_size)
> > +                       page_size = flash->page_size;
> > +               m25p_addr2cmd(flash, from + i, flash->command);
> > +               t[1].len = page_size;
> > +               t[1].rx_buf = buf + i;
> > +
> > +               spi_sync(flash->spi, &m);
> > +
> > +               *retlen += m.actual_length - m25p_cmdsz(flash)
> > +                       - FAST_READ_DUMMY_BYTE;
> > +       }
> > +
> > +       mutex_unlock(&flash->lock);
> > +
> > +       return 0;
> > +}
> > +
> > +/*
> >  * Write an address range to the flash chip.  Data must be written in
> >  * FLASH_PAGESIZE chunks.  The address range may be any size provided
> >  * it is within the physical boundaries.
> > @@ -877,6 +952,9 @@ static int __devinit m25p_probe(struct spi_device
> > *spi)
> >        flash->mtd.erase = m25p80_erase;
> >        flash->mtd.read = m25p80_read;
> >
> > +       if (spi->master->flags & SPI_MASTER_TRANS_LIMIT)
> > +               flash->mtd.read = m25p80_page_read;
> > +
> >        /* sst flash chips use AAI word program */
> >        if (info->jedec_id >> 16 == 0xbf)
> >                flash->mtd.write = sst_write; diff --git
> > a/drivers/spi/spi_fsl_espi.c b/drivers/spi/spi_fsl_espi.c index
> > 61987cf..e15b7dc 100644
> > --- a/drivers/spi/spi_fsl_espi.c
> > +++ b/drivers/spi/spi_fsl_espi.c
> > @@ -470,6 +470,7 @@ static struct spi_master * __devinit
> > fsl_espi_probe(struct device *dev,
> >                goto err_probe;
> >
> >        master->setup = fsl_espi_setup;
> > +       master->flags = SPI_MASTER_TRANS_LIMIT;
> >
> >        mpc8xxx_spi = spi_master_get_devdata(master);
> >        mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg; diff --git
> > a/include/linux/spi/spi.h b/include/linux/spi/spi.h index
> > af56071..0729cbd 100644
> > --- a/include/linux/spi/spi.h
> > +++ b/include/linux/spi/spi.h
> > @@ -261,6 +261,7 @@ struct spi_master {
> >  #define SPI_MASTER_HALF_DUPLEX BIT(0)          /* can't do full
> > duplex */
> >  #define SPI_MASTER_NO_RX       BIT(1)          /* can't do buffer
> > read */
> >  #define SPI_MASTER_NO_TX       BIT(2)          /* can't do buffer
> > write */
> > +#define SPI_MASTER_TRANS_LIMIT BIT(3)          /* have trans length
> > +limit */
> >
> >        /* Setup mode and clock, etc (spi driver may call many times).
> >         *
> > --
> > 1.6.4
> >
> >
> >
> 
> 
> 
> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.

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

end of thread, other threads:[~2010-09-02  9:04 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-02  7:51 [PATCH v2 0/6] refactor spi_mpc8xxx.c and add eSPI controller support Mingkai Hu
     [not found] ` <1280735524-17547-1-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2010-08-02  7:51   ` [PATCH v2 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Mingkai Hu
     [not found]     ` <1280735524-17547-2-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2010-08-02  7:52       ` [PATCH v2 2/6] eSPI: add eSPI controller support Mingkai Hu
     [not found]         ` <1280735524-17547-3-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2010-08-02  7:52           ` [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions Mingkai Hu
     [not found]             ` <1280735524-17547-4-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2010-08-02  7:52               ` [PATCH v2 4/6] mtd: m25p80: add a read function to read page by page Mingkai Hu
     [not found]                 ` <1280735524-17547-5-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2010-08-02  7:52                   ` [PATCH v2 5/6] powerpc/of: add eSPI controller dts bindings Mingkai Hu
     [not found]                     ` <1280735524-17547-6-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2010-08-02  7:52                       ` [PATCH v2 6/6] DTS: add SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board Mingkai Hu
     [not found]                         ` <1280735524-17547-7-git-send-email-Mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2010-08-10  7:10                           ` Grant Likely
     [not found]                             ` <AANLkTinzea7-k3Wd6EsAy+ipThHMhkpMF3pCP7g_6O6J-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-09-02  8:30                               ` Hu Mingkai-B21284
2010-08-10  7:00                   ` [PATCH v2 4/6] mtd: m25p80: add a read function to read page by page Grant Likely
2010-08-10 13:44                     ` [spi-devel-general] " David Brownell
2010-09-02  9:04                     ` Hu Mingkai-B21284
2010-08-10  6:56               ` [PATCH v2 3/6] mtd: m25p80: add support to parse the SPI flash's partitions Grant Likely
2010-08-10  7:14                 ` [spi-devel-general] " David Brownell
     [not found]                   ` <796604.30863.qm-g47maUHHHF9eqboJWQvT7/u2YVrzzGjVVpNB7YpNyf8@public.gmane.org>
2010-08-10  7:16                     ` Grant Likely
     [not found]                       ` <AANLkTi=FGf9gbWDkO4qs01Z+qkip+Zm11=Jc4wHu3G8b-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-08-10  8:29                         ` Joakim Tjernlund
     [not found]                           ` <OF0D24DC16.E1FE65D2-ONC125777B.002E544A-C125777B.002EA7C2-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org>
2010-08-10 14:56                             ` Grant Likely
     [not found]                               ` <AANLkTinYYTj+dR6ckPoShHKZTUmENEA1O-DYP9mjnWrs-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-08-10 16:01                                 ` Anton Vorontsov
2010-09-02  8:57                                   ` [spi-devel-general] " Hu Mingkai-B21284
2010-08-10 17:23                                 ` Joakim Tjernlund
     [not found]                                   ` <OFF5EA512A.075E51C6-ONC125777B.005D9750-C125777B.005F8CAF-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org>
2010-08-10 18:27                                     ` Grant Likely
     [not found]                                       ` <AANLkTi=EpjPC8Hf6dM1att8Mjg5vmfQxs2=4aUTYTrUL-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-09-02  8:46                                         ` Hu Mingkai-B21284
2010-08-10  6:44           ` [PATCH v2 2/6] eSPI: add eSPI controller support Grant Likely
     [not found]             ` <AANLkTin3W4++cAFcksVBX3QxeV8QF3d5T2tGy_KbEkRs-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-09-02  8:28               ` Hu Mingkai-B21284
2010-08-10  6:40       ` [PATCH v2 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller Grant Likely
2010-09-02  8:27         ` 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).