LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] i2c: adapt i2c_ram struct according to MPC8272 manual
From: Holger brunck @ 2010-07-23 15:22 UTC (permalink / raw)
  To: linuxppc-dev

Additionaly to the MPC8260, the MPC8272 I2C PRAM memory map
has an additional entry for the SDMATMP (word). This patch
adds this at offset 0x34 to the i2c_ram struct.

Signed-off-by: Holger Brunck <holger.brunck@keymile.com>
---
 drivers/i2c/busses/i2c-cpm.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index a6dbfb1..95d204f 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -77,7 +77,8 @@ struct i2c_ram {
 	uint    txtmp;		/* Internal */
 	char    res1[4];	/* Reserved */
 	ushort  rpbase;		/* Relocation pointer */
-	char    res2[2];	/* Reserved */
+	char    res2[6];	/* Reserved */
+	uint    sdmatmp;	/* Internal */
 };

 #define I2COM_START	0x80
-- 
1.7.0.5

^ permalink raw reply related

* problems flashing custom board
From: moises dominguez @ 2010-07-23 15:43 UTC (permalink / raw)
  To: linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 1307 bytes --]

Hi,

I am having problems programming u-boot(from ltib) in ads5121 based custom
board with CodeWarrior USB TAP(sector not erased). I hope you could help me.

Instead of 64 MB NOR flash(2xS29-GL256P) I am using a 16 MB (S29-GL128P) in
muxed-mode. I have choosen 5121ADS_init_sram_flash.cfg as base file, and
modified flash size and configuration on this way:
..
- writemem.l 0x80000020 0xfc00fcff     // CS0 from 0xfc00_0000 to
0xfcff_ffff, 16 MB flash
- writemem.l 0x80010000 0x05059110 //16 bit data, muxed mode
...

I have doubts about RST_CONF_LOC and RST_CONF_BMS; afaik, this two bits
select where u-boot should be programed, am I wrong? but, according
RST_CONF_BMS description there are only two boot start possible address for
CS0:
- 0x0000_0000 if BMS=0
- 0XFFF0_0000 if BMS=1 (as in eval. board).

But, if I map my flash to 0xfc00_0000.. it does not reach oxfff0_0000.. I
tried to map it to 0x0000_0000 (where SRAM is according cfg) and SRAM to
0xfc00_0000 but  I got : flash ID error (as if flash driver could not be
loaded?) Can u-boot be programed to any flash position? and .. can SRAM not
be mapped to any position different to cero?

I read too that we should change TEXT_BASE u-boot macro. I changed it to
0xFC00_0000 that is where I want to have u-boot.. but no success.

Regards,

Moises.

[-- Attachment #2: Type: text/html, Size: 1388 bytes --]

^ permalink raw reply

* Re: [PATCH][v2] powerpc: rename immap_86xx.h to fsl_guts.h, and add 85xx support
From: Liam Girdwood @ 2010-07-23 18:10 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev, alsa-devel, Mark Brown, Timur Tabi
In-Reply-To: <84CE2602-9E81-473B-8E5F-4F4AD0E07484@freescale.com>

On Thu, 2010-07-22 at 13:43 -0500, Kumar Gala wrote:
> On Jul 22, 2010, at 11:49 AM, Mark Brown wrote:
> 
> > On Thu, Jul 22, 2010 at 11:33:30AM -0500, Timur Tabi wrote:
> >> The immap_86xx.h header file only defines one data structure: the "global
> >> utilities" register set found on Freescale PowerPC SOCs.  Rename this file
> >> to fsl_guts.h to reflect its true purpose, and extend it to cover the "GUTS"
> >> register set on 85xx chips.
> >> 
> >> Signed-off-by: Timur Tabi <timur@freescale.com>
> > 
> > Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> 
> Acked-by: Kumar Gala <galak@kernel.crashing.org>
> 
> - k

Applied.

Thanks

Liam
-- 
Freelance Developer, SlimLogic Ltd
ASoC and Voltage Regulator Maintainer.
http://www.slimlogic.co.uk

^ permalink raw reply

* [PATCH][v2] fix of_flat_dt_is_compatible to match the full compatible string
From: Stuart Yoder @ 2010-07-23 18:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Stuart Yoder

From: Stuart Yoder <stuart.yoder@freescale.com>

With the previous string comparison, a device tree
compatible of "foo-bar" would match as compatible
with a driver looking for "foo".

Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com>
---
 drivers/of/fdt.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index dee4fb5..28c0c2b 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -169,7 +169,7 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
 	if (cp == NULL)
 		return 0;
 	while (cplen > 0) {
-		if (strncasecmp(cp, compat, strlen(compat)) == 0)
+		if (!strcasecmp(cp, compat))
 			return 1;
 		l = strlen(cp) + 1;
 		cp += l;
-- 
1.6.2.5

^ permalink raw reply related

* Re: [PATCH] Adding ADMA support for PPC460EX DMA engine.
From: Dan Williams @ 2010-07-23 19:21 UTC (permalink / raw)
  To: Stefan Roese; +Cc: linux-raid, linuxppc-dev, linux-crypto, tmarri
In-Reply-To: <201007230815.14464.sr@denx.de>

On Thu, Jul 22, 2010 at 11:15 PM, Stefan Roese <sr@denx.de> wrote:
> Hi Marri,
>
> On Friday 23 July 2010 02:57:18 tmarri@amcc.com wrote:
>> From: Tirumala Marri <tmarri@amcc.com>
>>
>> =A0 This patch will add ADMA support for DMA engine and HW offload for
>> =A0 XOR/ADG (RAID-5/6) functionalities.
>> =A0 1. It supports memcpy, xor, GF(2) based RAID-6.
>> =A0 2. It supports interrupt based DMA completions.
>> =A0 3. Also supports memcpy in RAID-1 case.
>>
>> =A0 Kernel version: 2.6.35-rc5
>>
>> =A0 Testing:
>> =A0 =A0 Created RAID-5/6 arrays usign mdadm.
>> =A0 =A0 And ran raw IO and filesystem IO to the RAID array.
>> =A0 =A0 Chunk size 4k,64k was tested.
>> =A0 =A0 RAID rebuild , disk fail, resync tested.
>>
>> =A0 File names:
>> =A0 =A0 This code is similar to ppc440spe . So I named the files as
>> =A0 =A0 drivers/dma/ppc4xx/adma1.c and drivers/dma/ppc4xx/adma1.h
>
> As you describe above, a lot of the code seems to be copied from
> drivers/dma/ppc4xx/adma.c/h. Wouldn't it make more sense to factor out th=
e
> common code instead of duplicating it?
>

Yes, and you might look to drivers/dma/iop-adma.c as an example of a
way to support similar hardware with a single code base.

--
Dan

^ permalink raw reply

* [PATCH] of: make of_find_device_by_node generic
From: Grant Likely @ 2010-07-23 20:02 UTC (permalink / raw)
  To: jonas, monstr, microblaze-uclinux, linux-kernel, linuxppc-dev,
	benh, sparclinux, davem

From: Jonas Bonn <jonas@southpole.se>

There's no need for this function to be architecture specific and all four
architectures defining it had the same definition.  The function has been
moved to drivers/of/platform.c.

Signed-off-by: Jonas Bonn <jonas@southpole.se>
[grant.likely@secretlab.ca: moved to drivers/of/platform.c, simplified code, and added kerneldoc comment]
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
 arch/microblaze/kernel/of_platform.c |   16 ----------------
 arch/powerpc/kernel/of_platform.c    |   16 ----------------
 arch/sparc/kernel/of_device_common.c |   20 --------------------
 drivers/of/platform.c                |   20 ++++++++++++++++++++
 4 files changed, 20 insertions(+), 52 deletions(-)

diff --git a/arch/microblaze/kernel/of_platform.c b/arch/microblaze/kernel/of_platform.c
index c664b27..6cffadb 100644
--- a/arch/microblaze/kernel/of_platform.c
+++ b/arch/microblaze/kernel/of_platform.c
@@ -47,19 +47,3 @@ const struct of_device_id of_default_bus_ids[] = {
 	{ .type = "simple", },
 	{},
 };
-
-static int of_dev_node_match(struct device *dev, void *data)
-{
-	return to_platform_device(dev)->dev.of_node == data;
-}
-
-struct platform_device *of_find_device_by_node(struct device_node *np)
-{
-	struct device *dev;
-
-	dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match);
-	if (dev)
-		return to_platform_device(dev);
-	return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_node);
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index 84439d1..760a7af 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -52,22 +52,6 @@ const struct of_device_id of_default_bus_ids[] = {
 	{},
 };
 
-static int of_dev_node_match(struct device *dev, void *data)
-{
-	return to_platform_device(dev)->dev.of_node == data;
-}
-
-struct platform_device *of_find_device_by_node(struct device_node *np)
-{
-	struct device *dev;
-
-	dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match);
-	if (dev)
-		return to_platform_device(dev);
-	return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_node);
-
 #ifdef CONFIG_PPC_OF_PLATFORM_PCI
 
 /* The probing of PCI controllers from of_platform is currently
diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c
index e80729b..49ddff5 100644
--- a/arch/sparc/kernel/of_device_common.c
+++ b/arch/sparc/kernel/of_device_common.c
@@ -11,26 +11,6 @@
 
 #include "of_device_common.h"
 
-static int node_match(struct device *dev, void *data)
-{
-	struct platform_device *op = to_platform_device(dev);
-	struct device_node *dp = data;
-
-	return (op->dev.of_node == dp);
-}
-
-struct platform_device *of_find_device_by_node(struct device_node *dp)
-{
-	struct device *dev = bus_find_device(&platform_bus_type, NULL,
-					     dp, node_match);
-
-	if (dev)
-		return to_platform_device(dev);
-
-	return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_node);
-
 unsigned int irq_of_parse_and_map(struct device_node *node, int index)
 {
 	struct platform_device *op = of_find_device_by_node(node);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 9b2d5b1..9126064 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -22,6 +22,26 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 
+static int of_dev_node_match(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+/**
+ * of_find_device_by_node - Find the platform_device associated with a node
+ * @np: Pointer to device tree node
+ *
+ * Returns platform_device pointer, or NULL if not found
+ */
+struct platform_device *of_find_device_by_node(struct device_node *np)
+{
+	struct device *dev;
+
+	dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match);
+	return dev ? to_platform_device(dev) : NULL;
+}
+EXPORT_SYMBOL(of_find_device_by_node);
+
 static int platform_driver_probe_shim(struct platform_device *pdev)
 {
 	struct platform_driver *pdrv;

^ permalink raw reply related

* [PATCH] of: remove of_default_bus_ids
From: Grant Likely @ 2010-07-23 20:02 UTC (permalink / raw)
  To: jonas, monstr, microblaze-uclinux, linux-kernel, linuxppc-dev,
	benh

From: Jonas Bonn <jonas@southpole.se>

This list used was by only two platforms with all other platforms defining an
own list of valid bus id's to pass to of_platform_bus_probe.  This patch:

i)   copies the default list to the two platforms that depended on it (powerpc)
ii)  remove the usage of of_default_bus_ids in of_platform_bus_probe
iii) removes the definition of the list from all architectures that defined it

Passing a NULL 'matches' parameter to of_platform_bus_probe is still valid; the
function returns no error in that case as the NULL value is equivalent to an
empty list.

Signed-off-by: Jonas Bonn <jonas@southpole.se>
[grant.likely@secretlab.ca: added __initdata annotations, warn on and return error on missing match table, and fix whitespace errors]
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
 arch/microblaze/kernel/Makefile           |    2 +
 arch/microblaze/kernel/of_platform.c      |   49 -----------------------------
 arch/powerpc/kernel/of_platform.c         |   24 --------------
 arch/powerpc/platforms/cell/qpace_setup.c |   14 ++++++++
 arch/powerpc/platforms/cell/setup.c       |   14 ++++++++
 drivers/of/platform.c                     |    4 +-
 include/linux/of_platform.h               |    2 -
 7 files changed, 28 insertions(+), 81 deletions(-)
 delete mode 100644 arch/microblaze/kernel/of_platform.c

diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile
index 727e2cb..7fcc5f7 100644
--- a/arch/microblaze/kernel/Makefile
+++ b/arch/microblaze/kernel/Makefile
@@ -16,7 +16,7 @@ extra-y := head.o vmlinux.lds
 
 obj-y += dma.o exceptions.o \
 	hw_exception_handler.o init_task.o intc.o irq.o \
-	of_platform.o process.o prom.o prom_parse.o ptrace.o \
+	process.o prom.o prom_parse.o ptrace.o \
 	setup.o signal.o sys_microblaze.o timer.o traps.o reset.o
 
 obj-y += cpu/
diff --git a/arch/microblaze/kernel/of_platform.c b/arch/microblaze/kernel/of_platform.c
deleted file mode 100644
index 6cffadb..0000000
--- a/arch/microblaze/kernel/of_platform.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
- *			 <benh@kernel.crashing.org>
- *    and		 Arnd Bergmann, IBM Corp.
- *
- *  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.
- *
- */
-
-#undef DEBUG
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/pci.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-
-#include <linux/errno.h>
-#include <linux/topology.h>
-#include <asm/atomic.h>
-
-/*
- * The list of OF IDs below is used for matching bus types in the
- * system whose devices are to be exposed as of_platform_devices.
- *
- * This is the default list valid for most platforms. This file provides
- * functions who can take an explicit list if necessary though
- *
- * The search is always performed recursively looking for children of
- * the provided device_node and recursively if such a children matches
- * a bus type in the list
- */
-
-const struct of_device_id of_default_bus_ids[] = {
-	{ .type = "soc", },
-	{ .compatible = "soc", },
-	{ .type = "plb5", },
-	{ .type = "plb4", },
-	{ .type = "opb", },
-	{ .type = "simple", },
-	{},
-};
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index 760a7af..b2c363e 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -28,30 +28,6 @@
 #include <asm/ppc-pci.h>
 #include <asm/atomic.h>
 
-/*
- * The list of OF IDs below is used for matching bus types in the
- * system whose devices are to be exposed as of_platform_devices.
- *
- * This is the default list valid for most platforms. This file provides
- * functions who can take an explicit list if necessary though
- *
- * The search is always performed recursively looking for children of
- * the provided device_node and recursively if such a children matches
- * a bus type in the list
- */
-
-const struct of_device_id of_default_bus_ids[] = {
-	{ .type = "soc", },
-	{ .compatible = "soc", },
-	{ .type = "spider", },
-	{ .type = "axon", },
-	{ .type = "plb5", },
-	{ .type = "plb4", },
-	{ .type = "opb", },
-	{ .type = "ebc", },
-	{},
-};
-
 #ifdef CONFIG_PPC_OF_PLATFORM_PCI
 
 /* The probing of PCI controllers from of_platform is currently
diff --git a/arch/powerpc/platforms/cell/qpace_setup.c b/arch/powerpc/platforms/cell/qpace_setup.c
index c5ce02e..1b57490 100644
--- a/arch/powerpc/platforms/cell/qpace_setup.c
+++ b/arch/powerpc/platforms/cell/qpace_setup.c
@@ -61,12 +61,24 @@ static void qpace_progress(char *s, unsigned short hex)
 	printk("*** %04x : %s\n", hex, s ? s : "");
 }
 
+static const struct of_device_id qpace_bus_ids[] __initdata = {
+	{ .type = "soc", },
+	{ .compatible = "soc", },
+	{ .type = "spider", },
+	{ .type = "axon", },
+	{ .type = "plb5", },
+	{ .type = "plb4", },
+	{ .type = "opb", },
+	{ .type = "ebc", },
+	{},
+};
+
 static int __init qpace_publish_devices(void)
 {
 	int node;
 
 	/* Publish OF platform devices for southbridge IOs */
-	of_platform_bus_probe(NULL, NULL, NULL);
+	of_platform_bus_probe(NULL, qpace_bus_ids, NULL);
 
 	/* There is no device for the MIC memory controller, thus we create
 	 * a platform device for it to attach the EDAC driver to.
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 50385db..6919957 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -141,6 +141,18 @@ static int __devinit cell_setup_phb(struct pci_controller *phb)
 	return 0;
 }
 
+static const struct of_device_id cell_bus_ids[] __initdata = {
+	{ .type = "soc", },
+	{ .compatible = "soc", },
+	{ .type = "spider", },
+	{ .type = "axon", },
+	{ .type = "plb5", },
+	{ .type = "plb4", },
+	{ .type = "opb", },
+	{ .type = "ebc", },
+	{},
+};
+
 static int __init cell_publish_devices(void)
 {
 	struct device_node *root = of_find_node_by_path("/");
@@ -148,7 +160,7 @@ static int __init cell_publish_devices(void)
 	int node;
 
 	/* Publish OF platform devices for southbridge IOs */
-	of_platform_bus_probe(NULL, NULL, NULL);
+	of_platform_bus_probe(NULL, cell_bus_ids, NULL);
 
 	/* On spider based blades, we need to manually create the OF
 	 * platform devices for the PCI host bridges
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 9126064..94fa719 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -701,9 +701,7 @@ int of_platform_bus_probe(struct device_node *root,
 	struct platform_device *dev;
 	int rc = 0;
 
-	if (matches == NULL)
-		matches = of_default_bus_ids;
-	if (matches == OF_NO_DEEP_PROBE)
+	if (WARN_ON(!matches || matches == OF_NO_DEEP_PROBE))
 		return -EINVAL;
 	if (root == NULL)
 		root = of_find_node_by_path("/");
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index b24c5a5..4e6d989 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -19,8 +19,6 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 
-extern const struct of_device_id of_default_bus_ids[];
-
 /*
  * An of_platform_driver driver is attached to a basic of_device on
  * the "platform bus" (platform_bus_type).

^ permalink raw reply related

* Re: [PATCH] of: make of_find_device_by_node generic
From: David Miller @ 2010-07-23 20:04 UTC (permalink / raw)
  To: grant.likely
  Cc: jonas, monstr, microblaze-uclinux, linux-kernel, linuxppc-dev,
	sparclinux
In-Reply-To: <20100723200217.18363.48627.stgit@angua>

From: Grant Likely <grant.likely@secretlab.ca>
Date: Fri, 23 Jul 2010 14:02:17 -0600

> From: Jonas Bonn <jonas@southpole.se>
> 
> There's no need for this function to be architecture specific and all four
> architectures defining it had the same definition.  The function has been
> moved to drivers/of/platform.c.
> 
> Signed-off-by: Jonas Bonn <jonas@southpole.se>
> [grant.likely@secretlab.ca: moved to drivers/of/platform.c, simplified code, and added kerneldoc comment]
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>

Acked-by: David S. Miller <davem@davemloft.net>

^ permalink raw reply

* [PATCH] of: Fix phandle endian issues
From: Grant Likely @ 2010-07-23 20:09 UTC (permalink / raw)
  To: jonas, sfr, monstr, microblaze-uclinux, linux-kernel,
	linuxppc-dev, benh, sparclinux, davem

The flat tree code wasn't fixing the endianness on phandle values when
unflattening the tree, and the code in drivers/of wasn't always doing a
be32_to_cpu before trying to dereference the phandle values.  This patch
fixes them.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
 drivers/of/base.c |   12 ++++++------
 drivers/of/fdt.c  |    4 ++--
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index e3f7af8..aa80525 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -605,14 +605,14 @@ EXPORT_SYMBOL(of_find_node_by_phandle);
 struct device_node *
 of_parse_phandle(struct device_node *np, const char *phandle_name, int index)
 {
-	const phandle *phandle;
+	const __be32 *phandle;
 	int size;
 
 	phandle = of_get_property(np, phandle_name, &size);
 	if ((!phandle) || (size < sizeof(*phandle) * (index + 1)))
 		return NULL;
 
-	return of_find_node_by_phandle(phandle[index]);
+	return of_find_node_by_phandle(be32_to_cpup(phandle + index));
 }
 EXPORT_SYMBOL(of_parse_phandle);
 
@@ -668,16 +668,16 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
 
 	while (list < list_end) {
 		const __be32 *cells;
-		const phandle *phandle;
+		phandle phandle;
 
-		phandle = list++;
+		phandle = be32_to_cpup(list++);
 		args = list;
 
 		/* one cell hole in the list = <>; */
-		if (!*phandle)
+		if (!phandle)
 			goto next;
 
-		node = of_find_node_by_phandle(*phandle);
+		node = of_find_node_by_phandle(phandle);
 		if (!node) {
 			pr_debug("%s: could not find phandle\n",
 				 np->full_name);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index d61fda8..f3a7b4f 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -320,13 +320,13 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
 			if ((strcmp(pname, "phandle") == 0) ||
 			    (strcmp(pname, "linux,phandle") == 0)) {
 				if (np->phandle == 0)
-					np->phandle = *((u32 *)*p);
+					np->phandle = be32_to_cpup((__be32*)*p);
 			}
 			/* And we process the "ibm,phandle" property
 			 * used in pSeries dynamic device tree
 			 * stuff */
 			if (strcmp(pname, "ibm,phandle") == 0)
-				np->phandle = *((u32 *)*p);
+				np->phandle = be32_to_cpup((__be32 *)*p);
 			pp->name = pname;
 			pp->length = sz;
 			pp->value = (void *)*p;

^ permalink raw reply related

* RE: [PATCH] Adding ADMA support for PPC460EX DMA engine.
From: Tirumala Marri @ 2010-07-23 21:39 UTC (permalink / raw)
  To: Stefan Roese, linuxppc-dev
  Cc: linux-raid, dan.j.williams, linux-crypto, tmarri
In-Reply-To: <201007230815.14464.sr@denx.de>

>As you describe above, a lot of the code seems to be copied from
>drivers/dma/ppc4xx/adma.c/h. Wouldn't it make more sense to factor out
the
>common code instead of duplicating it?



  Hi Stefan,
     Thanks for the review. There are definitely some functions can be
moved to a common file.

  Hi Dan,
 Could you also please review and see if there are any changes needed, so
I can include some changes as
Well in the modified patch.


Regards,
Marri

^ permalink raw reply

* Re: [PATCH] powerpc:  fix .data..init_task output section
From: Benjamin Herrenschmidt @ 2010-07-23 22:16 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: linuxppc-dev, Sean MacLennan
In-Reply-To: <20100723135859.GA26879@merkur.ravnborg.org>


> > > 
> > > On the assumption that Sean reports that it fixes
> > > the warnings/boot issue here is a real patch.
> > > 
> > > Ben - will you take it via the popwerpc tree
> > > or shall I ask Michal to take it via kbuild?
> > > 
> > > 	Sam
> 
> Sorry for the bad initial subject line!
> As Sean reported that the patch fixes his isuse it
> deserves a:
> 
> Tested-by: Sean MacLennan <smaclennan@pikatech.com>

Heh. Too late, I already sent it to Linus :-)

Ben.

^ permalink raw reply

* Re: [PATCH 2/2] mpc85xx_edac: change to use new definitions for PCI EDAC regspace
From: Dmitry Eremin-Solenikov @ 2010-07-24  0:20 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, Doug Thompson, bluesmoke-devel
In-Reply-To: <AANLkTimsKcn3n90cyqQTQ4Ycy2dlsHdi7afeiNX4M0v5@mail.gmail.com>

Hello,

On 7/22/10, Grant Likely <grant.likely@secretlab.ca> wrote:
> On Thu, Jul 22, 2010 at 10:48 AM, Dmitry Eremin-Solenikov
> <dbaryshkov@gmail.com> wrote:
>> Hello,
>>
>> On Thu, Jul 22, 2010 at 7:38 PM, Kumar Gala <galak@kernel.crashing.org>
>> wrote:
>>>
>>> On Jul 21, 2010, at 7:03 PM, Dmitry Eremin-Solenikov wrote:
>>>
>>>> Currently (as mpc8540-pci) devices are not created on of_platform bus,
>>>> mpc85xx_edac can't probe to them. Follow the change to dts trees to bind
>>>> not to the main mpc8540-pci node but to special mpc85xx-pci-error nodes,
>>>> present on soc bus.
>>>>
>>>> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
>>>> ---
>>>> drivers/edac/mpc85xx_edac.c |   18 +++++++++---------
>>>> 1 files changed, 9 insertions(+), 9 deletions(-)
>>>
>>> Nak.
>>>
>>> We already have a node in the dts for the PCI controller.  Lets update
>>> the platform code to add the pci controller to the of_platform_bus_probe
>>> list.
>>
>> I've had that idea. However it's really look strange to me to call
>> of_platform_bus_probe() on the bus node, for which we (IMO) explicitly
>> won't like for
>> child devices (PCI devices) to be added to of_platform bus. Would it
>> be suitable to just call of_platform_device_create for it (Or do i
>> miss someth<ing)?
>
> Try the attached patch (lightly tested).  If it works for you then
> I'll post it for wider review.

Yes, this patch worked for me. However it looks a bit like a hack for me.

-- 
With best wishes
Dmitry

^ permalink raw reply

* Re: [PATCH 2/2] mpc85xx_edac: change to use new definitions for PCI EDAC regspace
From: Grant Likely @ 2010-07-24  0:56 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linuxppc-dev, devicetree-discuss, Doug Thompson, bluesmoke-devel
In-Reply-To: <AANLkTik-3cujkh774H6WQB8sHD+gkKLT2FQp=8HYaWBt@mail.gmail.com>

On Fri, Jul 23, 2010 at 6:20 PM, Dmitry Eremin-Solenikov
<dbaryshkov@gmail.com> wrote:
> Hello,
>
> On 7/22/10, Grant Likely <grant.likely@secretlab.ca> wrote:
>> On Thu, Jul 22, 2010 at 10:48 AM, Dmitry Eremin-Solenikov
>> <dbaryshkov@gmail.com> wrote:
>>> Hello,
>>>
>>> On Thu, Jul 22, 2010 at 7:38 PM, Kumar Gala <galak@kernel.crashing.org>
>>> wrote:
>>>>
>>>> On Jul 21, 2010, at 7:03 PM, Dmitry Eremin-Solenikov wrote:
>>>>
>>>>> Currently (as mpc8540-pci) devices are not created on of_platform bus=
,
>>>>> mpc85xx_edac can't probe to them. Follow the change to dts trees to b=
ind
>>>>> not to the main mpc8540-pci node but to special mpc85xx-pci-error nod=
es,
>>>>> present on soc bus.
>>>>>
>>>>> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
>>>>> ---
>>>>> drivers/edac/mpc85xx_edac.c | =A0 18 +++++++++---------
>>>>> 1 files changed, 9 insertions(+), 9 deletions(-)
>>>>
>>>> Nak.
>>>>
>>>> We already have a node in the dts for the PCI controller. =A0Lets upda=
te
>>>> the platform code to add the pci controller to the of_platform_bus_pro=
be
>>>> list.
>>>
>>> I've had that idea. However it's really look strange to me to call
>>> of_platform_bus_probe() on the bus node, for which we (IMO) explicitly
>>> won't like for
>>> child devices (PCI devices) to be added to of_platform bus. Would it
>>> be suitable to just call of_platform_device_create for it (Or do i
>>> miss someth<ing)?
>>
>> Try the attached patch (lightly tested). =A0If it works for you then
>> I'll post it for wider review.
>
> Yes, this patch worked for me. However it looks a bit like a hack for me.

I'll probably refine it a bit before merging, but I don't think it is
a hack.  It reflects the behaviour that makes sense when registering
devices hanging off the root node.  If a device node is a child of the
root, then we know it isn't hanging off an i2c or pci bus, or anything
else.  It is essentially a system device.

The troublesome bit is that the root node also has memory, cpus,
chosen and aliases nodes which are not devices.  In the vast majority
of cases, we want all the device nodes that are children of the root
to be registered, but we don't want to register the special nodes.
Checking for the presence of a compatible property is a pretty good
test for determining whether or not a node actually represents a
device, especially because all users of of_platform_bus_probe() seem
to be FDT users where we've been very strict about enforcing that
drivers must use the compatible property for matching to device nodes.

Cheers,
g.

^ permalink raw reply

* Re: [PATCH 4/8] v3 Allow memory_block to span multiple memory sections
From: Nathan Fontenot @ 2010-07-24  3:09 UTC (permalink / raw)
  To: Dave Hansen; +Cc: linux-mm, greg, linux-kernel, KAMEZAWA Hiroyuki, linuxppc-dev
In-Reply-To: <1279653481.9785.4.camel@nimitz>

On 07/20/2010 02:18 PM, Dave Hansen wrote:
> On Mon, 2010-07-19 at 22:55 -0500, Nathan Fontenot wrote:
>> +static int add_memory_section(int nid, struct mem_section *section,
>> +                       unsigned long state, enum mem_add_context context)
>> +{
>> +       struct memory_block *mem;
>> +       int ret = 0;
>> +
>> +       mem = find_memory_block(section);
>> +       if (mem) {
>> +               atomic_inc(&mem->section_count);
>> +               kobject_put(&mem->sysdev.kobj);
>> +       } else
>> +               ret = init_memory_block(&mem, section, state);
>> +
>>         if (!ret) {
>> -               if (context == HOTPLUG)
>> +               if (context == HOTPLUG &&
>> +                   atomic_read(&mem->section_count) == sections_per_block)
>>                         ret = register_mem_sect_under_node(mem, nid);
>>         } 
> 
> I think the atomic_inc() can race with the atomic_dec_and_test() in
> remove_memory_block().
> 
> Thread 1 does:
> 
> 	mem = find_memory_block(section);
> 
> Thread 2 does 
> 
> 	atomic_dec_and_test(&mem->section_count);
> 
> and destroys the memory block,  Thread 1 runs again:
> 	
>        if (mem) {
>                atomic_inc(&mem->section_count);
>                kobject_put(&mem->sysdev.kobj);
>        } else
> 
> but now mem got destroyed by Thread 2.  You probably need to change
> find_memory_block() to itself take a reference, and to use
> atomic_inc_unless().
> 

You're right but I think the fix you suggested will narrow the window for the
race condition, not eliminate it.  We could still take a time splice in
find_memory_block prior to the container_of() calls to get the memory
block pointer and end up de-referencing a invalid kobject o sysdev pointer.

I think if we want to eliminate this we may need to have lock that protects
access to any of the memory_block structures.  This would need to be taken
any time find_memory_block is called and released when use of the memory_block
returned is finished.  If we're going to fix this we should eliminate the
window completely instead of just closing it further.

If we add a lock should I submit it as part of this patchset? or submit it
as a follow-on?

-Nathan 

^ permalink raw reply

* Re: [PATCH 2/2] mpc85xx_edac: change to use new definitions for PCI EDAC regspace
From: Dmitry Eremin-Solenikov @ 2010-07-24 10:09 UTC (permalink / raw)
  To: Grant Likely
  Cc: linuxppc-dev, devicetree-discuss, Doug Thompson, bluesmoke-devel
In-Reply-To: <AANLkTinKVet56HEnirf_Q5bbjT1a-D+mb6XoPNW3ZMTp@mail.gmail.com>

On 7/24/10, Grant Likely <grant.likely@secretlab.ca> wrote:
> On Fri, Jul 23, 2010 at 6:20 PM, Dmitry Eremin-Solenikov
> <dbaryshkov@gmail.com> wrote:
>> Hello,
>>
>> On 7/22/10, Grant Likely <grant.likely@secretlab.ca> wrote:
>>> On Thu, Jul 22, 2010 at 10:48 AM, Dmitry Eremin-Solenikov
>>> <dbaryshkov@gmail.com> wrote:
>>>> Hello,
>>>>
>>>> On Thu, Jul 22, 2010 at 7:38 PM, Kumar Gala <galak@kernel.crashing.org>
>>>> wrote:
>>>>>
>>>>> On Jul 21, 2010, at 7:03 PM, Dmitry Eremin-Solenikov wrote:
>>>>>
>>>>>> Currently (as mpc8540-pci) devices are not created on of_platform bus,
>>>>>> mpc85xx_edac can't probe to them. Follow the change to dts trees to
>>>>>> bind
>>>>>> not to the main mpc8540-pci node but to special mpc85xx-pci-error
>>>>>> nodes,
>>>>>> present on soc bus.
>>>>>>
>>>>>> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
>>>>>> ---
>>>>>> drivers/edac/mpc85xx_edac.c |   18 +++++++++---------
>>>>>> 1 files changed, 9 insertions(+), 9 deletions(-)
>>>>>
>>>>> Nak.
>>>>>
>>>>> We already have a node in the dts for the PCI controller.  Lets update
>>>>> the platform code to add the pci controller to the
>>>>> of_platform_bus_probe
>>>>> list.
>>>>
>>>> I've had that idea. However it's really look strange to me to call
>>>> of_platform_bus_probe() on the bus node, for which we (IMO) explicitly
>>>> won't like for
>>>> child devices (PCI devices) to be added to of_platform bus. Would it
>>>> be suitable to just call of_platform_device_create for it (Or do i
>>>> miss someth<ing)?
>>>
>>> Try the attached patch (lightly tested).  If it works for you then
>>> I'll post it for wider review.
>>
>> Yes, this patch worked for me. However it looks a bit like a hack for me.
>
> I'll probably refine it a bit before merging, but I don't think it is
> a hack.  It reflects the behaviour that makes sense when registering
> devices hanging off the root node.  If a device node is a child of the
> root, then we know it isn't hanging off an i2c or pci bus, or anything
> else.  It is essentially a system device.
>
> The troublesome bit is that the root node also has memory, cpus,
> chosen and aliases nodes which are not devices.  In the vast majority
> of cases, we want all the device nodes that are children of the root
> to be registered, but we don't want to register the special nodes.
> Checking for the presence of a compatible property is a pretty good
> test for determining whether or not a node actually represents a
> device, especially because all users of of_platform_bus_probe() seem
> to be FDT users where we've been very strict about enforcing that
> drivers must use the compatible property for matching to device nodes.


Now it's clear to me, thanks for the explanation.

BTW: On 2.6.35-rc6 I had to make 'compat' and 'match' variables const.

-- 
With best wishes
Dmitry

^ permalink raw reply

* [PATCH] of: Provide default of_node_to_nid() when CONFIG_NUMA is not set
From: Grant Likely @ 2010-07-24 15:43 UTC (permalink / raw)
  To: sfr, monstr, microblaze-uclinux, devicetree-discuss, linux-kernel,
	linuxppc-dev, benh, sparclinux, davem

of_node_to_nid() is only relevant for NUMA.  Don't force architectures to
implement it if CONFIG_NUMA is not set.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
 arch/microblaze/include/asm/topology.h |   10 ----------
 arch/powerpc/include/asm/topology.h    |    7 -------
 arch/sparc/include/asm/prom.h          |    5 -----
 include/linux/of.h                     |    8 ++++++++
 4 files changed, 8 insertions(+), 22 deletions(-)

diff --git a/arch/microblaze/include/asm/topology.h b/arch/microblaze/include/asm/topology.h
index 96bcea5..5428f33 100644
--- a/arch/microblaze/include/asm/topology.h
+++ b/arch/microblaze/include/asm/topology.h
@@ -1,11 +1 @@
 #include <asm-generic/topology.h>
-
-#ifndef _ASM_MICROBLAZE_TOPOLOGY_H
-#define _ASM_MICROBLAZE_TOPOLOGY_H
-
-struct device_node;
-static inline int of_node_to_nid(struct device_node *device)
-{
-	return 0;
-}
-#endif /* _ASM_MICROBLAZE_TOPOLOGY_H */
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index 32adf72..09dd38c 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -41,8 +41,6 @@ static inline int cpu_to_node(int cpu)
 			       cpu_all_mask :				\
 			       node_to_cpumask_map[node])
 
-int of_node_to_nid(struct device_node *device);
-
 struct pci_bus;
 #ifdef CONFIG_PCI
 extern int pcibus_to_node(struct pci_bus *bus);
@@ -94,11 +92,6 @@ extern void sysfs_remove_device_from_node(struct sys_device *dev, int nid);
 
 #else
 
-static inline int of_node_to_nid(struct device_node *device)
-{
-	return 0;
-}
-
 static inline void dump_numa_cpu_topology(void) {}
 
 static inline int sysfs_add_device_to_node(struct sys_device *dev, int nid)
diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
index c82a7da..b47d2a7 100644
--- a/arch/sparc/include/asm/prom.h
+++ b/arch/sparc/include/asm/prom.h
@@ -41,11 +41,6 @@ extern int of_getintprop_default(struct device_node *np,
 				 const char *name,
 				 int def);
 extern int of_find_in_proplist(const char *list, const char *match, int len);
-#ifdef CONFIG_NUMA
-extern int of_node_to_nid(struct device_node *dp);
-#else
-#define of_node_to_nid(dp)	(-1)
-#endif
 
 extern void prom_build_devicetree(void);
 extern void of_populate_present_mask(void);
diff --git a/include/linux/of.h b/include/linux/of.h
index b0756f3..ec25482 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -205,6 +205,14 @@ extern int of_parse_phandles_with_args(struct device_node *np,
 
 extern int of_machine_is_compatible(const char *compat);
 
+#if defined(CONFIG_NUMA)
+extern int of_node_to_nid(struct device_node *device);
+#elif defined(CONFIG_SPARC)
+static inline int of_node_to_nid(struct device_node *device) { return -1; }
+#else
+static inline int of_node_to_nid(struct device_node *device) { return 0; }
+#endif
+
 extern int prom_add_property(struct device_node* np, struct property* prop);
 extern int prom_remove_property(struct device_node *np, struct property *prop);
 extern int prom_update_property(struct device_node *np,

^ permalink raw reply related

* Re: [PATCH][v2] fix of_flat_dt_is_compatible to match the full compatible string
From: Grant Likely @ 2010-07-24 19:34 UTC (permalink / raw)
  To: Stuart Yoder, linuxppc-dev
In-Reply-To: <1279910564-17887-1-git-send-email-stuart.yoder@freescale.com>



"Stuart Yoder" <stuart.yoder@freescale.com> wrote:

>From: Stuart Yoder <stuart.yoder@freescale.com>
>
>With the previous string comparison, a device tree
>compatible of "foo-bar" would match as compatible
>with a driver looking for "foo".
>
>Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com>

Hi Stewart. 

Patch looks good.  I'll test it this afternoon.

However, please remember to cc: me and devicetree-discuss if you want patches picked up remotely quickly (I know, I'm slow anyway, but I'm even slower when I don't see something.  I only came across this one by chance.)

g.

>---
> drivers/of/fdt.c |    2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
>diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
>index dee4fb5..28c0c2b 100644
>--- a/drivers/of/fdt.c
>+++ b/drivers/of/fdt.c
>@@ -169,7 +169,7 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
> 	if (cp == NULL)
> 		return 0;
> 	while (cplen > 0) {
>-		if (strncasecmp(cp, compat, strlen(compat)) == 0)
>+		if (!strcasecmp(cp, compat))
> 			return 1;
> 		l = strlen(cp) + 1;
> 		cp += l;
>-- 
>1.6.2.5
>
>
>_______________________________________________
>Linuxppc-dev mailing list
>Linuxppc-dev@lists.ozlabs.org
>https://lists.ozlabs.org/listinfo/linuxppc-dev

-- 
Sent from my Android phone with K-9 Mail. Please excuse my brevity.

^ permalink raw reply

* Re: [PATCH] fix of_flat_dt_is_compatible to match the full compatible string
From: Grant Likely @ 2010-07-24 22:00 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Stuart Yoder
In-Reply-To: <1279853150.1970.58.camel@pasglop>

On Thu, Jul 22, 2010 at 8:45 PM, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:
> On Thu, 2010-07-22 at 18:28 -0500, Stuart Yoder wrote:
>> From: Stuart Yoder <stuart.yoder@freescale.com>
>>
>> With the previous string comparison, a device tree
>> compatible of "foo-bar" would match as compatible
>> with a driver looking for "foo".
>>
>> Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com>
>
> Beware you are doing two changes in one here and only documenting one...
>
> You also removed the case insenstivity.
>
> Now, those things are supposed to be case sensitive afaik, but we have
> enough legacy HW with more/less crap DTs and I'd be careful with
> changing that without a good reason (ie, it breaks not to do it ?).
>
> No objection with fixing the partial match tho.

On that note, for completeness, this code should be using the
of_compat_cmp() to match up with other code.  If SPARC ever uses this
code, which davem said he might tp support kexec, then this macro will
be important.  I'll change it when I pick up the patch.

g.

>
> Cheers,
> Ben.
>
>> ---
>> =A0drivers/of/fdt.c | =A0 =A02 +-
>> =A01 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
>> index dee4fb5..f5239c0 100644
>> --- a/drivers/of/fdt.c
>> +++ b/drivers/of/fdt.c
>> @@ -169,7 +169,7 @@ int __init of_flat_dt_is_compatible(unsigned long no=
de, const char *compat)
>> =A0 =A0 =A0 if (cp =3D=3D NULL)
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 return 0;
>> =A0 =A0 =A0 while (cplen > 0) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (strncasecmp(cp, compat, strlen(compat)) =
=3D=3D 0)
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (!strcmp(cp, compat))
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return 1;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 l =3D strlen(cp) + 1;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 cp +=3D l;
>
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>



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

^ permalink raw reply

* Re: [PATCH] of: Provide default of_node_to_nid() when CONFIG_NUMA is not set
From: Stephen Rothwell @ 2010-07-25  3:07 UTC (permalink / raw)
  To: Grant Likely
  Cc: monstr, microblaze-uclinux, devicetree-discuss, linux-kernel,
	linuxppc-dev, sparclinux, davem
In-Reply-To: <20100724154331.22701.3409.stgit@angua>

[-- Attachment #1: Type: text/plain, Size: 709 bytes --]

Hi Grant,

On Sat, 24 Jul 2010 09:43:31 -0600 Grant Likely <grant.likely@secretlab.ca> wrote:
>
> of_node_to_nid() is only relevant for NUMA.  Don't force architectures to
> implement it if CONFIG_NUMA is not set.

Why not just do:

#ifndef of_node_to_nid
static inline int of_node_to_nid(struct device_node *device) { return 0; }
#define of_node_to_nid	of_node_to_nid
#endif

in include/linux/of.h

and then add:

#define of_node_to_nid	of_node_to_nid

Where it is declared/defined for each arch ...
(it would be nice if all the archs were consistent in where it was
declared).
-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]

^ permalink raw reply

* Re: [PATCH v3 2/2] powerpc/mpc5121: add initial support for PDM360NG board
From: Grant Likely @ 2010-07-25  7:42 UTC (permalink / raw)
  To: Anatolij Gustschin
  Cc: Detlev Zundel, Markus Fischer, devicetree-discuss, Michael Weiss,
	linuxppc-dev, Wolfgang Grandegger
In-Reply-To: <1279892973-24110-1-git-send-email-agust@denx.de>

On Fri, Jul 23, 2010 at 7:49 AM, Anatolij Gustschin <agust@denx.de> wrote:
> Adds IFM PDM360NG device tree, and platform code.
>
> Currently following is supported:
> =A0- Spansion S29GL512P 256 MB NOR flash
> =A0- ST Micro NAND 1 GiB flash
> =A0- DIU, please use "fbcon=3Dmap:5 video=3Dfslfb:800x480-32@60"
> =A0 at the kernel command line to enable PrimeView PM070WL3
> =A0 Display support.
> =A0- FEC
> =A0- I2C
> =A0- RTC, EEPROM
> =A0- MSCAN
> =A0- PSC UART, please pass "console=3Dtty0 console=3DttyPSC5,115200"
> =A0 on the kernel command line.
> =A0- SPI, ADS7845 Touchscreen
> =A0- USB0/1 Host
> =A0- USB0 OTG Host/Device
> =A0- VIU, Overlay/Capture support
>
> Signed-off-by: Markus Fischer <markus.fischer.ec@ifm.com>
> Signed-off-by: Wolfgang Grandegger <wg@denx.de>
> Signed-off-by: Michael Weiss <michael.weiss@ifm.com>
> Signed-off-by: Detlev Zundel <dzu@denx.de>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: devicetree-discuss@lists.ozlabs.org
> Cc: Grant Likely <grant.likely@secretlab.ca>

Hi Anatolij,

Finally got some time tonight to properly dig into this patch.  Comments be=
low.

> ---
> v3:
> =A0- uncomment and correct .irq_flags field of touchscreen
> =A0 platform data struct as proposed extension to this
> =A0 data struct has been accepted and merged via input tree
> =A0 a short while ago
>
> v1 -> v2:
> =A0- fix interrupt-parent property in nfc node
> =A0- drop #address-cells in ipic node
> =A0- remove device_type from ethernet-phy sub-node
> =A0- remove device_type from ethernet node
> =A0- add aliases node for eth0, needed for MAC address
> =A0 update by U-Boot
> =A0- removed spaces around &ipic
>
> =A0arch/powerpc/boot/dts/pdm360ng.dts =A0 =A0 | =A0432 ++++++++++++++++++=
++++++++++++++
> =A0arch/powerpc/platforms/512x/Kconfig =A0 =A0| =A0 =A07 +
> =A0arch/powerpc/platforms/512x/Makefile =A0 | =A0 =A01 +
> =A0arch/powerpc/platforms/512x/pdm360ng.c | =A0158 ++++++++++++
> =A04 files changed, 598 insertions(+), 0 deletions(-)
> =A0create mode 100644 arch/powerpc/boot/dts/pdm360ng.dts
> =A0create mode 100644 arch/powerpc/platforms/512x/pdm360ng.c
>
> diff --git a/arch/powerpc/boot/dts/pdm360ng.dts b/arch/powerpc/boot/dts/p=
dm360ng.dts
> new file mode 100644
> index 0000000..7dc42e9
> --- /dev/null
> +++ b/arch/powerpc/boot/dts/pdm360ng.dts
> @@ -0,0 +1,432 @@
> +/*
> + * Device Tree Source for IFM PDM360NG.
> + *
> + * Copyright 2009 - 2010 DENX Software Engineering.
> + * Anatolij Gustschin <agust@denx.de>
> + *
> + * Based on MPC5121E ADS dts.
> + * Copyright 2008 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 you=
r
> + * option) any later version.
> + */
> +
> +/dts-v1/;
> +
> +/ {
> + =A0 =A0 =A0 model =3D "pdm360ng";
> + =A0 =A0 =A0 compatible =3D "ifm,pdm360ng";
> + =A0 =A0 =A0 #address-cells =3D <1>;
> + =A0 =A0 =A0 #size-cells =3D <1>;
> +
> + =A0 =A0 =A0 aliases {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ethernet0 =3D &eth0;
> + =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 cpus {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <0>;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 PowerPC,5121@0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 device_type =3D "cpu";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 d-cache-line-size =3D <0x20=
>; =A0 =A0 // 32 bytes
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 i-cache-line-size =3D <0x20=
>; =A0 =A0 // 32 bytes
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 d-cache-size =3D <0x8000>; =
=A0 =A0 =A0 =A0// L1, 32K
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 i-cache-size =3D <0x8000>; =
=A0 =A0 =A0 =A0// L1, 32K
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 timebase-frequency =3D <495=
00000>;// 49.5 MHz (csb/4)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bus-frequency =3D <19800000=
0>; =A0 =A0// 198 MHz csb bus
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 clock-frequency =3D <396000=
000>; =A0// 396 MHz ppc core
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 memory {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 device_type =3D "memory";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x00000000 0x20000000>; =A0// 512M=
B at 0
> + =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 nfc@40000000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121-nfc";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x40000000 0x100000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <0x6 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic>;

This device tree can be less verbose if you remove the
interrupt-parent property from all the nodes, and have a single
interrupt-parent =3D <&ipic>; in the root node.  Nodes inherit the
interrupt-parent from their (grand-)parents.

> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <0x1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <0x1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bank-width =3D <0x1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 chips =3D <0x1>;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 partition@0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 label =3D "nand0";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x0 0x40000000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 sram@50000000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121-sram";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x50000000 0x20000>; =A0 =A0 // 12=
8K at 0x50000000
> + =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 localbus@80000020 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121-localbus";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <2>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x80000020 0x40>;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ranges =3D <0x0 0x0 0xf0000000 0x10000000 =
=A0 /* Flash */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 0x2 0x0 0x50040000 0x00=
020000>; /* CS2: MRAM */
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 flash@0,0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "amd,s29gl01=
gp", "cfi-flash";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0 0x00000000 0x080=
00000
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00 0x08000000=
 0x08000000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bank-width =3D <4>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 device-width =3D <2>;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 partition@0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 label =3D "=
u-boot";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x=
00000000 0x00080000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 read-only;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 partition@80000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 label =3D "=
environment";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x=
00080000 0x00080000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 read-only;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 partition@100000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 label =3D "=
splash-image";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x=
00100000 0x00080000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 read-only;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 partition@180000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 label =3D "=
device-tree";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x=
00180000 0x00040000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 partition@1c0000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 label =3D "=
kernel";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x=
001c0000 0x00500000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 partition@6c0000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 label =3D "=
filesystem";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x=
006c0000 0x07940000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mram0@2,0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "mtd-ram";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <2 0x00000 0x10000>=
;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bank-width =3D <2>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mram1@2,10000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "mtd-ram";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <2 0x010000 0x10000=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bank-width =3D <2>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 soc@80000000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121-immr";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #interrupt-cells =3D <2>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ranges =3D <0x0 0x80000000 0x400000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x80000000 0x400000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bus-frequency =3D <66000000>; =A0 =A0 // 66=
 MHz ips bus
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 // IPIC
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 // interrupts cell =3D <intr #, sense>
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 // sense values match linux IORESOURCE_IRQ_=
* defines:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 // sense =3D=3D 8: Level, low assertion
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 // sense =3D=3D 2: Edge, high-to-low change
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 //
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ipic: interrupt-controller@c00 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-ipic", "fsl,ipic";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-controller;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <0>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #interrupt-cells =3D <2>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0xc00 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtc@a00 { =A0 =A0 =A0 // Real time clock
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-rtc";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0xa00 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <79 0x8 80 0=
x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 reset@e00 { =A0 =A0 // Reset module
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-reset";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0xe00 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 clock@f00 { =A0 =A0 // Clock control
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-clock";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0xf00 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pmc@1000{ =A0 =A0 =A0 //Power Management Co=
ntroller
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-pmc";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x1000 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <83 0x2>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 gpio@1100 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-gpio";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x1100 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <78 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 can@1300 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-mscan";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <12 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x1300 0x80>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 can@1380 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-mscan";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <13 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x1380 0x80>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 i2c@1700 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <0>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-i2c";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x1700 0x20>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <0x9 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,preserve-clocking;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 eeprom@50 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =
=3D "at,24c01";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x=
50>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtc@68 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =
=3D "stm,m41t00";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x=
68>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 i2c@1740 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <0>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-i2c";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x1740 0x20>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <0xb 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,preserve-clocking;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 i2ccontrol@1760 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-i2c-ctrl";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x1760 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 axe@2000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-axe";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x2000 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <42 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 display@2100 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-diu";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x2100 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <64 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 can@2300 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-mscan";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <90 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x2300 0x80>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 can@2380 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-mscan";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <91 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x2380 0x80>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 viu@2400 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-viu";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x2400 0x400>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <67 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mdio@2800 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-fec-mdio";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x2800 0x200>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <0>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 phy: ethernet-phy@0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x=
1f>;

For completeness, phy should have a compatible property.

> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 eth0: ethernet@2800 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-fec";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x2800 0x200>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 local-mac-address =3D [ 00 =
00 00 00 00 00 ];
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <4 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 phy-handle =3D < &phy >;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 // USB1 using external ULPI PHY
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 usb@3000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-usb2-dr";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x3000 0x600>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <0>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <43 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dr_mode =3D "host";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 phy_type =3D "ulpi";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 // USB0 using internal UTMI PHY
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 usb@4000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-usb2-dr";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x4000 0x600>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <0>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <44 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dr_mode =3D "otg";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 phy_type =3D "utmi_wide";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,invert-pwr-fault;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 // IO control
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ioctl@a000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-ioctl";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0xA000 0x1000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 // 512x PSCs are not 52xx PSCs compatible
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 serial@11000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-psc-uart", "fsl,mpc5121-psc";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cell-index =3D <0>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x11000 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <40 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,rx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,tx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 serial@11100 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-psc-uart", "fsl,mpc5121-psc";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cell-index =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x11100 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <40 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,rx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,tx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 serial@11200 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-psc-uart", "fsl,mpc5121-psc";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cell-index =3D <2>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x11200 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <40 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,rx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,tx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 serial@11300 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-psc-uart", "fsl,mpc5121-psc";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cell-index =3D <3>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x11300 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <40 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,rx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,tx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 serial@11400 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-psc-uart", "fsl,mpc5121-psc";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cell-index =3D <4>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x11400 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <40 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,rx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,tx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 serial@11600 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-psc-uart", "fsl,mpc5121-psc";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cell-index =3D <6>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x11600 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <40 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,rx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,tx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 serial@11800 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-psc-uart", "fsl,mpc5121-psc";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cell-index =3D <8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x11800 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <40 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,rx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,tx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 serial@11B00 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-psc-uart", "fsl,mpc5121-psc";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cell-index =3D <11>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x11B00 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <40 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,rx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,tx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pscfifo@11f00 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-psc-fifo";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x11f00 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <40 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spi@11900 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-psc-spi", "fsl,mpc5121-psc";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cell-index =3D <9>;

Try to drop the cell-index properties.  They are almost always misused.

> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x11900 0x100>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <40 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,rx-fifo-size =3D <16>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fsl,tx-fifo-size =3D <16>;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 // 7845 touch screen contro=
ller
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ts@0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =
=3D "ti,ads7845";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-p=
arent =3D <&ipic>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 // pen irq =
is GPIO25
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =
=3D <78 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dma@14000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-dma";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0x14000 0x1800>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupts =3D <65 0x8>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 interrupt-parent =3D <&ipic=
>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 };
> +};
> diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms=
/512x/Kconfig
> index e9dca28..27b0651 100644
> --- a/arch/powerpc/platforms/512x/Kconfig
> +++ b/arch/powerpc/platforms/512x/Kconfig
> @@ -25,3 +25,10 @@ config MPC5121_GENERIC
>
> =A0 =A0 =A0 =A0 =A0Compatible boards include: =A0Protonic LVT base boards=
 (ZANMCU
> =A0 =A0 =A0 =A0 =A0and VICVT2).
> +
> +config PDM360NG
> + =A0 =A0 =A0 bool "ifm PDM360NG board"
> + =A0 =A0 =A0 depends on PPC_MPC512x
> + =A0 =A0 =A0 select DEFAULT_UIMAGE
> + =A0 =A0 =A0 help
> + =A0 =A0 =A0 =A0 This option enables support for the PDM360NG board.
> diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platform=
s/512x/Makefile
> index 90be2f5..4efc1c4 100644
> --- a/arch/powerpc/platforms/512x/Makefile
> +++ b/arch/powerpc/platforms/512x/Makefile
> @@ -4,3 +4,4 @@
> =A0obj-y =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0+=3D clock.o =
mpc512x_shared.o
> =A0obj-$(CONFIG_MPC5121_ADS) =A0 =A0 =A0+=3D mpc5121_ads.o mpc5121_ads_cp=
ld.o
> =A0obj-$(CONFIG_MPC5121_GENERIC) =A0+=3D mpc5121_generic.o
> +obj-$(CONFIG_PDM360NG) =A0 =A0 =A0 =A0 +=3D pdm360ng.o
> diff --git a/arch/powerpc/platforms/512x/pdm360ng.c b/arch/powerpc/platfo=
rms/512x/pdm360ng.c
> new file mode 100644
> index 0000000..01e6023
> --- /dev/null
> +++ b/arch/powerpc/platforms/512x/pdm360ng.c
> @@ -0,0 +1,158 @@
> +/*
> + * Copyright (C) 2010 DENX Software Engineering
> + *
> + * Anatolij Gustschin, <agust@denx.de>
> + *
> + * PDM360NG board setup
> + *
> + * This 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/io.h>
> +#include <linux/of_platform.h>
> +
> +#include <asm/machdep.h>
> +#include <asm/ipic.h>
> +#include <asm/prom.h>
> +
> +#include "mpc512x.h"
> +
> +#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
> + =A0 =A0defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
> +#include <linux/fsl_devices.h>
> +#include <linux/interrupt.h>
> +#include <linux/spi/ads7846.h>
> +#include <linux/spi/spi.h>
> +
> +static void *pdm360ng_gpio_base;
> +
> +static int pdm360ng_get_pendown_state(void)
> +{
> + =A0 =A0 =A0 u32 reg;
> +
> + =A0 =A0 =A0 reg =3D in_be32((u32 *)(pdm360ng_gpio_base + 0xc));
> + =A0 =A0 =A0 if (reg & 0x40)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 setbits32((u32 *)(pdm360ng_gpio_base + 0xc)=
, 0x40);
> +
> + =A0 =A0 =A0 reg =3D in_be32((u32 *)(pdm360ng_gpio_base + 0x8));

(u32*) casts are unnecessary and can be removed.

> +
> + =A0 =A0 =A0 /* return 1 if pen is down */
> + =A0 =A0 =A0 return reg & 0x40 ? 0 : 1;

return reg & 0x40 =3D=3D 0;

> +}
> +
> +static struct ads7846_platform_data pdm360ng_ads7846_pdata __initdata =
=3D {
> + =A0 =A0 =A0 .model =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D 7845,
> + =A0 =A0 =A0 .get_pendown_state =A0 =A0 =A0=3D pdm360ng_get_pendown_stat=
e,
> + =A0 =A0 =A0 .irq_flags =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D IRQF_TRIGGER_LOW,
> +};
> +
> +static int __init pdm360ng_penirq_init(void)
> +{
> + =A0 =A0 =A0 struct device_node *np;
> + =A0 =A0 =A0 struct resource r;
> +
> + =A0 =A0 =A0 np =3D of_find_compatible_node(NULL, NULL, "fsl,mpc5121-gpi=
o");
> + =A0 =A0 =A0 if (!np) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("%s: Can't find 'mpc5121-gpio' node\=
n", __func__);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -1;
> + =A0 =A0 =A0 }

return -ENODEV;

> +
> + =A0 =A0 =A0 if (of_address_to_resource(np, 0, &r)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("%s: Invalid gpio address.\n", __fun=
c__);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(np);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -1;

ditto

> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 of_node_put(np);
> +
> + =A0 =A0 =A0 pdm360ng_gpio_base =3D ioremap(r.start, resource_size(&r));

Or you could have simply used of_iomap() to eliminate some code.

> + =A0 =A0 =A0 if (!pdm360ng_gpio_base) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("%s: Can't map gpio regs.\n", __func=
__);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -1;

ditto

> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 out_be32((u32 *)pdm360ng_gpio_base + 0xc, 0xffffffff);
> + =A0 =A0 =A0 setbits32((u32 *)(pdm360ng_gpio_base + 0x18), 0x2000);
> + =A0 =A0 =A0 setbits32((u32 *)(pdm360ng_gpio_base + 0x10), 0x40);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int __init pdm360ng_touchscreen_init(void)
> +{
> + =A0 =A0 =A0 struct device_node *np;
> + =A0 =A0 =A0 struct of_device *of_dev;
> + =A0 =A0 =A0 struct spi_board_info info;
> + =A0 =A0 =A0 const u32 *prop;
> + =A0 =A0 =A0 int bus_num =3D -1;
> + =A0 =A0 =A0 int len;
> +
> + =A0 =A0 =A0 np =3D of_find_compatible_node(NULL, NULL, "ti,ads7845");
> + =A0 =A0 =A0 if (!np)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> +
> + =A0 =A0 =A0 memset(&info, 0, sizeof(info));
> + =A0 =A0 =A0 info.irq =3D irq_of_parse_and_map(np, 0);
> + =A0 =A0 =A0 if (info.irq =3D=3D NO_IRQ)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> +
> + =A0 =A0 =A0 info.platform_data =3D &pdm360ng_ads7846_pdata;
> + =A0 =A0 =A0 if (strlcpy(info.modalias, "ads7846",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 SPI_NAME_SIZE) >=3D SPI_NAME_SIZE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> +
> + =A0 =A0 =A0 np =3D of_get_next_parent(np);
> + =A0 =A0 =A0 if (!np)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "cell-index", &len);
> + =A0 =A0 =A0 if (prop && len =3D=3D 4)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bus_num =3D *prop;

Blech.  Don't use cell-index for bus enumeration.  In fact, none of
this should be necessary at all (see below).

> +
> + =A0 =A0 =A0 if (bus_num < 0 || bus_num > 11)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> +
> + =A0 =A0 =A0 info.bus_num =3D bus_num;
> +
> + =A0 =A0 =A0 of_dev =3D of_find_device_by_node(np);
> + =A0 =A0 =A0 of_node_put(np);
> + =A0 =A0 =A0 if (of_dev) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct fsl_spi_platform_data *pdata;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata =3D kzalloc(sizeof(*pdata), GFP_KERNE=
L);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (pdata) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata->bus_num =3D bus_num;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata->max_chipselect =3D 1=
;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 of_dev->dev.platform_data =
=3D pdata;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 if (pdm360ng_penirq_init())
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> +
> + =A0 =A0 =A0 return spi_register_board_info(&info, 1);

This ends up being a lot of code simply to attach a pdata structure to
an spi device.  I've been thinking about this problem, and I think
there is a better way.  Instead, use a bus notifier attached to the
SPI bus to wait for the spi_device to get registered, but before it
gets bound to a driver.  Then you can attach the pdata structure very
simply.  Something like this I think (completely untested, or even
compiled.  Details are left as an exercise to the developer):

static int pdm360ng_touchscreen_notifier_call(struct notifier_block *nb,
					unsigned long event, void *__dev)
{
	struct device *dev =3D __dev;

	if ((event =3D=3D BUS_NOTIFIY_ADD_DEVICE) && (dev->of_node =3D=3D [FOO]))
		dev->platform_data =3D [BAR];
}

static struct notifier_block pdm360ng_touchscreen_nb =3D {
	notifier_call =3D pdm360ng_touchscreen_notifier_call;
};

static int __init pdm360ng_touchscreen_init(void)
{
	bus_register_notifier(&spi_bus_type, pdm360ng_touchscreen_nb);
}


> +}
> +machine_device_initcall(pdm360ng, pdm360ng_touchscreen_init);

This code is *in the same file* as the board setup file.  Don't use an
initcall.  Call it from the init callback instead.

> +#endif
> +
> +static int __init pdm360ng_probe(void)
> +{
> + =A0 =A0 =A0 unsigned long root =3D of_get_flat_dt_root();
> +
> + =A0 =A0 =A0 return of_flat_dt_is_compatible(root, "ifm,pdm360ng");
> +}
> +
> +define_machine(pdm360ng) {
> + =A0 =A0 =A0 .name =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D "PDM360NG",
> + =A0 =A0 =A0 .probe =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D pdm360ng_prob=
e,
> + =A0 =A0 =A0 .setup_arch =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc512x_setup_diu,
> + =A0 =A0 =A0 .init =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc512x_init,
> + =A0 =A0 =A0 .init_early =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc512x_init_diu,
> + =A0 =A0 =A0 .init_IRQ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc512x_init_IRQ,
> + =A0 =A0 =A0 .get_irq =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D ipic_get_irq,
> + =A0 =A0 =A0 .calibrate_decr =A0 =A0 =A0 =A0 =3D generic_calibrate_decr,
> + =A0 =A0 =A0 .restart =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D mpc512x_restart=
,
> +};
> --
> 1.7.0.4
>
>



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

^ permalink raw reply

* Re: [PATCH] of: Provide default of_node_to_nid() when CONFIG_NUMA is not set
From: Grant Likely @ 2010-07-25 20:37 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: monstr, microblaze-uclinux, devicetree-discuss, linux-kernel,
	linuxppc-dev, sparclinux, davem
In-Reply-To: <20100725130723.a5192793.sfr@canb.auug.org.au>

On Sat, Jul 24, 2010 at 9:07 PM, Stephen Rothwell <sfr@canb.auug.org.au> wr=
ote:
> Hi Grant,
>
> On Sat, 24 Jul 2010 09:43:31 -0600 Grant Likely <grant.likely@secretlab.c=
a> wrote:
>>
>> of_node_to_nid() is only relevant for NUMA. =A0Don't force architectures=
 to
>> implement it if CONFIG_NUMA is not set.
>
> Why not just do:
>
> #ifndef of_node_to_nid
> static inline int of_node_to_nid(struct device_node *device) { return 0; =
}
> #define of_node_to_nid =A0of_node_to_nid
> #endif
>
> in include/linux/of.h
>
> and then add:
>
> #define of_node_to_nid =A0of_node_to_nid
>
> Where it is declared/defined for each arch ...
> (it would be nice if all the archs were consistent in where it was
> declared).

Two reasons; I had started doing that in topology.h, but it caused a
bunch of collateral damage with files missing the include, so I punted
and took the easy way out.  Also, I didn't know if that was an
acceptable or safe pattern for override symbols.

I'll spin it again with this pattern and see what it looks.

g.


> --
> Cheers,
> Stephen Rothwell =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sfr@canb.auug.org=
.au
> http://www.canb.auug.org.au/~sfr/
>



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

^ permalink raw reply

* Re: [PATCH] of: Provide default of_node_to_nid() when CONFIG_NUMA is not set
From: Grant Likely @ 2010-07-25 21:14 UTC (permalink / raw)
  To: Stephen Rothwell, Arnd Bergmann
  Cc: monstr, microblaze-uclinux, devicetree-discuss, linux-kernel,
	linuxppc-dev, sparclinux, davem
In-Reply-To: <AANLkTinE4X0iAJAiatc7Qtj2QP6dhyBKo9fqxqUt40Y6@mail.gmail.com>

[cc'ing Arnd]

On Sun, Jul 25, 2010 at 02:37:38PM -0600, Grant Likely wrote:
> On Sat, Jul 24, 2010 at 9:07 PM, Stephen Rothwell <sfr@canb.auug.org.au> wrote:
> > Hi Grant,
> >
> > On Sat, 24 Jul 2010 09:43:31 -0600 Grant Likely <grant.likely@secretlab.ca> wrote:
> >>
> >> of_node_to_nid() is only relevant for NUMA.  Don't force architectures to
> >> implement it if CONFIG_NUMA is not set.
> >
> > Why not just do:
> >
> > #ifndef of_node_to_nid
> > static inline int of_node_to_nid(struct device_node *device) { return 0; }
> > #define of_node_to_nid  of_node_to_nid
> > #endif
> >
> > in include/linux/of.h
> >
> > and then add:
> >
> > #define of_node_to_nid  of_node_to_nid
> >
> > Where it is declared/defined for each arch ...
> > (it would be nice if all the archs were consistent in where it was
> > declared).
> 
> Two reasons; I had started doing that in topology.h, but it caused a
> bunch of collateral damage with files missing the include, so I punted
> and took the easy way out.  Also, I didn't know if that was an
> acceptable or safe pattern for override symbols.
> 
> I'll spin it again with this pattern and see what it looks.
> 
> g.

Should I use asm-generic for this and other similar symbols?  How does the following look?

---

>From 1ac16ad91d4752b49ff0644854dd2cbe593bbfa8 Mon Sep 17 00:00:00 2001
From: Grant Likely <grant.likely@secretlab.ca>
Date: Fri, 23 Jul 2010 20:11:18 -0600
Subject: [PATCH] of: Create asm-generic/of.h and provide default of_node_to_nid()

of_node_to_nid() is only relevant in a few architectures.  Don't force
everyone to implement it anyway.  This patch also adds asm-generic/of.h
which will be used to contain other overrideable symbols.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
 arch/microblaze/include/asm/prom.h     |    3 +++
 arch/microblaze/include/asm/topology.h |   10 ----------
 arch/powerpc/include/asm/prom.h        |    6 ++++++
 arch/powerpc/include/asm/topology.h    |    7 -------
 arch/sparc/include/asm/prom.h          |    4 ++++
 include/asm-generic/of.h               |   19 +++++++++++++++++++
 6 files changed, 32 insertions(+), 17 deletions(-)
 create mode 100644 include/asm-generic/of.h

diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
index cb9c3dd..ff99d7d 100644
--- a/arch/microblaze/include/asm/prom.h
+++ b/arch/microblaze/include/asm/prom.h
@@ -103,4 +103,7 @@ extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
 
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
+
+#include <asm-generic/of.h>
+
 #endif /* _ASM_MICROBLAZE_PROM_H */
diff --git a/arch/microblaze/include/asm/topology.h b/arch/microblaze/include/asm/topology.h
index 96bcea5..5428f33 100644
--- a/arch/microblaze/include/asm/topology.h
+++ b/arch/microblaze/include/asm/topology.h
@@ -1,11 +1 @@
 #include <asm-generic/topology.h>
-
-#ifndef _ASM_MICROBLAZE_TOPOLOGY_H
-#define _ASM_MICROBLAZE_TOPOLOGY_H
-
-struct device_node;
-static inline int of_node_to_nid(struct device_node *device)
-{
-	return 0;
-}
-#endif /* _ASM_MICROBLAZE_TOPOLOGY_H */
diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
index da7dd63..52457dc 100644
--- a/arch/powerpc/include/asm/prom.h
+++ b/arch/powerpc/include/asm/prom.h
@@ -103,6 +103,9 @@ struct device_node *of_find_next_cache_node(struct device_node *np);
 /* Get the MAC address */
 extern const void *of_get_mac_address(struct device_node *np);
 
+extern int of_node_to_nid(struct device_node *device);
+#define of_node_to_nid of_node_to_nid
+
 /**
  * of_irq_map_pci - Resolve the interrupt for a PCI device
  * @pdev:	the device whose interrupt is to be resolved
@@ -120,4 +123,7 @@ extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
 extern void of_instantiate_rtc(void);
 
 #endif /* __KERNEL__ */
+
+#include <asm-generic/of.h>
+
 #endif /* _POWERPC_PROM_H */
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index 32adf72..09dd38c 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -41,8 +41,6 @@ static inline int cpu_to_node(int cpu)
 			       cpu_all_mask :				\
 			       node_to_cpumask_map[node])
 
-int of_node_to_nid(struct device_node *device);
-
 struct pci_bus;
 #ifdef CONFIG_PCI
 extern int pcibus_to_node(struct pci_bus *bus);
@@ -94,11 +92,6 @@ extern void sysfs_remove_device_from_node(struct sys_device *dev, int nid);
 
 #else
 
-static inline int of_node_to_nid(struct device_node *device)
-{
-	return 0;
-}
-
 static inline void dump_numa_cpu_topology(void) {}
 
 static inline int sysfs_add_device_to_node(struct sys_device *dev, int nid)
diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
index c82a7da..09f0e07 100644
--- a/arch/sparc/include/asm/prom.h
+++ b/arch/sparc/include/asm/prom.h
@@ -43,6 +43,7 @@ extern int of_getintprop_default(struct device_node *np,
 extern int of_find_in_proplist(const char *list, const char *match, int len);
 #ifdef CONFIG_NUMA
 extern int of_node_to_nid(struct device_node *dp);
+#define of_node_to_nid of_node_to_nid
 #else
 #define of_node_to_nid(dp)	(-1)
 #endif
@@ -72,4 +73,7 @@ extern void (*prom_build_more)(struct device_node *dp, struct device_node ***nex
 extern char *build_full_name(struct device_node *dp);
 
 #endif /* __KERNEL__ */
+
+#include <asm-generic/of.h>
+
 #endif /* _SPARC_PROM_H */
diff --git a/include/asm-generic/of.h b/include/asm-generic/of.h
new file mode 100644
index 0000000..8d8d147
--- /dev/null
+++ b/include/asm-generic/of.h
@@ -0,0 +1,19 @@
+/*
+ * Generic OpenFirmware/Flattened Device Tree definitions
+ *
+ * Copyright (C) 2010, Secret Lab Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef __ASM_GENERIC_OF_H
+#define __ASM_GENERIC_OF_H
+
+#ifndef of_node_to_nid
+static inline int of_node_to_nid(struct device_node *np) { return 0; }
+#define of_node_to_nid of_node_to_nid
+#endif
+
+#endif /* __ASM_GENERIC_OF_H */
-- 
1.7.0.4

^ permalink raw reply related

* Re: [PATCH 1/6] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
From: Grant Likely @ 2010-07-26  0:14 UTC (permalink / raw)
  To: Mingkai Hu, "; +Cc: linuxppc-dev
In-Reply-To: <1279591705-7574-2-git-send-email-Mingkai.hu@freescale.com>

On Tue, Jul 20, 2010 at 10:08:20AM +0800, Mingkai Hu wrote:
> Refactor the common code to file spi_mpc8xxx.c used by SPI/eSPI
> controller driver, move the SPI controller driver to a new file
> fsl_spi.c, and leave the QE/CPM SPI controller code in this file.
> 
> Because the register map of the SPI controller and eSPI controller
> is so different, also leave the code operated the register to the
> driver code, not the common code.
> 
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> ---
>  drivers/spi/Kconfig       |   13 +-
>  drivers/spi/Makefile      |    1 +
>  drivers/spi/fsl_spi.c     | 1118 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/spi/spi_mpc8xxx.c | 1198 ++-------------------------------------------
>  drivers/spi/spi_mpc8xxx.h |  135 +++++

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

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

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

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

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

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

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

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

config SPI_MPC8xxx_SPI
and
config SPI_MPC8xxx_ESPI

> +	depends on FSL_SOC
> +	select SPI_MPC8xxx
> +	help
> +	  This enables using the Freescale SPI controllers in master mode.
>  
>  config SPI_OMAP_UWIRE
>  	tristate "OMAP1 MicroWire"
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index e9cbd18..dca9fea 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_SPI_MPC512x_PSC)		+= mpc512x_psc_spi.o
>  obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
>  obj-$(CONFIG_SPI_MPC52xx)		+= mpc52xx_spi.o
>  obj-$(CONFIG_SPI_MPC8xxx)		+= spi_mpc8xxx.o
> +obj-$(CONFIG_SPI_FSL_SPI)		+= fsl_spi.o
>  obj-$(CONFIG_SPI_PPC4xx)		+= spi_ppc4xx.o
>  obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
>  obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx_hw.o
> diff --git a/drivers/spi/fsl_spi.c b/drivers/spi/fsl_spi.c
> new file mode 100644
> index 0000000..a1637c0
> --- /dev/null
> +++ b/drivers/spi/fsl_spi.c
> @@ -0,0 +1,1118 @@
> +/*
> + * MPC8xxx SPI controller driver.
> + *
> + * Maintainer: Kumar Gala
> + *
> + * Copyright (C) 2006 Polycom, Inc.
> + *
> + * CPM SPI and QE buffer descriptors mode support:
> + * Copyright (c) 2009  MontaVista Software, Inc.
> + * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
> + *
> + * Copyright 2010 Freescale Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + */
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +#include <linux/irq.h>
> +#include <linux/spi/spi.h>
> +#include <linux/spi/spi_bitbang.h>
> +#include <linux/platform_device.h>
> +#include <linux/fsl_devices.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/mm.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/gpio.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_spi.h>
> +
> +#include <sysdev/fsl_soc.h>
> +#include <asm/cpm.h>
> +#include <asm/qe.h>
> +
> +#include "spi_mpc8xxx.h"
> +
> +/* CPM1 and CPM2 are mutually exclusive. */
> +#ifdef CONFIG_CPM1
> +#include <asm/cpm1.h>
> +#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_CH_SPI, 0)
> +#else
> +#include <asm/cpm2.h>
> +#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK, 0, 0)
> +#endif
> +
> +/* SPI Controller mode register definitions */
> +#define	SPMODE_LOOP		(1 << 30)
> +#define	SPMODE_CI_INACTIVEHIGH	(1 << 29)
> +#define	SPMODE_CP_BEGIN_EDGECLK	(1 << 28)
> +#define	SPMODE_DIV16		(1 << 27)
> +#define	SPMODE_REV		(1 << 26)
> +#define	SPMODE_MS		(1 << 25)
> +#define	SPMODE_ENABLE		(1 << 24)
> +#define	SPMODE_LEN(x)		((x) << 20)
> +#define	SPMODE_PM(x)		((x) << 16)
> +#define	SPMODE_OP		(1 << 14)
> +#define	SPMODE_CG(x)		((x) << 7)
> +
> +/*
> + * Default for SPI Mode:
> + *	SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
> + */
> +#define	SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
> +			 SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
> +
> +/* SPIE register values */
> +#define	SPIE_NE		0x00000200	/* Not empty */
> +#define	SPIE_NF		0x00000100	/* Not full */
> +
> +/* SPIM register values */
> +#define	SPIM_NE		0x00000200	/* Not empty */
> +#define	SPIM_NF		0x00000100	/* Not full */
> +
> +#define	SPIE_TXB	0x00000200	/* Last char is written to tx fifo */
> +#define	SPIE_RXB	0x00000100	/* Last char is written to rx buf */
> +
> +/* SPCOM register values */
> +#define	SPCOM_STR	(1 << 23)	/* Start transmit */
> +
> +#define	SPI_PRAM_SIZE	0x100
> +#define	SPI_MRBLR	((unsigned int)PAGE_SIZE)
> +
> +static void *fsl_dummy_rx;
> +static DEFINE_MUTEX(fsl_dummy_rx_lock);
> +static int fsl_dummy_rx_refcnt;
> +
> +static void fsl_spi_change_mode(struct spi_device *spi)
> +{
> +	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
> +	struct spi_mpc8xxx_cs *cs = spi->controller_state;
> +	__be32 __iomem *mode = &mspi->base->mode;
> +	unsigned long flags;
> +
> +	if (cs->hw_mode == mpc8xxx_spi_read_reg(mode))
> +		return;
> +
> +	/* Turn off IRQs locally to minimize time that SPI is disabled. */
> +	local_irq_save(flags);
> +
> +	/* Turn off SPI unit prior changing mode */
> +	mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE);
> +
> +	/* When in CPM mode, we need to reinit tx and rx. */
> +	if (mspi->flags & SPI_CPM_MODE) {
> +		if (mspi->flags & SPI_QE) {
> +			qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock,
> +				     QE_CR_PROTOCOL_UNSPECIFIED, 0);
> +		} else {
> +			cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
> +			if (mspi->flags & SPI_CPM1) {
> +				out_be16(&mspi->pram->rbptr,
> +					 in_be16(&mspi->pram->rbase));
> +				out_be16(&mspi->pram->tbptr,
> +					 in_be16(&mspi->pram->tbase));
> +			}
> +		}
> +	}
> +	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
> +	local_irq_restore(flags);
> +}
> +
> +static void fsl_spi_chipselect(struct spi_device *spi, int value)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +	struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
> +	bool pol = spi->mode & SPI_CS_HIGH;
> +	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
> +
> +	if (value == BITBANG_CS_INACTIVE) {
> +		if (pdata->cs_control)
> +			pdata->cs_control(spi, !pol);
> +	}
> +
> +	if (value == BITBANG_CS_ACTIVE) {
> +		mpc8xxx_spi->rx_shift = cs->rx_shift;
> +		mpc8xxx_spi->tx_shift = cs->tx_shift;
> +		mpc8xxx_spi->get_rx = cs->get_rx;
> +		mpc8xxx_spi->get_tx = cs->get_tx;
> +
> +		fsl_spi_change_mode(spi);
> +
> +		if (pdata->cs_control)
> +			pdata->cs_control(spi, pol);
> +	}
> +}
> +
> +static int
> +mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
> +			   struct spi_device *spi,
> +			   struct mpc8xxx_spi *mpc8xxx_spi,
> +			   int bits_per_word)
> +{
> +	cs->rx_shift = 0;
> +	cs->tx_shift = 0;
> +	if (bits_per_word <= 8) {
> +		cs->get_rx = mpc8xxx_spi_rx_buf_u8;
> +		cs->get_tx = mpc8xxx_spi_tx_buf_u8;
> +		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
> +			cs->rx_shift = 16;
> +			cs->tx_shift = 24;
> +		}
> +	} else if (bits_per_word <= 16) {
> +		cs->get_rx = mpc8xxx_spi_rx_buf_u16;
> +		cs->get_tx = mpc8xxx_spi_tx_buf_u16;
> +		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
> +			cs->rx_shift = 16;
> +			cs->tx_shift = 16;
> +		}
> +	} else if (bits_per_word <= 32) {
> +		cs->get_rx = mpc8xxx_spi_rx_buf_u32;
> +		cs->get_tx = mpc8xxx_spi_tx_buf_u32;
> +	} else
> +		return -EINVAL;
> +
> +	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE &&
> +	    spi->mode & SPI_LSB_FIRST) {
> +		cs->tx_shift = 0;
> +		if (bits_per_word <= 8)
> +			cs->rx_shift = 8;
> +		else
> +			cs->rx_shift = 0;
> +	}
> +	mpc8xxx_spi->rx_shift = cs->rx_shift;
> +	mpc8xxx_spi->tx_shift = cs->tx_shift;
> +	mpc8xxx_spi->get_rx = cs->get_rx;
> +	mpc8xxx_spi->get_tx = cs->get_tx;
> +
> +	return bits_per_word;
> +}
> +
> +static int
> +mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
> +			  struct spi_device *spi,
> +			  int bits_per_word)
> +{
> +	/* QE uses Little Endian for words > 8
> +	 * so transform all words > 8 into 8 bits
> +	 * Unfortnatly that doesn't work for LSB so
> +	 * reject these for now */
> +	/* Note: 32 bits word, LSB works iff
> +	 * tfcr/rfcr is set to CPMFCR_GBL */
> +	if (spi->mode & SPI_LSB_FIRST &&
> +	    bits_per_word > 8)
> +		return -EINVAL;
> +	if (bits_per_word > 8)
> +		return 8; /* pretend its 8 bits */
> +	return bits_per_word;
> +}
> +
> +static
> +int fsl_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	int bits_per_word;
> +	u8 pm;
> +	u32 hz;
> +	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
> +
> +	mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +
> +	if (t) {
> +		bits_per_word = t->bits_per_word;
> +		hz = t->speed_hz;
> +	} else {
> +		bits_per_word = 0;
> +		hz = 0;
> +	}
> +
> +	/* spi_transfer level calls that work per-word */
> +	if (!bits_per_word)
> +		bits_per_word = spi->bits_per_word;
> +
> +	/* Make sure its a bit width we support [4..16, 32] */
> +	if ((bits_per_word < 4)
> +	    || ((bits_per_word > 16) && (bits_per_word != 32)))
> +		return -EINVAL;
> +
> +	if (!hz)
> +		hz = spi->max_speed_hz;
> +
> +	if (!(mpc8xxx_spi->flags & SPI_CPM_MODE))
> +		bits_per_word = mspi_apply_cpu_mode_quirks(cs, spi,
> +							   mpc8xxx_spi,
> +							   bits_per_word);
> +	else if (mpc8xxx_spi->flags & SPI_QE)
> +		bits_per_word = mspi_apply_qe_mode_quirks(cs, spi,
> +							  bits_per_word);
> +
> +	if (bits_per_word < 0)
> +		return bits_per_word;
> +
> +	if (bits_per_word == 32)
> +		bits_per_word = 0;
> +	else
> +		bits_per_word = bits_per_word - 1;
> +
> +	/* mask out bits we are going to set */
> +	cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16
> +				  | SPMODE_PM(0xF));
> +
> +	cs->hw_mode |= SPMODE_LEN(bits_per_word);
> +
> +	if ((mpc8xxx_spi->spibrg / hz) > 64) {
> +		cs->hw_mode |= SPMODE_DIV16;
> +		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
> +
> +		WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
> +			  "Will use %d Hz instead.\n", dev_name(&spi->dev),
> +			  hz, mpc8xxx_spi->spibrg / 1024);
> +		if (pm > 16)
> +			pm = 16;
> +	} else
> +		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
> +	if (pm)
> +		pm--;
> +
> +	cs->hw_mode |= SPMODE_PM(pm);
> +
> +	fsl_spi_change_mode(spi);
> +	return 0;
> +}
> +
> +static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
> +{
> +	struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd;
> +	struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
> +	unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
> +	unsigned int xfer_ofs;
> +
> +	xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
> +
> +	out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
> +	out_be16(&rx_bd->cbd_datlen, 0);
> +	out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
> +
> +	out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
> +	out_be16(&tx_bd->cbd_datlen, xfer_len);
> +	out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
> +				 BD_SC_LAST);
> +
> +	/* start transfer */
> +	mpc8xxx_spi_write_reg(&mspi->base->command, SPCOM_STR);
> +}
> +
> +static int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
> +				struct spi_transfer *t, bool is_dma_mapped)
> +{
> +	struct device *dev = mspi->dev;
> +
> +	if (is_dma_mapped) {
> +		mspi->map_tx_dma = 0;
> +		mspi->map_rx_dma = 0;
> +	} else {
> +		mspi->map_tx_dma = 1;
> +		mspi->map_rx_dma = 1;
> +	}
> +
> +	if (!t->tx_buf) {
> +		mspi->tx_dma = mspi->dma_dummy_tx;
> +		mspi->map_tx_dma = 0;
> +	}
> +
> +	if (!t->rx_buf) {
> +		mspi->rx_dma = mspi->dma_dummy_rx;
> +		mspi->map_rx_dma = 0;
> +	}
> +
> +	if (mspi->map_tx_dma) {
> +		void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */
> +
> +		mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len,
> +					      DMA_TO_DEVICE);
> +		if (dma_mapping_error(dev, mspi->tx_dma)) {
> +			dev_err(dev, "unable to map tx dma\n");
> +			return -ENOMEM;
> +		}
> +	} else if (t->tx_buf) {
> +		mspi->tx_dma = t->tx_dma;
> +	}
> +
> +	if (mspi->map_rx_dma) {
> +		mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len,
> +					      DMA_FROM_DEVICE);
> +		if (dma_mapping_error(dev, mspi->rx_dma)) {
> +			dev_err(dev, "unable to map rx dma\n");
> +			goto err_rx_dma;
> +		}
> +	} else if (t->rx_buf) {
> +		mspi->rx_dma = t->rx_dma;
> +	}
> +
> +	/* enable rx ints */
> +	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIE_RXB);
> +
> +	mspi->xfer_in_progress = t;
> +	mspi->count = t->len;
> +
> +	/* start CPM transfers */
> +	fsl_spi_cpm_bufs_start(mspi);
> +
> +	return 0;
> +
> +err_rx_dma:
> +	if (mspi->map_tx_dma)
> +		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
> +	return -ENOMEM;
> +}
> +
> +static void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
> +{
> +	struct device *dev = mspi->dev;
> +	struct spi_transfer *t = mspi->xfer_in_progress;
> +
> +	if (mspi->map_tx_dma)
> +		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
> +	if (mspi->map_rx_dma)
> +		dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
> +	mspi->xfer_in_progress = NULL;
> +}
> +
> +static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
> +			    bool is_dma_mapped)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +	unsigned int len = t->len;
> +	u8 bits_per_word;
> +	int ret;
> +
> +	bits_per_word = spi->bits_per_word;
> +	if (t->bits_per_word)
> +		bits_per_word = t->bits_per_word;
> +
> +	if (bits_per_word > 8) {
> +		/* invalid length? */
> +		if (len & 1)
> +			return -EINVAL;
> +		len /= 2;
> +	}
> +	if (bits_per_word > 16) {
> +		/* invalid length? */
> +		if (len & 1)
> +			return -EINVAL;
> +		len /= 2;
> +	}
> +
> +	mpc8xxx_spi->tx = t->tx_buf;
> +	mpc8xxx_spi->rx = t->rx_buf;
> +
> +	INIT_COMPLETION(mpc8xxx_spi->done);
> +
> +	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
> +		ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
> +	else
> +		ret = mpc8xxx_spi_bufs(mpc8xxx_spi, t, len);
> +	if (ret)
> +		return ret;
> +
> +	wait_for_completion(&mpc8xxx_spi->done);
> +
> +	/* disable rx ints */
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
> +
> +	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
> +		fsl_spi_cpm_bufs_complete(mpc8xxx_spi);
> +
> +	return mpc8xxx_spi->count;
> +}
> +
> +static void fsl_spi_do_one_msg(struct spi_message *m)
> +{
> +	struct spi_device *spi = m->spi;
> +	struct spi_transfer *t;
> +	unsigned int cs_change;
> +	const int nsecs = 50;
> +	int status;
> +
> +	cs_change = 1;
> +	status = 0;
> +	list_for_each_entry(t, &m->transfers, transfer_list) {
> +		if (t->bits_per_word || t->speed_hz) {
> +			/* Don't allow changes if CS is active */
> +			status = -EINVAL;
> +
> +			if (cs_change)
> +				status = fsl_spi_setup_transfer(spi, t);
> +			if (status < 0)
> +				break;
> +		}
> +
> +		if (cs_change) {
> +			fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE);
> +			ndelay(nsecs);
> +		}
> +		cs_change = t->cs_change;
> +		if (t->len)
> +			status = fsl_spi_bufs(spi, t, m->is_dma_mapped);
> +		if (status) {
> +			status = -EMSGSIZE;
> +			break;
> +		}
> +		m->actual_length += t->len;
> +
> +		if (t->delay_usecs)
> +			udelay(t->delay_usecs);
> +
> +		if (cs_change) {
> +			ndelay(nsecs);
> +			fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
> +			ndelay(nsecs);
> +		}
> +	}
> +
> +	m->status = status;
> +	m->complete(m->context);
> +
> +	if (status || !cs_change) {
> +		ndelay(nsecs);
> +		fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
> +	}
> +
> +	fsl_spi_setup_transfer(spi, NULL);
> +}
> +
> +static int fsl_spi_setup(struct spi_device *spi)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	int retval;
> +	u32 hw_mode;
> +	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
> +
> +	if (!spi->max_speed_hz)
> +		return -EINVAL;
> +
> +	if (!cs) {
> +		cs = kzalloc(sizeof *cs, GFP_KERNEL);
> +		if (!cs)
> +			return -ENOMEM;
> +		spi->controller_state = cs;
> +	}
> +	mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +
> +	hw_mode = cs->hw_mode; /* Save original settings */
> +	cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
> +	/* mask out bits we are going to set */
> +	cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
> +			 | SPMODE_REV | SPMODE_LOOP);
> +
> +	if (spi->mode & SPI_CPHA)
> +		cs->hw_mode |= SPMODE_CP_BEGIN_EDGECLK;
> +	if (spi->mode & SPI_CPOL)
> +		cs->hw_mode |= SPMODE_CI_INACTIVEHIGH;
> +	if (!(spi->mode & SPI_LSB_FIRST))
> +		cs->hw_mode |= SPMODE_REV;
> +	if (spi->mode & SPI_LOOP)
> +		cs->hw_mode |= SPMODE_LOOP;
> +
> +	retval = fsl_spi_setup_transfer(spi, NULL);
> +	if (retval < 0) {
> +		cs->hw_mode = hw_mode; /* Restore settings */
> +		return retval;
> +	}
> +	return 0;
> +}
> +
> +static void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
> +{
> +	u16 len;
> +
> +	dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
> +		in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
> +
> +	len = in_be16(&mspi->rx_bd->cbd_datlen);
> +	if (len > mspi->count) {
> +		WARN_ON(1);
> +		len = mspi->count;
> +	}
> +
> +	/* Clear the events */
> +	mpc8xxx_spi_write_reg(&mspi->base->event, events);
> +
> +	mspi->count -= len;
> +	if (mspi->count)
> +		fsl_spi_cpm_bufs_start(mspi);
> +	else
> +		complete(&mspi->done);
> +}
> +
> +static void fsl_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
> +{
> +	/* We need handle RX first */
> +	if (events & SPIE_NE) {
> +		u32 rx_data = mpc8xxx_spi_read_reg(&mspi->base->receive);
> +
> +		if (mspi->rx)
> +			mspi->get_rx(rx_data, mspi);
> +	}
> +
> +	if ((events & SPIE_NF) == 0)
> +		/* spin until TX is done */
> +		while (((events =
> +			mpc8xxx_spi_read_reg(&mspi->base->event)) &
> +						SPIE_NF) == 0)
> +			cpu_relax();
> +
> +	/* Clear the events */
> +	mpc8xxx_spi_write_reg(&mspi->base->event, events);
> +
> +	mspi->count -= 1;
> +	if (mspi->count) {
> +		u32 word = mspi->get_tx(mspi);
> +
> +		mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
> +	} else {
> +		complete(&mspi->done);
> +	}
> +}
> +
> +static void fsl_spi_irq(struct mpc8xxx_spi *mspi, u32 events)
> +{
> +	if (mspi->flags & SPI_CPM_MODE)
> +		fsl_spi_cpm_irq(mspi, events);
> +	else
> +		fsl_spi_cpu_irq(mspi, events);
> +}
> +
> +static void *fsl_spi_alloc_dummy_rx(void)
> +{
> +	mutex_lock(&fsl_dummy_rx_lock);
> +
> +	if (!fsl_dummy_rx)
> +		fsl_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
> +	if (fsl_dummy_rx)
> +		fsl_dummy_rx_refcnt++;
> +
> +	mutex_unlock(&fsl_dummy_rx_lock);
> +
> +	return fsl_dummy_rx;
> +}
> +
> +static void fsl_spi_free_dummy_rx(void)
> +{
> +	mutex_lock(&fsl_dummy_rx_lock);
> +
> +	switch (fsl_dummy_rx_refcnt) {
> +	case 0:
> +		WARN_ON(1);
> +		break;
> +	case 1:
> +		kfree(fsl_dummy_rx);
> +		fsl_dummy_rx = NULL;
> +		/* fall through */
> +	default:
> +		fsl_dummy_rx_refcnt--;
> +		break;
> +	}
> +
> +	mutex_unlock(&fsl_dummy_rx_lock);
> +}
> +
> +static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
> +{
> +	struct device *dev = mspi->dev;
> +	struct device_node *np = dev->of_node;
> +	const u32 *iprop;
> +	int size;
> +	unsigned long spi_base_ofs;
> +	unsigned long pram_ofs = -ENOMEM;
> +
> +	/* Can't use of_address_to_resource(), QE muram isn't at 0. */
> +	iprop = of_get_property(np, "reg", &size);
> +
> +	/* QE with a fixed pram location? */
> +	if (mspi->flags & SPI_QE && iprop && size == sizeof(*iprop) * 4)
> +		return cpm_muram_alloc_fixed(iprop[2], SPI_PRAM_SIZE);
> +
> +	/* QE but with a dynamic pram location? */
> +	if (mspi->flags & SPI_QE) {
> +		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
> +		qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, mspi->subblock,
> +				QE_CR_PROTOCOL_UNSPECIFIED, pram_ofs);
> +		return pram_ofs;
> +	}
> +
> +	/* CPM1 and CPM2 pram must be at a fixed addr. */
> +	if (!iprop || size != sizeof(*iprop) * 4)
> +		return -ENOMEM;
> +
> +	spi_base_ofs = cpm_muram_alloc_fixed(iprop[2], 2);
> +	if (IS_ERR_VALUE(spi_base_ofs))
> +		return -ENOMEM;
> +
> +	if (mspi->flags & SPI_CPM2) {
> +		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
> +		if (!IS_ERR_VALUE(pram_ofs)) {
> +			u16 __iomem *spi_base = cpm_muram_addr(spi_base_ofs);
> +
> +			out_be16(spi_base, pram_ofs);
> +		}
> +	} else {
> +		struct spi_pram __iomem *pram = cpm_muram_addr(spi_base_ofs);
> +		u16 rpbase = in_be16(&pram->rpbase);
> +
> +		/* Microcode relocation patch applied? */
> +		if (rpbase)
> +			pram_ofs = rpbase;
> +		else
> +			return spi_base_ofs;
> +	}
> +
> +	cpm_muram_free(spi_base_ofs);
> +	return pram_ofs;
> +}
> +
> +static int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
> +{
> +	struct device *dev = mspi->dev;
> +	struct device_node *np = dev->of_node;
> +	const u32 *iprop;
> +	int size;
> +	unsigned long pram_ofs;
> +	unsigned long bds_ofs;
> +
> +	if (!(mspi->flags & SPI_CPM_MODE))
> +		return 0;
> +
> +	if (!fsl_spi_alloc_dummy_rx())
> +		return -ENOMEM;
> +
> +	if (mspi->flags & SPI_QE) {
> +		iprop = of_get_property(np, "cell-index", &size);
> +		if (iprop && size == sizeof(*iprop))
> +			mspi->subblock = *iprop;
> +
> +		switch (mspi->subblock) {
> +		default:
> +			dev_warn(dev, "cell-index unspecified, assuming SPI1");
> +			/* fall through */
> +		case 0:
> +			mspi->subblock = QE_CR_SUBBLOCK_SPI1;
> +			break;
> +		case 1:
> +			mspi->subblock = QE_CR_SUBBLOCK_SPI2;
> +			break;
> +		}
> +	}
> +
> +	pram_ofs = fsl_spi_cpm_get_pram(mspi);
> +	if (IS_ERR_VALUE(pram_ofs)) {
> +		dev_err(dev, "can't allocate spi parameter ram\n");
> +		goto err_pram;
> +	}
> +
> +	bds_ofs = cpm_muram_alloc(sizeof(*mspi->tx_bd) +
> +				  sizeof(*mspi->rx_bd), 8);
> +	if (IS_ERR_VALUE(bds_ofs)) {
> +		dev_err(dev, "can't allocate bds\n");
> +		goto err_bds;
> +	}
> +
> +	mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE,
> +					    DMA_TO_DEVICE);
> +	if (dma_mapping_error(dev, mspi->dma_dummy_tx)) {
> +		dev_err(dev, "unable to map dummy tx buffer\n");
> +		goto err_dummy_tx;
> +	}
> +
> +	mspi->dma_dummy_rx = dma_map_single(dev, fsl_dummy_rx, SPI_MRBLR,
> +					    DMA_FROM_DEVICE);
> +	if (dma_mapping_error(dev, mspi->dma_dummy_rx)) {
> +		dev_err(dev, "unable to map dummy rx buffer\n");
> +		goto err_dummy_rx;
> +	}
> +
> +	mspi->pram = cpm_muram_addr(pram_ofs);
> +
> +	mspi->tx_bd = cpm_muram_addr(bds_ofs);
> +	mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
> +
> +	/* Initialize parameter ram. */
> +	out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd));
> +	out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd));
> +	out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL);
> +	out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL);
> +	out_be16(&mspi->pram->mrblr, SPI_MRBLR);
> +	out_be32(&mspi->pram->rstate, 0);
> +	out_be32(&mspi->pram->rdp, 0);
> +	out_be16(&mspi->pram->rbptr, 0);
> +	out_be16(&mspi->pram->rbc, 0);
> +	out_be32(&mspi->pram->rxtmp, 0);
> +	out_be32(&mspi->pram->tstate, 0);
> +	out_be32(&mspi->pram->tdp, 0);
> +	out_be16(&mspi->pram->tbptr, 0);
> +	out_be16(&mspi->pram->tbc, 0);
> +	out_be32(&mspi->pram->txtmp, 0);
> +
> +	return 0;
> +
> +err_dummy_rx:
> +	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
> +err_dummy_tx:
> +	cpm_muram_free(bds_ofs);
> +err_bds:
> +	cpm_muram_free(pram_ofs);
> +err_pram:
> +	fsl_spi_free_dummy_rx();
> +	return -ENOMEM;
> +}
> +
> +static void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
> +{
> +	struct device *dev = mspi->dev;
> +
> +	dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
> +	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
> +	cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
> +	cpm_muram_free(cpm_muram_offset(mspi->pram));
> +	fsl_spi_free_dummy_rx();
> +}
> +
> +static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
> +{
> +	fsl_spi_cpm_free(mspi);
> +}
> +
> +static struct spi_master * __devinit
> +fsl_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
> +{
> +	struct fsl_spi_platform_data *pdata = dev->platform_data;
> +	struct spi_master *master;
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	u32 regval;
> +	int ret = 0;
> +
> +	master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
> +	if (master == NULL) {
> +		ret = -ENOMEM;
> +		goto err;
> +	}
> +
> +	dev_set_drvdata(dev, master);
> +
> +	ret = mpc8xxx_spi_probe(dev, mem, irq);
> +	if (ret)
> +		goto err_probe;
> +
> +	master->setup = fsl_spi_setup;
> +
> +	mpc8xxx_spi = spi_master_get_devdata(master);
> +	mpc8xxx_spi->spi_do_one_msg = fsl_spi_do_one_msg;
> +	mpc8xxx_spi->spi_remove = fsl_spi_remove;
> +	mpc8xxx_spi->spi_irq = fsl_spi_irq;
> +
> +	ret = fsl_spi_cpm_init(mpc8xxx_spi);
> +	if (ret)
> +		goto err_probe;
> +
> +	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
> +		mpc8xxx_spi->rx_shift = 16;
> +		mpc8xxx_spi->tx_shift = 24;
> +	}
> +
> +	/* SPI controller initializations */
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0);
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0);
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff);
> +
> +	/* Enable SPI interface */
> +	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
> +	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
> +		regval |= SPMODE_OP;
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
> +
> +	ret = spi_register_master(master);
> +	if (ret < 0)
> +		goto unreg_master;
> +
> +	dev_info(dev, "at 0x%p (irq = %d), %s mode\n", mpc8xxx_spi->base,
> +		 mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
> +
> +	return master;
> +
> +unreg_master:
> +	fsl_spi_cpm_free(mpc8xxx_spi);
> +err_probe:
> +	spi_master_put(master);
> +err:
> +	return ERR_PTR(ret);
> +}
> +
> +static void fsl_spi_cs_control(struct spi_device *spi, bool on)
> +{
> +	struct device *dev = spi->dev.parent;
> +	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
> +	u16 cs = spi->chip_select;
> +	int gpio = pinfo->gpios[cs];
> +	bool alow = pinfo->alow_flags[cs];
> +
> +	gpio_set_value(gpio, on ^ alow);
> +}
> +
> +static int of_fsl_spi_get_chipselects(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct fsl_spi_platform_data *pdata = dev->platform_data;
> +	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
> +	unsigned int ngpios;
> +	int i = 0;
> +	int ret;
> +
> +	ngpios = of_gpio_count(np);
> +	if (!ngpios) {
> +		/*
> +		 * SPI w/o chip-select line. One SPI device is still permitted
> +		 * though.
> +		 */
> +		pdata->max_chipselect = 1;
> +		return 0;
> +	}
> +
> +	pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
> +	if (!pinfo->gpios)
> +		return -ENOMEM;
> +	memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
> +
> +	pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
> +				    GFP_KERNEL);
> +	if (!pinfo->alow_flags) {
> +		ret = -ENOMEM;
> +		goto err_alloc_flags;
> +	}
> +
> +	for (; i < ngpios; i++) {
> +		int gpio;
> +		enum of_gpio_flags flags;
> +
> +		gpio = of_get_gpio_flags(np, i, &flags);
> +		if (!gpio_is_valid(gpio)) {
> +			dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
> +			ret = gpio;
> +			goto err_loop;
> +		}
> +
> +		ret = gpio_request(gpio, dev_name(dev));
> +		if (ret) {
> +			dev_err(dev, "can't request gpio #%d: %d\n", i, ret);
> +			goto err_loop;
> +		}
> +
> +		pinfo->gpios[i] = gpio;
> +		pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW;
> +
> +		ret = gpio_direction_output(pinfo->gpios[i],
> +					    pinfo->alow_flags[i]);
> +		if (ret) {
> +			dev_err(dev, "can't set output direction for gpio "
> +				"#%d: %d\n", i, ret);
> +			goto err_loop;
> +		}
> +	}
> +
> +	pdata->max_chipselect = ngpios;
> +	pdata->cs_control = fsl_spi_cs_control;
> +
> +	return 0;
> +
> +err_loop:
> +	while (i >= 0) {
> +		if (gpio_is_valid(pinfo->gpios[i]))
> +			gpio_free(pinfo->gpios[i]);
> +		i--;
> +	}
> +
> +	kfree(pinfo->alow_flags);
> +	pinfo->alow_flags = NULL;
> +err_alloc_flags:
> +	kfree(pinfo->gpios);
> +	pinfo->gpios = NULL;
> +	return ret;
> +}
> +
> +static int of_fsl_spi_free_chipselects(struct device *dev)
> +{
> +	struct fsl_spi_platform_data *pdata = dev->platform_data;
> +	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
> +	int i;
> +
> +	if (!pinfo->gpios)
> +		return 0;
> +
> +	for (i = 0; i < pdata->max_chipselect; i++) {
> +		if (gpio_is_valid(pinfo->gpios[i]))
> +			gpio_free(pinfo->gpios[i]);
> +	}
> +
> +	kfree(pinfo->gpios);
> +	kfree(pinfo->alow_flags);
> +	return 0;
> +}
> +
> +static int __devinit of_fsl_spi_probe(struct of_device *ofdev,
> +					  const struct of_device_id *ofid)
> +{
> +	struct device *dev = &ofdev->dev;
> +	struct device_node *np = ofdev->dev.of_node;
> +	struct spi_master *master;
> +	struct resource mem;
> +	struct resource irq;
> +	int ret = -ENOMEM;
> +
> +	ret = of_mpc8xxx_spi_probe(ofdev, ofid);
> +	if (ret)
> +		return ret;
> +
> +	ret = of_fsl_spi_get_chipselects(dev);
> +	if (ret)
> +		goto err;
> +
> +	ret = of_address_to_resource(np, 0, &mem);
> +	if (ret)
> +		goto err;
> +
> +	ret = of_irq_to_resource(np, 0, &irq);
> +	if (!ret) {
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +
> +	master = fsl_spi_probe(dev, &mem, irq.start);
> +	if (IS_ERR(master)) {
> +		ret = PTR_ERR(master);
> +		goto err;
> +	}
> +
> +	of_register_spi_devices(master, np);
> +
> +	return 0;
> +
> +err:
> +	of_fsl_spi_free_chipselects(dev);
> +	return ret;
> +}
> +
> +static int __devexit of_fsl_spi_remove(struct of_device *ofdev)
> +{
> +	int ret;
> +
> +	ret = mpc8xxx_spi_remove(&ofdev->dev);
> +	if (ret)
> +		return ret;
> +	of_fsl_spi_free_chipselects(&ofdev->dev);
> +	return 0;
> +}
> +
> +static const struct of_device_id of_fsl_spi_match[] = {
> +	{ .compatible = "fsl,spi" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, of_fsl_spi_match);
> +
> +static struct of_platform_driver of_fsl_spi_driver = {
> +	.driver = {
> +		.name = "fsl_spi",
> +		.owner = THIS_MODULE,
> +		.of_match_table = of_fsl_spi_match,
> +	},
> +	.probe		= of_fsl_spi_probe,
> +	.remove		= __devexit_p(of_fsl_spi_remove),
> +};
> +
> +#ifdef CONFIG_MPC832x_RDB
> +/*
> + * XXX XXX XXX
> + * This is "legacy" platform driver, was used by the MPC8323E-RDB boards
> + * only. The driver should go away soon, since newer MPC8323E-RDB's device
> + * tree can work with OpenFirmware driver. But for now we support old trees
> + * as well.
> + */
> +static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
> +{
> +	struct resource *mem;
> +	int irq;
> +	struct spi_master *master;
> +
> +	if (!pdev->dev.platform_data)
> +		return -EINVAL;
> +
> +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!mem)
> +		return -EINVAL;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq <= 0)
> +		return -EINVAL;
> +
> +	master = fsl_spi_probe(&pdev->dev, mem, irq);
> +	if (IS_ERR(master))
> +		return PTR_ERR(master);
> +	return 0;
> +}
> +
> +static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
> +{
> +	return mpc8xxx_spi_remove(&pdev->dev);
> +}
> +
> +MODULE_ALIAS("platform:mpc8xxx_spi");
> +static struct platform_driver mpc8xxx_spi_driver = {
> +	.probe = plat_mpc8xxx_spi_probe,
> +	.remove = __devexit_p(plat_mpc8xxx_spi_remove),
> +	.driver = {
> +		.name = "mpc8xxx_spi",
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +static bool legacy_driver_failed;
> +
> +static void __init legacy_driver_register(void)
> +{
> +	legacy_driver_failed = platform_driver_register(&mpc8xxx_spi_driver);
> +}
> +
> +static void __exit legacy_driver_unregister(void)
> +{
> +	if (legacy_driver_failed)
> +		return;
> +	platform_driver_unregister(&mpc8xxx_spi_driver);
> +}
> +#else
> +static void __init legacy_driver_register(void) {}
> +static void __exit legacy_driver_unregister(void) {}
> +#endif /* CONFIG_MPC832x_RDB */
> +
> +static int __init fsl_spi_init(void)
> +{
> +	legacy_driver_register();
> +	return of_register_platform_driver(&of_fsl_spi_driver);
> +}
> +
> +static void __exit fsl_spi_exit(void)
> +{
> +	of_unregister_platform_driver(&of_fsl_spi_driver);
> +	legacy_driver_unregister();
> +}

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

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

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

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

^ permalink raw reply

* Re: [PATCH 2/6] eSPI: add eSPI controller support
From: Grant Likely @ 2010-07-26  0:25 UTC (permalink / raw)
  To: Mingkai Hu; +Cc: linuxppc-dev
In-Reply-To: <1279591705-7574-3-git-send-email-Mingkai.hu@freescale.com>

On Tue, Jul 20, 2010 at 10:08:21AM +0800, Mingkai Hu wrote:
> Add eSPI controller support based on the common code spi_mpc8xxx.c.
> 
> The eSPI controller is newer controller 85xx/Pxxx devices supported.
> There're some differences comparing to the SPI controller:
> 
> 1. Has different register map and different bit definition
>    So leave the code operated the register to the driver code, not
>    the common code.
> 
> 2. Support 4 dedicated chip selects
>    The software can't controll the chip selects directly, The SPCOM[CS]
>    field is used to select which chip selects is used, and the
>    SPCOM[TRANLEN] field is set to tell the controller how long the CS
>    signal need to be asserted. So the driver doesn't need the chipselect
>    related function when transfering data, just set corresponding register
>    fields to controll the chipseclect.
> 
> 3. Different Transmit/Receive FIFO access register behavior
>    For SPI controller, the Tx/Rx FIFO access register can hold only
>    one character regardless of the character length, but for eSPI
>    controller, the register can hold 4 or 2 characters according to
>    the character lengths. Access the Tx/Rx FIFO access register of the
>    eSPI controller will shift out/in 4/2 characters one time, so all the
>    transfers in the same message are needed to combine to one transfer.
> 
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> ---
>  drivers/spi/Kconfig       |    7 +
>  drivers/spi/Makefile      |    1 +
>  drivers/spi/fsl_espi.c    |  562 +++++++++++++++++++++++++++++++++++++++++++++
>  drivers/spi/spi_mpc8xxx.h |   12 +
>  4 files changed, 582 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/spi/fsl_espi.c
> 
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index cd564e2..c647a00 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -196,6 +196,13 @@ config SPI_FSL_SPI
>  	help
>  	  This enables using the Freescale SPI controllers in master mode.
>  
> +config SPI_FSL_ESPI
> +	tristate "Freescale eSPI controller"
> +	depends on FSL_SOC
> +	select SPI_MPC8xxx
> +	help
> +	  This enables using the Freescale eSPI controllers in master mode.
> +

Ditto from last patch.  config SPI_MPC8xxx_SPI

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

spi_mpc8xxx_espi.o

>  obj-$(CONFIG_SPI_PPC4xx)		+= spi_ppc4xx.o
>  obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
>  obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx_hw.o
> diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c
> new file mode 100644
> index 0000000..ac70c8c
> --- /dev/null
> +++ b/drivers/spi/fsl_espi.c
> @@ -0,0 +1,562 @@
> +/*
> + * MPC8xxx eSPI controller driver.
> + *
> + * Copyright 2010 Freescale Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + */
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/irq.h>
> +#include <linux/spi/spi.h>
> +#include <linux/platform_device.h>
> +#include <linux/fsl_devices.h>
> +#include <linux/mm.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_spi.h>
> +#include <sysdev/fsl_soc.h>
> +
> +#include "spi_mpc8xxx.h"
> +
> +/* eSPI Controller mode register definitions */
> +#define SPMODE_ENABLE		(1 << 31)
> +#define SPMODE_LOOP		(1 << 30)
> +#define SPMODE_TXTHR(x)		((x) << 8)
> +#define SPMODE_RXTHR(x)		((x) << 0)
> +
> +/* eSPI Controller CS mode register definitions */
> +#define CSMODE_CI_INACTIVEHIGH	(1 << 31)
> +#define CSMODE_CP_BEGIN_EDGECLK	(1 << 30)
> +#define CSMODE_REV		(1 << 29)
> +#define CSMODE_DIV16		(1 << 28)
> +#define CSMODE_PM(x)		((x) << 24)
> +#define CSMODE_POL_1		(1 << 20)
> +#define CSMODE_LEN(x)		((x) << 16)
> +#define CSMODE_BEF(x)		((x) << 12)
> +#define CSMODE_AFT(x)		((x) << 8)
> +#define CSMODE_CG(x)		((x) << 3)
> +
> +/* Default mode/csmode for eSPI controller */
> +#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3))
> +#define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \
> +			| CSMODE_AFT(0) | CSMODE_CG(1))
> +
> +/* SPIE register values */
> +#define	SPIE_NE		0x00000200	/* Not empty */
> +#define	SPIE_NF		0x00000100	/* Not full */
> +
> +/* SPIM register values */
> +#define	SPIM_NE		0x00000200	/* Not empty */
> +#define	SPIM_NF		0x00000100	/* Not full */
> +#define SPIE_RXCNT(reg)     ((reg >> 24) & 0x3F)
> +#define SPIE_TXCNT(reg)     ((reg >> 16) & 0x3F)
> +
> +/* SPCOM register values */
> +#define SPCOM_CS(x)		((x) << 30)
> +#define SPCOM_TRANLEN(x)	((x) << 0)
> +#define	SPCOM_TRANLEN_MAX	0xFFFF	/* Max transaction length */

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

> +
> +static void fsl_espi_change_mode(struct spi_device *spi)
> +{
> +	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
> +	struct spi_mpc8xxx_cs *cs = spi->controller_state;
> +	__be32 __iomem *mode;
> +	__be32 __iomem *espi_mode = NULL;
> +	u32 tmp;
> +	unsigned long flags;
> +
> +	espi_mode = &mspi->base->mode;
> +	mode = &mspi->base->csmode[spi->chip_select];
> +
> +	/* Turn off IRQs locally to minimize time that SPI is disabled. */
> +	local_irq_save(flags);
> +
> +	/* Turn off SPI unit prior changing mode */
> +	tmp = mpc8xxx_spi_read_reg(espi_mode);
> +	mpc8xxx_spi_write_reg(espi_mode, tmp & ~SPMODE_ENABLE);
> +	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
> +	mpc8xxx_spi_write_reg(espi_mode, tmp);
> +
> +	local_irq_restore(flags);
> +}
> +
> +static u32 fsl_espi_tx_buf_lsb(struct mpc8xxx_spi *mpc8xxx_spi)
> +{
> +	u32 data;
> +	u16 data_h, data_l;
> +
> +	const u32 *tx = mpc8xxx_spi->tx;
> +	if (!tx)
> +		return 0;
> +
> +	data = *tx++ << mpc8xxx_spi->tx_shift;
> +	data_l = data & 0xffff;
> +	data_h = (data >> 16) & 0xffff;
> +	swab16s(&data_l);
> +	swab16s(&data_h);
> +	data = data_h | data_l;
> +
> +	mpc8xxx_spi->tx = tx;
> +	return data;
> +}
> +
> +static
> +int fsl_espi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)

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

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

> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	u8 bits_per_word, pm;
> +	u32 hz;
> +	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
> +
> +	mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +
> +	if (t) {
> +		bits_per_word = t->bits_per_word;
> +		hz = t->speed_hz;
> +	} else {
> +		bits_per_word = 0;
> +		hz = 0;
> +	}

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

> +
> +	/* spi_transfer level calls that work per-word */
> +	if (!bits_per_word)
> +		bits_per_word = spi->bits_per_word;
> +
> +	/* Make sure its a bit width we support [4..16] */
> +	if ((bits_per_word < 4) || (bits_per_word > 16))
> +		return -EINVAL;
> +
> +	if (!hz)
> +		hz = spi->max_speed_hz;
> +
> +	cs->rx_shift = 0;
> +	cs->tx_shift = 0;
> +	cs->get_rx = mpc8xxx_spi_rx_buf_u32;
> +	cs->get_tx = mpc8xxx_spi_tx_buf_u32;
> +	if (bits_per_word <= 8) {
> +		cs->rx_shift = 8 - bits_per_word;
> +	} else if (bits_per_word <= 16) {
> +		cs->rx_shift = 16 - bits_per_word;
> +		if (spi->mode & SPI_LSB_FIRST)
> +			cs->get_tx = fsl_espi_tx_buf_lsb;
> +	} else
> +		return -EINVAL;
> +
> +	mpc8xxx_spi->rx_shift = cs->rx_shift;
> +	mpc8xxx_spi->tx_shift = cs->tx_shift;
> +	mpc8xxx_spi->get_rx = cs->get_rx;
> +	mpc8xxx_spi->get_tx = cs->get_tx;
> +
> +	bits_per_word = bits_per_word - 1;
> +
> +	/* mask out bits we are going to set */
> +	cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16
> +				  | CSMODE_PM(0xF));
> +
> +	cs->hw_mode |= CSMODE_LEN(bits_per_word);
> +
> +	if ((mpc8xxx_spi->spibrg / hz) > 64) {
> +		cs->hw_mode |= CSMODE_DIV16;
> +		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
> +
> +		WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
> +			  "Will use %d Hz instead.\n", dev_name(&spi->dev),
> +			  hz, mpc8xxx_spi->spibrg / 1024);
> +		if (pm > 16)
> +			pm = 16;
> +	} else
> +		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;

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

> +	if (pm)
> +		pm--;
> +
> +	cs->hw_mode |= CSMODE_PM(pm);
> +
> +	fsl_espi_change_mode(spi);
> +	return 0;
> +}
> +
> +static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t,
> +			    bool is_dma_mapped)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +	unsigned int len = t->len;
> +	u8 bits_per_word;
> +	int ret;
> +
> +	bits_per_word = spi->bits_per_word;
> +	if (t->bits_per_word)
> +		bits_per_word = t->bits_per_word;
> +
> +	mpc8xxx_spi->len = t->len;
> +	len = roundup(len, 4) / 4;
> +
> +	mpc8xxx_spi->tx = t->tx_buf;
> +	mpc8xxx_spi->rx = t->rx_buf;
> +
> +	INIT_COMPLETION(mpc8xxx_spi->done);
> +
> +	/* Set SPCOM[CS] and SPCOM[TRANLEN] field */
> +	if ((t->len - 1) > SPCOM_TRANLEN_MAX) {
> +		dev_err(mpc8xxx_spi->dev, "Transaction length (%d)"
> +				" beyond the SPCOM[TRANLEN] field\n", t->len);
> +		return -EINVAL;
> +	}
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command,
> +		(SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
> +
> +	ret = mpc8xxx_spi_bufs(mpc8xxx_spi, t, len);
> +	if (ret)
> +		return ret;
> +
> +	wait_for_completion(&mpc8xxx_spi->done);
> +
> +	/* disable rx ints */
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
> +
> +	return mpc8xxx_spi->count;
> +}
> +
> +static void fsl_espi_do_one_msg(struct spi_message *m)
> +{
> +	struct spi_device *spi = m->spi;
> +	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
> +	struct spi_message message;
> +	struct spi_transfer *t, *first, trans;
> +	u8 *local_buf, *rx_buf = NULL;
> +	unsigned int n_tx = 0;
> +	unsigned int n_rx = 0;
> +	int status = 0;
> +	int i = 0;
> +
> +	spi_message_init(&message);
> +	memset(&trans, 0, sizeof(trans));
> +
> +	first = list_first_entry(&m->transfers, struct spi_transfer,
> +			transfer_list);
> +	list_for_each_entry(t, &m->transfers, transfer_list) {
> +		if ((first->bits_per_word != t->bits_per_word) ||
> +			(first->speed_hz != t->speed_hz)) {
> +			status = -EINVAL;
> +			dev_err(mspi->dev, "bits_per_word/speed_hz should be"
> +					" same for the same SPI transfer\n");
> +			return;
> +		}
> +
> +		trans.speed_hz = t->speed_hz;
> +		trans.bits_per_word = t->bits_per_word;
> +		trans.delay_usecs = max(first->delay_usecs, t->delay_usecs);
> +
> +		if (t->tx_buf)
> +			n_tx += t->len;
> +
> +		if (t->rx_buf) {
> +			n_rx += t->len;
> +			rx_buf = t->rx_buf;
> +		}
> +	}
> +
> +	local_buf = kzalloc(n_tx * 2 + roundup(n_rx + n_tx, 4), GFP_KERNEL);
> +	if (!local_buf) {
> +		status = -ENOMEM;
> +		return;
> +	}
> +
> +	list_for_each_entry(t, &m->transfers, transfer_list) {
> +		if (t->tx_buf) {
> +			memcpy(local_buf + i, t->tx_buf, t->len);
> +			i += t->len;
> +		}
> +	}
> +
> +	trans.len = n_tx + n_rx;
> +	trans.tx_buf = local_buf;
> +	trans.rx_buf = local_buf + n_tx;
> +	spi_message_add_tail(&trans, &message);
> +
> +	list_for_each_entry(t, &message.transfers, transfer_list) {
> +		if (t->bits_per_word || t->speed_hz) {
> +			status = -EINVAL;
> +
> +			status = fsl_espi_setup_transfer(spi, t);
> +			if (status < 0)
> +				break;
> +		}
> +
> +		if (t->len)
> +			status = fsl_espi_bufs(spi, t, 0);
> +		if (status) {
> +			status = -EMSGSIZE;
> +			break;
> +		}
> +		m->actual_length += t->len;
> +
> +		if (rx_buf)
> +			memcpy(rx_buf, t->rx_buf + n_tx, n_rx);
> +
> +		if (t->delay_usecs)
> +			udelay(t->delay_usecs);
> +	}
> +
> +	m->status = status;
> +	m->complete(m->context);
> +
> +	fsl_espi_setup_transfer(spi, NULL);
> +	kfree(local_buf);
> +}
> +
> +static int fsl_espi_setup(struct spi_device *spi)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	int retval;
> +	u32 hw_mode;
> +	u32 loop_mode;
> +	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
> +
> +	if (!spi->max_speed_hz)
> +		return -EINVAL;
> +
> +	if (!cs) {
> +		cs = kzalloc(sizeof *cs, GFP_KERNEL);
> +		if (!cs)
> +			return -ENOMEM;
> +		spi->controller_state = cs;
> +	}
> +
> +	mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +
> +	hw_mode = cs->hw_mode; /* Save orginal settings */
> +	cs->hw_mode = mpc8xxx_spi_read_reg(
> +			&mpc8xxx_spi->base->csmode[spi->chip_select]);
> +	/* mask out bits we are going to set */
> +	cs->hw_mode &= ~(CSMODE_CP_BEGIN_EDGECLK | CSMODE_CI_INACTIVEHIGH
> +			 | CSMODE_REV);
> +
> +	if (spi->mode & SPI_CPHA)
> +		cs->hw_mode |= CSMODE_CP_BEGIN_EDGECLK;
> +	if (spi->mode & SPI_CPOL)
> +		cs->hw_mode |= CSMODE_CI_INACTIVEHIGH;
> +	if (!(spi->mode & SPI_LSB_FIRST))
> +		cs->hw_mode |= CSMODE_REV;
> +
> +	/* Handle the loop mode */
> +	loop_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
> +	loop_mode &= ~SPMODE_LOOP;
> +	if (spi->mode & SPI_LOOP)
> +		loop_mode |= SPMODE_LOOP;
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, loop_mode);
> +
> +	retval = fsl_espi_setup_transfer(spi, NULL);
> +	if (retval < 0) {
> +		cs->hw_mode = hw_mode; /* Restore settings */
> +		return retval;
> +	}
> +	return 0;
> +}
> +
> +static void fsl_espi_irq(struct mpc8xxx_spi *mspi, u32 events)
> +{
> +	/* We need handle RX first */
> +	if (events & SPIE_NE) {
> +		u32 rx_data;
> +
> +		/* Spin until RX is done */
> +		while (SPIE_RXCNT(events) < min(4, mspi->len)) {
> +			cpu_relax();
> +			events = mpc8xxx_spi_read_reg(&mspi->base->event);
> +		}
> +		mspi->len -= 4;
> +
> +		rx_data = mpc8xxx_spi_read_reg(&mspi->base->receive);
> +
> +		if (mspi->rx)
> +			mspi->get_rx(rx_data, mspi);
> +	}
> +
> +	if ((events & SPIE_NF) == 0)
> +		/* spin until TX is done */
> +		while (((events =
> +			mpc8xxx_spi_read_reg(&mspi->base->event)) &
> +						SPIE_NF) == 0)
> +			cpu_relax();
> +
> +	/* Clear the events */
> +	mpc8xxx_spi_write_reg(&mspi->base->event, events);
> +
> +	mspi->count -= 1;
> +	if (mspi->count) {
> +		u32 word = mspi->get_tx(mspi);
> +
> +		mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
> +	} else {
> +		complete(&mspi->done);
> +	}
> +}
> +
> +static struct spi_master * __devinit
> +fsl_espi_probe(struct device *dev, struct resource *mem, unsigned int irq)
> +{
> +	struct fsl_spi_platform_data *pdata = dev->platform_data;
> +	struct spi_master *master;
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	u32 regval;
> +	int i, ret = 0;
> +
> +	master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
> +	if (master == NULL) {
> +		ret = -ENOMEM;
> +		goto err;
> +	}
> +
> +	dev_set_drvdata(dev, master);
> +
> +	ret = mpc8xxx_spi_probe(dev, mem, irq);
> +	if (ret)
> +		goto err_probe;
> +
> +	master->setup = fsl_espi_setup;
> +
> +	mpc8xxx_spi = spi_master_get_devdata(master);
> +	mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg;
> +	mpc8xxx_spi->spi_remove = NULL;
> +	mpc8xxx_spi->spi_irq = fsl_espi_irq;
> +
> +	/* SPI controller initializations */
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0);
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0);
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff);
> +
> +	/* Init eSPI CS mode register */
> +	for (i = 0; i < pdata->max_chipselect; i++)
> +		mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->csmode[i],
> +				CSMODE_INIT_VAL);
> +
> +	/* Enable SPI interface */
> +	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
> +
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
> +
> +	ret = spi_register_master(master);
> +	if (ret < 0)
> +		goto unreg_master;
> +
> +	dev_info(dev, "at 0x%p (irq = %d)\n", mpc8xxx_spi->base,
> +			mpc8xxx_spi->irq);
> +
> +	return master;
> +
> +unreg_master:
> +err_probe:
> +	spi_master_put(master);
> +err:
> +	return ERR_PTR(ret);
> +}
> +
> +static int of_fsl_espi_get_chipselects(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct fsl_spi_platform_data *pdata = dev->platform_data;
> +	const u32 *prop;
> +	int len;
> +
> +	prop = of_get_property(np, "fsl,espi-num-chipselects", &len);
> +	if (!prop || len < sizeof(*prop)) {
> +		dev_err(dev, "No 'fsl,espi-num-chipselects' property\n");
> +		return -EINVAL;
> +	}
> +
> +	pdata->max_chipselect = *prop;
> +	pdata->cs_control = NULL;
> +
> +	return 0;
> +}
> +
> +static int __devinit of_fsl_espi_probe(struct of_device *ofdev,
> +					  const struct of_device_id *ofid)
> +{
> +	struct device *dev = &ofdev->dev;
> +	struct device_node *np = ofdev->dev.of_node;
> +	struct spi_master *master;
> +	struct resource mem;
> +	struct resource irq;
> +	int ret = -ENOMEM;
> +
> +	ret = of_mpc8xxx_spi_probe(ofdev, ofid);
> +	if (ret)
> +		return ret;
> +
> +	ret = of_fsl_espi_get_chipselects(dev);
> +	if (ret)
> +		goto err;
> +
> +	ret = of_address_to_resource(np, 0, &mem);
> +	if (ret)
> +		goto err;
> +
> +	ret = of_irq_to_resource(np, 0, &irq);
> +	if (!ret) {
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +
> +	master = fsl_espi_probe(dev, &mem, irq.start);
> +	if (IS_ERR(master)) {
> +		ret = PTR_ERR(master);
> +		goto err;
> +	}
> +
> +	of_register_spi_devices(master, np);
> +
> +	return 0;
> +
> +err:
> +	return ret;
> +}
> +
> +static int __devexit of_fsl_espi_remove(struct of_device *ofdev)
> +{
> +	int ret;
> +
> +	ret = mpc8xxx_spi_remove(&ofdev->dev);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id of_fsl_espi_match[] = {
> +	{ .compatible = "fsl,espi" },

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

> +	{},

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

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

Move module_init() to right below fsl_espi_init.

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

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

>  };
>  
>  /* SPI Controller driver's private data. */
> @@ -37,6 +48,7 @@ struct mpc8xxx_spi {
>  	/* rx & tx bufs from the spi_transfer */
>  	const void *tx;
>  	void *rx;
> +	int len;
>  
>  	int subblock;
>  	struct spi_pram __iomem *pram;
> -- 
> 1.6.4
> 
> 

^ permalink raw reply

* Re: [PATCH 3/6] of/spi: add support to parse the SPI flash's partitions
From: Grant Likely @ 2010-07-26  0:28 UTC (permalink / raw)
  To: Mingkai Hu; +Cc: linuxppc-dev
In-Reply-To: <1279591705-7574-4-git-send-email-Mingkai.hu@freescale.com>

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

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

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

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

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

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

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox