* Re: [PATCH 2/3] Use embedded libfdt in the bootwrapper
From: Scott Wood @ 2007-12-10 23:27 UTC (permalink / raw)
To: Scott Wood, linuxppc-dev, Paul Mackerras
In-Reply-To: <475DC966.6070301@freescale.com>
Scott Wood wrote:
> David Gibson wrote:
>> On Mon, Dec 10, 2007 at 11:32:17AM -0600, Scott Wood wrote:
>>> How does using offsets as devps work if a devp was previously
>>> acquired to a node that has to be moved due to a change later made
>>> in an earlier part of the tree?
>>
>> It doesn't; don't do that. I just don't think truly persistent
>> phandles are worth the code complexity to implement them.
[snip]
> It breaks the extremely common and useful usage of:
>
> devp = create node;
> setprop(devp, "foo", something);
> setprop(devp, "bar", something);
BTW, there's code in devtree.c with your name on it that does exactly
this. :-)
-Scott
^ permalink raw reply
* Re: [PATCH RFC 7/7] [POWERPC] MPC8360E-RDK: add support for NAND on UPM
From: Anton Vorontsov @ 2007-12-10 23:16 UTC (permalink / raw)
To: Anton Vorontsov, linuxppc-dev
In-Reply-To: <20071210230321.GA5495@localhost.localdomain>
On Tue, Dec 11, 2007 at 10:03:21AM +1100, David Gibson wrote:
> On Mon, Dec 10, 2007 at 11:49:51PM +0300, Anton Vorontsov wrote:
> > Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> > ---
> > arch/powerpc/boot/dts/mpc836x_rdk.dts | 24 +++++++++++++++++++++++-
> > arch/powerpc/platforms/83xx/Kconfig | 2 ++
> > arch/powerpc/platforms/83xx/mpc836x_rdk.c | 1 +
> > 3 files changed, 26 insertions(+), 1 deletions(-)
> >
> > diff --git a/arch/powerpc/boot/dts/mpc836x_rdk.dts b/arch/powerpc/boot/dts/mpc836x_rdk.dts
> > index a1b2da6..f57ba53 100644
> > --- a/arch/powerpc/boot/dts/mpc836x_rdk.dts
> > +++ b/arch/powerpc/boot/dts/mpc836x_rdk.dts
> > @@ -115,7 +115,7 @@
> > device_type = "ipic";
> > };
> >
> > - par_io@1400 {
> > + qe_pio: par_io@1400 {
> > reg = <0x1400 0x100>;
> > num-ports = <7>;
> > };
> > @@ -229,4 +229,26 @@
> > interrupt-parent = <&ipic>;
> > };
> > };
> > +
> > + localbus@e0005000 {
> > + #address-cells = <2>;
> > + #size-cells = <1>;
> > + compatible = "fsl,mpc8360erdk-localbus",
> > + "fsl,mpc8360e-localbus",
> > + "fsl,pq2pro-localbus";
> > + reg = <0xe0005000 0xd8>;
> > + ranges = <1 0 0x60000000 1>;
>
> The bridge translates a range one byte wide? I don't think so...
Nope, 4KB min, IIRC.
> > +
> > + nand-flash@1,0 {
> > + compatible = "STMicro,NAND512W3A2BN6E", "fsl,upm-nand";
> > + reg = <1 0 1>;
>
> The device has a register window *one byte* wide? That seems
> improbable...
Here, actually yes. The device just 8 bits wide. Reading next 8 bits
will return the same value, obviously. ;-)
But points taken. I should not derivate chip width from the
ranges/reg. This looks unusual indeed, will implement chip-width
property.
Thanks,
--
Anton Vorontsov
email: cbou@mail.ru
backup email: ya-cbou@yandex.ru
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH RFC 0/7] "NAND on UPM" and related patches
From: Anton Vorontsov @ 2007-12-10 23:10 UTC (permalink / raw)
To: Anton Vorontsov, linuxppc-dev
In-Reply-To: <20071210230453.GB5495@localhost.localdomain>
On Tue, Dec 11, 2007 at 10:04:53AM +1100, David Gibson wrote:
> On Mon, Dec 10, 2007 at 11:47:05PM +0300, Anton Vorontsov wrote:
> > Hi all,
> >
> > Here are patches to support NAND on UPM. That driver is generic for
> > all processors with FSL UPMs. And because of that, few more patches are
> > needed -- GPIO API and generic FSL UPM functions.
> >
> > This is early RFC, all patches are in single thread, so everyone could
> > make up overall picture of what is going on. I'll split the thread by
> > topics after that RFC.
> >
> > Ok, the patches and what they are for:
> >
> > 1,2,3,4. GPIO API:
> > ------------------
> > Usually NAND chips exports RNB (Ready-Not-Busy) pin, so drivers
> > could read it and get a hint when chip is ready.
> >
> > Often, WP (write protect) pin is also connected to GPIO. So, GPIO API
> > is mandatory for generic drivers.
> >
> > OF device tree GPIOs bindings are similar to IRQs:
> >
> > node {
> > gpios = <bank pin bank pin bank pin>;
> > gpio-parent = <&par_io_controller>;
> > };
> >
> > "bank pin" scheme is controller specific, so controllers that want
> > to implement flat mappings or any other could do so.
>
> It might be safest to do as is done for interrupts, and not define the
> internal format at all.
This is how it is done already. Take a look into second and third patches:
+static int par_io_xlate(struct device_node *np, int index)
+{
+ return __of_parse_gpio_bank_pin(np, index, 32, num_par_io_ports);
+}
+
+static struct of_gpio_chip of_gpio_chip = {
+ .xlate = par_io_xlate,
+};
__of_parse_gpio_bank_pin() is helper function, I just factored
it out, because both QE and CPM2 using same format.
But generally, controllers are encouraged to do their own xlates.
Or am I missing the point?
> The gpio within the gpio controller would be
> defined by a gpio-descriptor whose format is determined by the
> controller. You would need to add a #gpio-cells property in this
> case, so you can at least determine the size of the descriptors
> associated with a particular gpio controller.
--
Anton Vorontsov
email: cbou@mail.ru
backup email: ya-cbou@yandex.ru
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH 2/3] Use embedded libfdt in the bootwrapper
From: Scott Wood @ 2007-12-10 23:19 UTC (permalink / raw)
To: Scott Wood, linuxppc-dev, Paul Mackerras
In-Reply-To: <20071210231056.GC5495@localhost.localdomain>
David Gibson wrote:
> On Mon, Dec 10, 2007 at 11:32:17AM -0600, Scott Wood wrote:
>> How does using offsets as devps work if a devp was previously
>> acquired to a node that has to be moved due to a change later made
>> in an earlier part of the tree?
>
> It doesn't; don't do that. I just don't think truly persistent
> phandles are worth the code complexity to implement them.
We already have working code to implement them. This is a regression
over flatdevicetree.c, and it (or something else in libfdt) seems to be
breaking the ep8248e wrapper (it didn't make it in to the last window
because of dependency on a netdev patch, but I'll probably send it out
tomorrow).
It breaks the extremely common and useful usage of:
devp = create node;
setprop(devp, "foo", something);
setprop(devp, "bar", something);
> Especially since their use more-or-less completely precludes libfdt's
> "stateless" approach, which has significant other advantages.
It doesn't preclude stateless read-only -- what are the benefits to
stateless read-write that are worth invalidating all node references any
time something changes?
-Scott
^ permalink raw reply
* Re: [PATCH RFC 4/7] [GPIO] Let drivers link if they support GPIO API as an addition
From: Anton Vorontsov @ 2007-12-10 23:04 UTC (permalink / raw)
To: David Brownell; +Cc: linuxppc-dev
In-Reply-To: <20071210225525.2F6C6266154@adsl-69-226-248-13.dsl.pltn13.pacbell.net>
On Mon, Dec 10, 2007 at 02:55:24PM -0800, David Brownell wrote:
> > I'm interested in your opinion about that patch. You're also Cc'ed
> > to patch that using that feature.
> >
> > I know, currently that patch will conflict with GPIOLIB patches in -mm,
> > so this is only RFC.
>
> The point of CONFIG_GENERIC_GPIO is to be *the* conditional used to
> tell whether that programming interface is available ... starting
> from "#include <asm/gpio.h>", and including all gpio_*() calls.
>
> So my first reaction is to not like this patch. It changes semantics
> in an incompatible way. And AFAICT, needlessly so.
Why incompatible? gpio-aware drivers will get -ENOSYS on gpio_request,
thus they will not do anything wrong. GPIO-only drivers could still
depend on GENERIC_GPIO, and their behaviour will not change.
> What other options did consider? Like, why not #ifdef the GPIO parts
> of that NAND driver,
Hehe, it's used to avoid #ifdef hell indeed. ;-) And no-op wrappers
like that I purposed is widely used to avoid #ifdefs. They will just
optimize away.
> or have the whole driver depend on GENERIC_GPIO?
Well, this is an option, and I was considering this. Further more,
I implemented gpio api for all platforms which currently using fsl
upm nand, so in theory I can add "depends on GENERIC_GPIO".
But the thing is: some drivers don't actually *require* gpios, they
can use it, but at the same time they might live without it.
As for fsl upm nand (the user of that change), it can poll status
from the nand chip instead of looking for RNB gpio. So, strict
depending on GENERIC_GPIO looks weird in that case.
Thanks,
--
Anton Vorontsov
email: cbou@mail.ru
backup email: ya-cbou@yandex.ru
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH 2/3] Use embedded libfdt in the bootwrapper
From: David Gibson @ 2007-12-10 23:10 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <20071210173217.GB4497@loki.buserror.net>
On Mon, Dec 10, 2007 at 11:32:17AM -0600, Scott Wood wrote:
> On Mon, Dec 10, 2007 at 02:28:39PM +1100, David Gibson wrote:
> > +#define check_err(err) \
> > + ({ \
> > + if (BAD_ERROR(err) || ((err < 0) && DEBUG)) \
> > + printf("%s():%d %s\n\r", __FUNCTION__, __LINE__, \
> > + fdt_strerror(err)); \
> > + if (BAD_ERROR(err)) \
> > + exit(); \
> > + (err < 0) ? -1 : 0; \
> > + })
> > +
> > +#define offset_devp(off) \
> > + ({ \
> > + int offset = (off); \
> > + check_err(offset) ? NULL : (void *)(offset+1); \
> > + })
> > +
> > +#define devp_offset(devp) (((int)(devp))-1)
>
> How does using offsets as devps work if a devp was previously acquired to a
> node that has to be moved due to a change later made in an earlier part of
> the tree?
It doesn't; don't do that. I just don't think truly persistent
phandles are worth the code complexity to implement them. Especially
since their use more-or-less completely precludes libfdt's "stateless"
approach, which has significant other advantages.
To reduce the confusion over this, the libfdt native interface always
refers to the offsets explicitly as offsets. For the bootwrapper
abstraction layer, unfortunately I'm stuck with the "devp" terminology
for the time being.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: [PATCH RFC 0/7] "NAND on UPM" and related patches
From: David Gibson @ 2007-12-10 23:04 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: linuxppc-dev
In-Reply-To: <20071210204705.GA31263@localhost.localdomain>
On Mon, Dec 10, 2007 at 11:47:05PM +0300, Anton Vorontsov wrote:
> Hi all,
>
> Here are patches to support NAND on UPM. That driver is generic for
> all processors with FSL UPMs. And because of that, few more patches are
> needed -- GPIO API and generic FSL UPM functions.
>
> This is early RFC, all patches are in single thread, so everyone could
> make up overall picture of what is going on. I'll split the thread by
> topics after that RFC.
>
> Ok, the patches and what they are for:
>
> 1,2,3,4. GPIO API:
> ------------------
> Usually NAND chips exports RNB (Ready-Not-Busy) pin, so drivers
> could read it and get a hint when chip is ready.
>
> Often, WP (write protect) pin is also connected to GPIO. So, GPIO API
> is mandatory for generic drivers.
>
> OF device tree GPIOs bindings are similar to IRQs:
>
> node {
> gpios = <bank pin bank pin bank pin>;
> gpio-parent = <&par_io_controller>;
> };
>
> "bank pin" scheme is controller specific, so controllers that want
> to implement flat mappings or any other could do so.
It might be safest to do as is done for interrupts, and not define the
internal format at all. The gpio within the gpio controller would be
defined by a gpio-descriptor whose format is determined by the
controller. You would need to add a #gpio-cells property in this
case, so you can at least determine the size of the descriptors
associated with a particular gpio controller.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: [PATCH RFC 7/7] [POWERPC] MPC8360E-RDK: add support for NAND on UPM
From: David Gibson @ 2007-12-10 23:03 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: linuxppc-dev
In-Reply-To: <20071210204951.GG32278@localhost.localdomain>
On Mon, Dec 10, 2007 at 11:49:51PM +0300, Anton Vorontsov wrote:
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
> arch/powerpc/boot/dts/mpc836x_rdk.dts | 24 +++++++++++++++++++++++-
> arch/powerpc/platforms/83xx/Kconfig | 2 ++
> arch/powerpc/platforms/83xx/mpc836x_rdk.c | 1 +
> 3 files changed, 26 insertions(+), 1 deletions(-)
>
> diff --git a/arch/powerpc/boot/dts/mpc836x_rdk.dts b/arch/powerpc/boot/dts/mpc836x_rdk.dts
> index a1b2da6..f57ba53 100644
> --- a/arch/powerpc/boot/dts/mpc836x_rdk.dts
> +++ b/arch/powerpc/boot/dts/mpc836x_rdk.dts
> @@ -115,7 +115,7 @@
> device_type = "ipic";
> };
>
> - par_io@1400 {
> + qe_pio: par_io@1400 {
> reg = <0x1400 0x100>;
> num-ports = <7>;
> };
> @@ -229,4 +229,26 @@
> interrupt-parent = <&ipic>;
> };
> };
> +
> + localbus@e0005000 {
> + #address-cells = <2>;
> + #size-cells = <1>;
> + compatible = "fsl,mpc8360erdk-localbus",
> + "fsl,mpc8360e-localbus",
> + "fsl,pq2pro-localbus";
> + reg = <0xe0005000 0xd8>;
> + ranges = <1 0 0x60000000 1>;
The bridge translates a range one byte wide? I don't think so...
> +
> + nand-flash@1,0 {
> + compatible = "STMicro,NAND512W3A2BN6E", "fsl,upm-nand";
> + reg = <1 0 1>;
The device has a register window *one byte* wide? That seems
improbable...
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: [PATCH] Fake NUMA emulation for PowerPC (Take 2)
From: Olof Johansson @ 2007-12-10 23:07 UTC (permalink / raw)
To: Balbir Singh; +Cc: linuxppc-dev, LKML
In-Reply-To: <20071207223714.11448.91386.sendpatchset@balbir-laptop>
On Sat, Dec 08, 2007 at 04:07:14AM +0530, Balbir Singh wrote:
> Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com>
Looks good to me. Sure, it could be fleshed out to something more
generic and in common code, but this is small and simple and doesn't
bloat the kernel much as it stands, and it has value for debugging.
Acked-by: Olof Johansson <olof@lixom.net>
^ permalink raw reply
* Re: [PATCH RFC 4/7] [GPIO] Let drivers link if they support GPIO API as an addition
From: David Brownell @ 2007-12-10 22:55 UTC (permalink / raw)
To: linuxppc-dev, avorontsov
In-Reply-To: <20071210204906.GD32278@localhost.localdomain>
> I'm interested in your opinion about that patch. You're also Cc'ed
> to patch that using that feature.
>
> I know, currently that patch will conflict with GPIOLIB patches in -mm,
> so this is only RFC.
The point of CONFIG_GENERIC_GPIO is to be *the* conditional used to
tell whether that programming interface is available ... starting
from "#include <asm/gpio.h>", and including all gpio_*() calls.
So my first reaction is to not like this patch. It changes semantics
in an incompatible way. And AFAICT, needlessly so.
What other options did consider? Like, why not #ifdef the GPIO parts
of that NAND driver, or have the whole driver depend on GENERIC_GPIO?
- Dave
^ permalink raw reply
* Re: [PATCH] Addition to the i2c series, copy the ppc mpc-i2c driver before changing it on powerpc
From: Jon Smirl @ 2007-12-10 22:54 UTC (permalink / raw)
To: Grant Likely; +Cc: PowerPC dev list
In-Reply-To: <fa686aa40712101444l448657c5jb6117e7a60715651@mail.gmail.com>
On 12/10/07, Grant Likely <grant.likely@secretlab.ca> wrote:
> On 12/10/07, Jon Smirl <jonsmirl@gmail.com> wrote:
> > Copy mpc-i2c to preserve support for ARCH=ppc and allow changes on ARCH=powerpc
> >
> > Temporarily copy the mpc-i2c driver to continue support for the ppc
> > architecture until it is removed in mid-2008. This file should be
> > deleted as part of ppc's final removal.
> >
> > Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
>
> For the record; I'm not fond of this approach. Supporting both bus
> bindings in the single driver is simple and results in less code churn
> when arch/ppc is removed, and encourages separation between the driver
> proper and the bus bindings which is just a good idea for all drivers
> in general.
But it also triggers a testing burden on a bunch of hardware that I
don't own. By copying off the known working ppc driver the testing
burden is avoided.
A subject for later discussion is whether platform bus should even
exist when of_platform_bus is in use. I have removed platform_bus for
the mpc5200 in my local builds. Removing platform bus exposed a bunch
of junk from other platofrms that had inadvertently accumulated into
the mpc5200 build.
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: [PATCH] Addition to the i2c series, copy the ppc mpc-i2c driver before changing it on powerpc
From: Jon Smirl @ 2007-12-10 22:48 UTC (permalink / raw)
To: Tony Breeds; +Cc: PowerPC dev list
In-Reply-To: <20071210224224.GF24243@bakeyournoodle.com>
Same patch minus the Makefile change. It was part of testing the builds.
Copy mpc-i2c to preserve support for ARCH=ppc and allow changes on ARCH=powerpc
Temporarily copy the mpc-i2c driver to continue support for the ppc
architecture until it is removed in mid-2008. This file should be
deleted as part of ppc's final removal.
Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---
arch/ppc/configs/TQM8540_defconfig | 2
arch/ppc/configs/TQM8541_defconfig | 2
arch/ppc/configs/TQM8555_defconfig | 2
arch/ppc/configs/TQM8560_defconfig | 2
arch/ppc/configs/mpc834x_sys_defconfig | 2
arch/ppc/configs/mpc8540_ads_defconfig | 2
arch/ppc/configs/mpc8548_cds_defconfig | 2
arch/ppc/configs/mpc8555_cds_defconfig | 2
arch/ppc/configs/mpc8560_ads_defconfig | 2
drivers/i2c/busses/Kconfig | 16 +
drivers/i2c/busses/Makefile | 1
drivers/i2c/busses/i2c-mpc-ppc.c | 418 ++++++++++++++++++++++++++++++++
12 files changed, 443 insertions(+), 10 deletions(-)
create mode 100644 drivers/i2c/busses/i2c-mpc-ppc.c
diff --git a/arch/ppc/configs/TQM8540_defconfig
b/arch/ppc/configs/TQM8540_defconfig
index f33f0e7..7098ed0 100644
--- a/arch/ppc/configs/TQM8540_defconfig
+++ b/arch/ppc/configs/TQM8540_defconfig
@@ -684,7 +684,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
diff --git a/arch/ppc/configs/TQM8541_defconfig
b/arch/ppc/configs/TQM8541_defconfig
index e00cd62..2137d01 100644
--- a/arch/ppc/configs/TQM8541_defconfig
+++ b/arch/ppc/configs/TQM8541_defconfig
@@ -687,7 +687,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_MPC8260 is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
diff --git a/arch/ppc/configs/TQM8555_defconfig
b/arch/ppc/configs/TQM8555_defconfig
index 43a0d9d..f2317b6 100644
--- a/arch/ppc/configs/TQM8555_defconfig
+++ b/arch/ppc/configs/TQM8555_defconfig
@@ -687,7 +687,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
diff --git a/arch/ppc/configs/TQM8560_defconfig
b/arch/ppc/configs/TQM8560_defconfig
index a814d17..6c19121 100644
--- a/arch/ppc/configs/TQM8560_defconfig
+++ b/arch/ppc/configs/TQM8560_defconfig
@@ -694,7 +694,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_MPC8260 is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
diff --git a/arch/ppc/configs/mpc834x_sys_defconfig
b/arch/ppc/configs/mpc834x_sys_defconfig
index d90c8a7..cd568d2 100644
--- a/arch/ppc/configs/mpc834x_sys_defconfig
+++ b/arch/ppc/configs/mpc834x_sys_defconfig
@@ -562,7 +562,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
diff --git a/arch/ppc/configs/mpc8540_ads_defconfig
b/arch/ppc/configs/mpc8540_ads_defconfig
index bf676eb..5819835 100644
--- a/arch/ppc/configs/mpc8540_ads_defconfig
+++ b/arch/ppc/configs/mpc8540_ads_defconfig
@@ -452,7 +452,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PIIX4 is not set
diff --git a/arch/ppc/configs/mpc8548_cds_defconfig
b/arch/ppc/configs/mpc8548_cds_defconfig
index f36fc5d..e5b5071 100644
--- a/arch/ppc/configs/mpc8548_cds_defconfig
+++ b/arch/ppc/configs/mpc8548_cds_defconfig
@@ -413,7 +413,7 @@ CONFIG_I2C_CHARDEV=y
#
# I2C Hardware Bus support
#
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PCA_ISA is not set
diff --git a/arch/ppc/configs/mpc8555_cds_defconfig
b/arch/ppc/configs/mpc8555_cds_defconfig
index 4f1e320..08dbab0 100644
--- a/arch/ppc/configs/mpc8555_cds_defconfig
+++ b/arch/ppc/configs/mpc8555_cds_defconfig
@@ -518,7 +518,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
diff --git a/arch/ppc/configs/mpc8560_ads_defconfig
b/arch/ppc/configs/mpc8560_ads_defconfig
index f12d48f..0e0080b 100644
--- a/arch/ppc/configs/mpc8560_ads_defconfig
+++ b/arch/ppc/configs/mpc8560_ads_defconfig
@@ -489,7 +489,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index c466c6c..bdde307 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -301,7 +301,7 @@ config I2C_POWERMAC
config I2C_MPC
tristate "MPC107/824x/85xx/52xx/86xx"
- depends on PPC32
+ depends on PPC32 && PPC_MERGE
help
If you say yes to this option, support will be included for the
built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
@@ -311,6 +311,20 @@ config I2C_MPC
This driver can also be built as a module. If so, the module
will be called i2c-mpc.
+config I2C_MPC_PPC
+ tristate "MPC107/824x/85xx/52xx/86xx"
+ depends on PPC32 && !PPC_MERGE
+ help
+ If you say yes to this option, support will be included for the
+ built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
+ MPC85xx/MPC8641 family processors. The driver may also work on 52xx
+ family processors, though interrupts are known not to work.
+
+ This version of the driver is scheduled for deletion with the PPC
architecture.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mpc.
+
config I2C_NFORCE2
tristate "Nvidia nForce2, nForce3 and nForce4"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 81d43c2..b7fe095 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o
obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
+obj-$(CONFIG_I2C_MPC_PPC) += i2c-mpc-ppc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
diff --git a/drivers/i2c/busses/i2c-mpc-ppc.c b/drivers/i2c/busses/i2c-mpc-ppc.c
new file mode 100644
index 0000000..d8de4ac
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mpc-ppc.c
@@ -0,0 +1,418 @@
+/*
+ * (C) Copyright 2003-2004
+ * Humboldt Solutions Ltd, adrian@humboldt.co.uk.
+
+ * This is a combined i2c adapter and algorithm driver for the
+ * MPC107/Tsi107 PowerPC northbridge and processors that include
+ * the same I2C unit (8240, 8245, 85xx).
+ *
+ * Release 0.8
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <linux/fsl_devices.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#define MPC_I2C_ADDR 0x00
+#define MPC_I2C_FDR 0x04
+#define MPC_I2C_CR 0x08
+#define MPC_I2C_SR 0x0c
+#define MPC_I2C_DR 0x10
+#define MPC_I2C_DFSRR 0x14
+#define MPC_I2C_REGION 0x20
+
+#define CCR_MEN 0x80
+#define CCR_MIEN 0x40
+#define CCR_MSTA 0x20
+#define CCR_MTX 0x10
+#define CCR_TXAK 0x08
+#define CCR_RSTA 0x04
+
+#define CSR_MCF 0x80
+#define CSR_MAAS 0x40
+#define CSR_MBB 0x20
+#define CSR_MAL 0x10
+#define CSR_SRW 0x04
+#define CSR_MIF 0x02
+#define CSR_RXAK 0x01
+
+struct mpc_i2c {
+ void __iomem *base;
+ u32 interrupt;
+ wait_queue_head_t queue;
+ struct i2c_adapter adap;
+ int irq;
+ u32 flags;
+};
+
+static __inline__ void writeccr(struct mpc_i2c *i2c, u32 x)
+{
+ writeb(x, i2c->base + MPC_I2C_CR);
+}
+
+static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
+{
+ struct mpc_i2c *i2c = dev_id;
+ if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) {
+ /* Read again to allow register to stabilise */
+ i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
+ writeb(0, i2c->base + MPC_I2C_SR);
+ wake_up_interruptible(&i2c->queue);
+ }
+ return IRQ_HANDLED;
+}
+
+/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
+ * the bus, because it wants to send ACK.
+ * Following sequence of enabling/disabling and sending start/stop generates
+ * the pulse, so it's all OK.
+ */
+static void mpc_i2c_fixup(struct mpc_i2c *i2c)
+{
+ writeccr(i2c, 0);
+ udelay(30);
+ writeccr(i2c, CCR_MEN);
+ udelay(30);
+ writeccr(i2c, CCR_MSTA | CCR_MTX);
+ udelay(30);
+ writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
+ udelay(30);
+ writeccr(i2c, CCR_MEN);
+ udelay(30);
+}
+
+static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
+{
+ unsigned long orig_jiffies = jiffies;
+ u32 x;
+ int result = 0;
+
+ if (i2c->irq == 0)
+ {
+ while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
+ schedule();
+ if (time_after(jiffies, orig_jiffies + timeout)) {
+ pr_debug("I2C: timeout\n");
+ writeccr(i2c, 0);
+ result = -EIO;
+ break;
+ }
+ }
+ x = readb(i2c->base + MPC_I2C_SR);
+ writeb(0, i2c->base + MPC_I2C_SR);
+ } else {
+ /* Interrupt mode */
+ result = wait_event_interruptible_timeout(i2c->queue,
+ (i2c->interrupt & CSR_MIF), timeout * HZ);
+
+ if (unlikely(result < 0)) {
+ pr_debug("I2C: wait interrupted\n");
+ writeccr(i2c, 0);
+ } else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
+ pr_debug("I2C: wait timeout\n");
+ writeccr(i2c, 0);
+ result = -ETIMEDOUT;
+ }
+
+ x = i2c->interrupt;
+ i2c->interrupt = 0;
+ }
+
+ if (result < 0)
+ return result;
+
+ if (!(x & CSR_MCF)) {
+ pr_debug("I2C: unfinished\n");
+ return -EIO;
+ }
+
+ if (x & CSR_MAL) {
+ pr_debug("I2C: MAL\n");
+ return -EIO;
+ }
+
+ if (writing && (x & CSR_RXAK)) {
+ pr_debug("I2C: No RXAK\n");
+ /* generate stop */
+ writeccr(i2c, CCR_MEN);
+ return -EIO;
+ }
+ return 0;
+}
+
+static void mpc_i2c_setclock(struct mpc_i2c *i2c)
+{
+ /* Set clock and filters */
+ if (i2c->flags & FSL_I2C_DEV_SEPARATE_DFSRR) {
+ writeb(0x31, i2c->base + MPC_I2C_FDR);
+ writeb(0x10, i2c->base + MPC_I2C_DFSRR);
+ } else if (i2c->flags & FSL_I2C_DEV_CLOCK_5200)
+ writeb(0x3f, i2c->base + MPC_I2C_FDR);
+ else
+ writel(0x1031, i2c->base + MPC_I2C_FDR);
+}
+
+static void mpc_i2c_start(struct mpc_i2c *i2c)
+{
+ /* Clear arbitration */
+ writeb(0, i2c->base + MPC_I2C_SR);
+ /* Start with MEN */
+ writeccr(i2c, CCR_MEN);
+}
+
+static void mpc_i2c_stop(struct mpc_i2c *i2c)
+{
+ writeccr(i2c, CCR_MEN);
+}
+
+static int mpc_write(struct mpc_i2c *i2c, int target,
+ const u8 * data, int length, int restart)
+{
+ int i;
+ unsigned timeout = i2c->adap.timeout;
+ u32 flags = restart ? CCR_RSTA : 0;
+
+ /* Start with MEN */
+ if (!restart)
+ writeccr(i2c, CCR_MEN);
+ /* Start as master */
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+ /* Write target byte */
+ writeb((target << 1), i2c->base + MPC_I2C_DR);
+
+ if (i2c_wait(i2c, timeout, 1) < 0)
+ return -1;
+
+ for (i = 0; i < length; i++) {
+ /* Write data byte */
+ writeb(data[i], i2c->base + MPC_I2C_DR);
+
+ if (i2c_wait(i2c, timeout, 1) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mpc_read(struct mpc_i2c *i2c, int target,
+ u8 * data, int length, int restart)
+{
+ unsigned timeout = i2c->adap.timeout;
+ int i;
+ u32 flags = restart ? CCR_RSTA : 0;
+
+ /* Start with MEN */
+ if (!restart)
+ writeccr(i2c, CCR_MEN);
+ /* Switch to read - restart */
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+ /* Write target address byte - this time with the read flag set */
+ writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
+
+ if (i2c_wait(i2c, timeout, 1) < 0)
+ return -1;
+
+ if (length) {
+ if (length == 1)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
+ else
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
+ /* Dummy read */
+ readb(i2c->base + MPC_I2C_DR);
+ }
+
+ for (i = 0; i < length; i++) {
+ if (i2c_wait(i2c, timeout, 0) < 0)
+ return -1;
+
+ /* Generate txack on next to last byte */
+ if (i == length - 2)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
+ /* Generate stop on last byte */
+ if (i == length - 1)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);
+ data[i] = readb(i2c->base + MPC_I2C_DR);
+ }
+
+ return length;
+}
+
+static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *pmsg;
+ int i;
+ int ret = 0;
+ unsigned long orig_jiffies = jiffies;
+ struct mpc_i2c *i2c = i2c_get_adapdata(adap);
+
+ mpc_i2c_start(i2c);
+
+ /* Allow bus up to 1s to become not busy */
+ while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
+ if (signal_pending(current)) {
+ pr_debug("I2C: Interrupted\n");
+ writeccr(i2c, 0);
+ return -EINTR;
+ }
+ if (time_after(jiffies, orig_jiffies + HZ)) {
+ pr_debug("I2C: timeout\n");
+ if (readb(i2c->base + MPC_I2C_SR) ==
+ (CSR_MCF | CSR_MBB | CSR_RXAK))
+ mpc_i2c_fixup(i2c);
+ return -EIO;
+ }
+ schedule();
+ }
+
+ for (i = 0; ret >= 0 && i < num; i++) {
+ pmsg = &msgs[i];
+ pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages\n",
+ pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->len, pmsg->addr, i + 1, num);
+ if (pmsg->flags & I2C_M_RD)
+ ret =
+ mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+ else
+ ret =
+ mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+ }
+ mpc_i2c_stop(i2c);
+ return (ret < 0) ? ret : num;
+}
+
+static u32 mpc_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm mpc_algo = {
+ .master_xfer = mpc_xfer,
+ .functionality = mpc_functionality,
+};
+
+static struct i2c_adapter mpc_ops = {
+ .owner = THIS_MODULE,
+ .name = "MPC adapter",
+ .id = I2C_HW_MPC107,
+ .algo = &mpc_algo,
+ .class = I2C_CLASS_HWMON,
+ .timeout = 1,
+ .retries = 1
+};
+
+static int fsl_i2c_probe(struct platform_device *pdev)
+{
+ int result = 0;
+ struct mpc_i2c *i2c;
+ struct fsl_i2c_platform_data *pdata;
+ struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
+
+ if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) {
+ return -ENOMEM;
+ }
+
+ i2c->irq = platform_get_irq(pdev, 0);
+ if (i2c->irq < 0) {
+ result = -ENXIO;
+ goto fail_get_irq;
+ }
+ i2c->flags = pdata->device_flags;
+ init_waitqueue_head(&i2c->queue);
+
+ i2c->base = ioremap((phys_addr_t)r->start, MPC_I2C_REGION);
+
+ if (!i2c->base) {
+ printk(KERN_ERR "i2c-mpc - failed to map controller\n");
+ result = -ENOMEM;
+ goto fail_map;
+ }
+
+ if (i2c->irq != 0)
+ if ((result = request_irq(i2c->irq, mpc_i2c_isr,
+ IRQF_SHARED, "i2c-mpc", i2c)) < 0) {
+ printk(KERN_ERR
+ "i2c-mpc - failed to attach interrupt\n");
+ goto fail_irq;
+ }
+
+ mpc_i2c_setclock(i2c);
+ platform_set_drvdata(pdev, i2c);
+
+ i2c->adap = mpc_ops;
+ i2c->adap.nr = pdev->id;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &pdev->dev;
+ if ((result = i2c_add_numbered_adapter(&i2c->adap)) < 0) {
+ printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
+ goto fail_add;
+ }
+
+ return result;
+
+ fail_add:
+ if (i2c->irq != 0)
+ free_irq(i2c->irq, i2c);
+ fail_irq:
+ iounmap(i2c->base);
+ fail_map:
+ fail_get_irq:
+ kfree(i2c);
+ return result;
+};
+
+static int fsl_i2c_remove(struct platform_device *pdev)
+{
+ struct mpc_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ platform_set_drvdata(pdev, NULL);
+
+ if (i2c->irq != 0)
+ free_irq(i2c->irq, i2c);
+
+ iounmap(i2c->base);
+ kfree(i2c);
+ return 0;
+};
+
+/* Structure for a device driver */
+static struct platform_driver fsl_i2c_driver = {
+ .probe = fsl_i2c_probe,
+ .remove = fsl_i2c_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "fsl-i2c",
+ },
+};
+
+static int __init fsl_i2c_init(void)
+{
+ return platform_driver_register(&fsl_i2c_driver);
+}
+
+static void __exit fsl_i2c_exit(void)
+{
+ platform_driver_unregister(&fsl_i2c_driver);
+}
+
+module_init(fsl_i2c_init);
+module_exit(fsl_i2c_exit);
+
+MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
+MODULE_DESCRIPTION
+ ("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors");
+MODULE_LICENSE("GPL");
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply related
* Re: [PATCH] Addition to the i2c series, copy the ppc mpc-i2c driver before changing it on powerpc
From: Grant Likely @ 2007-12-10 22:44 UTC (permalink / raw)
To: Jon Smirl; +Cc: PowerPC dev list
In-Reply-To: <9e4733910712101420o15b5e908jc7291a0086832467@mail.gmail.com>
On 12/10/07, Jon Smirl <jonsmirl@gmail.com> wrote:
> Copy mpc-i2c to preserve support for ARCH=ppc and allow changes on ARCH=powerpc
>
> Temporarily copy the mpc-i2c driver to continue support for the ppc
> architecture until it is removed in mid-2008. This file should be
> deleted as part of ppc's final removal.
>
> Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
For the record; I'm not fond of this approach. Supporting both bus
bindings in the single driver is simple and results in less code churn
when arch/ppc is removed, and encourages separation between the driver
proper and the bus bindings which is just a good idea for all drivers
in general.
Just my $0.02
Cheers,
g.
> ---
>
> Makefile | 2
> arch/ppc/configs/TQM8540_defconfig | 2
> arch/ppc/configs/TQM8541_defconfig | 2
> arch/ppc/configs/TQM8555_defconfig | 2
> arch/ppc/configs/TQM8560_defconfig | 2
> arch/ppc/configs/mpc834x_sys_defconfig | 2
> arch/ppc/configs/mpc8540_ads_defconfig | 2
> arch/ppc/configs/mpc8548_cds_defconfig | 2
> arch/ppc/configs/mpc8555_cds_defconfig | 2
> arch/ppc/configs/mpc8560_ads_defconfig | 2
> drivers/i2c/busses/Kconfig | 16 +
> drivers/i2c/busses/Makefile | 1
> drivers/i2c/busses/i2c-mpc-ppc.c | 418 ++++++++++++++++++++++++++++++++
> 13 files changed, 444 insertions(+), 11 deletions(-)
> create mode 100644 drivers/i2c/busses/i2c-mpc-ppc.c
>
>
> diff --git a/Makefile b/Makefile
> index 013b43a..3e714e2 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -35,7 +35,7 @@ MAKEFLAGS += -rR --no-print-directory
> # To put more focus on warnings, be less verbose as default
> # Use 'make V=1' to see the full commands
>
> -ARCH=powerpc
> +ARCH=ppc
> CROSS_COMPILE=powerpc-603e-linux-gnu-
>
> ifdef V
> diff --git a/arch/ppc/configs/TQM8540_defconfig
> b/arch/ppc/configs/TQM8540_defconfig
> index f33f0e7..7098ed0 100644
> --- a/arch/ppc/configs/TQM8540_defconfig
> +++ b/arch/ppc/configs/TQM8540_defconfig
> @@ -684,7 +684,7 @@ CONFIG_I2C_CHARDEV=y
> # CONFIG_I2C_I801 is not set
> # CONFIG_I2C_I810 is not set
> # CONFIG_I2C_PIIX4 is not set
> -CONFIG_I2C_MPC=y
> +CONFIG_I2C_MPC_PPC=y
> # CONFIG_I2C_NFORCE2 is not set
> # CONFIG_I2C_PARPORT_LIGHT is not set
> # CONFIG_I2C_PROSAVAGE is not set
> diff --git a/arch/ppc/configs/TQM8541_defconfig
> b/arch/ppc/configs/TQM8541_defconfig
> index e00cd62..2137d01 100644
> --- a/arch/ppc/configs/TQM8541_defconfig
> +++ b/arch/ppc/configs/TQM8541_defconfig
> @@ -687,7 +687,7 @@ CONFIG_I2C_CHARDEV=y
> # CONFIG_I2C_I801 is not set
> # CONFIG_I2C_I810 is not set
> # CONFIG_I2C_PIIX4 is not set
> -CONFIG_I2C_MPC=y
> +CONFIG_I2C_MPC_PPC=y
> # CONFIG_I2C_MPC8260 is not set
> # CONFIG_I2C_NFORCE2 is not set
> # CONFIG_I2C_PARPORT_LIGHT is not set
> diff --git a/arch/ppc/configs/TQM8555_defconfig
> b/arch/ppc/configs/TQM8555_defconfig
> index 43a0d9d..f2317b6 100644
> --- a/arch/ppc/configs/TQM8555_defconfig
> +++ b/arch/ppc/configs/TQM8555_defconfig
> @@ -687,7 +687,7 @@ CONFIG_I2C_CHARDEV=y
> # CONFIG_I2C_I801 is not set
> # CONFIG_I2C_I810 is not set
> # CONFIG_I2C_PIIX4 is not set
> -CONFIG_I2C_MPC=y
> +CONFIG_I2C_MPC_PPC=y
> # CONFIG_I2C_NFORCE2 is not set
> # CONFIG_I2C_PARPORT_LIGHT is not set
> # CONFIG_I2C_PROSAVAGE is not set
> diff --git a/arch/ppc/configs/TQM8560_defconfig
> b/arch/ppc/configs/TQM8560_defconfig
> index a814d17..6c19121 100644
> --- a/arch/ppc/configs/TQM8560_defconfig
> +++ b/arch/ppc/configs/TQM8560_defconfig
> @@ -694,7 +694,7 @@ CONFIG_I2C_CHARDEV=y
> # CONFIG_I2C_I801 is not set
> # CONFIG_I2C_I810 is not set
> # CONFIG_I2C_PIIX4 is not set
> -CONFIG_I2C_MPC=y
> +CONFIG_I2C_MPC_PPC=y
> # CONFIG_I2C_MPC8260 is not set
> # CONFIG_I2C_NFORCE2 is not set
> # CONFIG_I2C_PARPORT_LIGHT is not set
> diff --git a/arch/ppc/configs/mpc834x_sys_defconfig
> b/arch/ppc/configs/mpc834x_sys_defconfig
> index d90c8a7..cd568d2 100644
> --- a/arch/ppc/configs/mpc834x_sys_defconfig
> +++ b/arch/ppc/configs/mpc834x_sys_defconfig
> @@ -562,7 +562,7 @@ CONFIG_I2C_CHARDEV=y
> # CONFIG_I2C_I801 is not set
> # CONFIG_I2C_I810 is not set
> # CONFIG_I2C_PIIX4 is not set
> -CONFIG_I2C_MPC=y
> +CONFIG_I2C_MPC_PPC=y
> # CONFIG_I2C_NFORCE2 is not set
> # CONFIG_I2C_PARPORT_LIGHT is not set
> # CONFIG_I2C_PROSAVAGE is not set
> diff --git a/arch/ppc/configs/mpc8540_ads_defconfig
> b/arch/ppc/configs/mpc8540_ads_defconfig
> index bf676eb..5819835 100644
> --- a/arch/ppc/configs/mpc8540_ads_defconfig
> +++ b/arch/ppc/configs/mpc8540_ads_defconfig
> @@ -452,7 +452,7 @@ CONFIG_I2C_CHARDEV=y
> # CONFIG_I2C_AMD8111 is not set
> # CONFIG_I2C_I801 is not set
> # CONFIG_I2C_I810 is not set
> -CONFIG_I2C_MPC=y
> +CONFIG_I2C_MPC_PPC=y
> # CONFIG_I2C_NFORCE2 is not set
> # CONFIG_I2C_PARPORT_LIGHT is not set
> # CONFIG_I2C_PIIX4 is not set
> diff --git a/arch/ppc/configs/mpc8548_cds_defconfig
> b/arch/ppc/configs/mpc8548_cds_defconfig
> index f36fc5d..e5b5071 100644
> --- a/arch/ppc/configs/mpc8548_cds_defconfig
> +++ b/arch/ppc/configs/mpc8548_cds_defconfig
> @@ -413,7 +413,7 @@ CONFIG_I2C_CHARDEV=y
> #
> # I2C Hardware Bus support
> #
> -CONFIG_I2C_MPC=y
> +CONFIG_I2C_MPC_PPC=y
> # CONFIG_I2C_PARPORT_LIGHT is not set
> # CONFIG_I2C_PCA_ISA is not set
>
> diff --git a/arch/ppc/configs/mpc8555_cds_defconfig
> b/arch/ppc/configs/mpc8555_cds_defconfig
> index 4f1e320..08dbab0 100644
> --- a/arch/ppc/configs/mpc8555_cds_defconfig
> +++ b/arch/ppc/configs/mpc8555_cds_defconfig
> @@ -518,7 +518,7 @@ CONFIG_I2C_CHARDEV=y
> # CONFIG_I2C_I801 is not set
> # CONFIG_I2C_I810 is not set
> # CONFIG_I2C_PIIX4 is not set
> -CONFIG_I2C_MPC=y
> +CONFIG_I2C_MPC_PPC=y
> # CONFIG_I2C_NFORCE2 is not set
> # CONFIG_I2C_PARPORT_LIGHT is not set
> # CONFIG_I2C_PROSAVAGE is not set
> diff --git a/arch/ppc/configs/mpc8560_ads_defconfig
> b/arch/ppc/configs/mpc8560_ads_defconfig
> index f12d48f..0e0080b 100644
> --- a/arch/ppc/configs/mpc8560_ads_defconfig
> +++ b/arch/ppc/configs/mpc8560_ads_defconfig
> @@ -489,7 +489,7 @@ CONFIG_I2C_CHARDEV=y
> # CONFIG_I2C_I801 is not set
> # CONFIG_I2C_I810 is not set
> # CONFIG_I2C_PIIX4 is not set
> -CONFIG_I2C_MPC=y
> +CONFIG_I2C_MPC_PPC=y
> # CONFIG_I2C_NFORCE2 is not set
> # CONFIG_I2C_PARPORT_LIGHT is not set
> # CONFIG_I2C_PROSAVAGE is not set
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index c466c6c..bdde307 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -301,7 +301,7 @@ config I2C_POWERMAC
>
> config I2C_MPC
> tristate "MPC107/824x/85xx/52xx/86xx"
> - depends on PPC32
> + depends on PPC32 && PPC_MERGE
> help
> If you say yes to this option, support will be included for the
> built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
> @@ -311,6 +311,20 @@ config I2C_MPC
> This driver can also be built as a module. If so, the module
> will be called i2c-mpc.
>
> +config I2C_MPC_PPC
> + tristate "MPC107/824x/85xx/52xx/86xx"
> + depends on PPC32 && !PPC_MERGE
> + help
> + If you say yes to this option, support will be included for the
> + built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
> + MPC85xx/MPC8641 family processors. The driver may also work on 52xx
> + family processors, though interrupts are known not to work.
> +
> + This version of the driver is scheduled for deletion with the PPC
> architecture.
> +
> + This driver can also be built as a module. If so, the module
> + will be called i2c-mpc.
> +
> config I2C_NFORCE2
> tristate "Nvidia nForce2, nForce3 and nForce4"
> depends on PCI
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 81d43c2..b7fe095 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -23,6 +23,7 @@ obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
> obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o
> obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
> obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
> +obj-$(CONFIG_I2C_MPC_PPC) += i2c-mpc-ppc.o
> obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
> obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
> obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
> diff --git a/drivers/i2c/busses/i2c-mpc-ppc.c b/drivers/i2c/busses/i2c-mpc-ppc.c
> new file mode 100644
> index 0000000..d8de4ac
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-mpc-ppc.c
> @@ -0,0 +1,418 @@
> +/*
> + * (C) Copyright 2003-2004
> + * Humboldt Solutions Ltd, adrian@humboldt.co.uk.
> +
> + * This is a combined i2c adapter and algorithm driver for the
> + * MPC107/Tsi107 PowerPC northbridge and processors that include
> + * the same I2C unit (8240, 8245, 85xx).
> + *
> + * Release 0.8
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/sched.h>
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +
> +#include <asm/io.h>
> +#include <linux/fsl_devices.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +
> +#define MPC_I2C_ADDR 0x00
> +#define MPC_I2C_FDR 0x04
> +#define MPC_I2C_CR 0x08
> +#define MPC_I2C_SR 0x0c
> +#define MPC_I2C_DR 0x10
> +#define MPC_I2C_DFSRR 0x14
> +#define MPC_I2C_REGION 0x20
> +
> +#define CCR_MEN 0x80
> +#define CCR_MIEN 0x40
> +#define CCR_MSTA 0x20
> +#define CCR_MTX 0x10
> +#define CCR_TXAK 0x08
> +#define CCR_RSTA 0x04
> +
> +#define CSR_MCF 0x80
> +#define CSR_MAAS 0x40
> +#define CSR_MBB 0x20
> +#define CSR_MAL 0x10
> +#define CSR_SRW 0x04
> +#define CSR_MIF 0x02
> +#define CSR_RXAK 0x01
> +
> +struct mpc_i2c {
> + void __iomem *base;
> + u32 interrupt;
> + wait_queue_head_t queue;
> + struct i2c_adapter adap;
> + int irq;
> + u32 flags;
> +};
> +
> +static __inline__ void writeccr(struct mpc_i2c *i2c, u32 x)
> +{
> + writeb(x, i2c->base + MPC_I2C_CR);
> +}
> +
> +static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
> +{
> + struct mpc_i2c *i2c = dev_id;
> + if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) {
> + /* Read again to allow register to stabilise */
> + i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
> + writeb(0, i2c->base + MPC_I2C_SR);
> + wake_up_interruptible(&i2c->queue);
> + }
> + return IRQ_HANDLED;
> +}
> +
> +/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
> + * the bus, because it wants to send ACK.
> + * Following sequence of enabling/disabling and sending start/stop generates
> + * the pulse, so it's all OK.
> + */
> +static void mpc_i2c_fixup(struct mpc_i2c *i2c)
> +{
> + writeccr(i2c, 0);
> + udelay(30);
> + writeccr(i2c, CCR_MEN);
> + udelay(30);
> + writeccr(i2c, CCR_MSTA | CCR_MTX);
> + udelay(30);
> + writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
> + udelay(30);
> + writeccr(i2c, CCR_MEN);
> + udelay(30);
> +}
> +
> +static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
> +{
> + unsigned long orig_jiffies = jiffies;
> + u32 x;
> + int result = 0;
> +
> + if (i2c->irq == 0)
> + {
> + while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
> + schedule();
> + if (time_after(jiffies, orig_jiffies + timeout)) {
> + pr_debug("I2C: timeout\n");
> + writeccr(i2c, 0);
> + result = -EIO;
> + break;
> + }
> + }
> + x = readb(i2c->base + MPC_I2C_SR);
> + writeb(0, i2c->base + MPC_I2C_SR);
> + } else {
> + /* Interrupt mode */
> + result = wait_event_interruptible_timeout(i2c->queue,
> + (i2c->interrupt & CSR_MIF), timeout * HZ);
> +
> + if (unlikely(result < 0)) {
> + pr_debug("I2C: wait interrupted\n");
> + writeccr(i2c, 0);
> + } else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
> + pr_debug("I2C: wait timeout\n");
> + writeccr(i2c, 0);
> + result = -ETIMEDOUT;
> + }
> +
> + x = i2c->interrupt;
> + i2c->interrupt = 0;
> + }
> +
> + if (result < 0)
> + return result;
> +
> + if (!(x & CSR_MCF)) {
> + pr_debug("I2C: unfinished\n");
> + return -EIO;
> + }
> +
> + if (x & CSR_MAL) {
> + pr_debug("I2C: MAL\n");
> + return -EIO;
> + }
> +
> + if (writing && (x & CSR_RXAK)) {
> + pr_debug("I2C: No RXAK\n");
> + /* generate stop */
> + writeccr(i2c, CCR_MEN);
> + return -EIO;
> + }
> + return 0;
> +}
> +
> +static void mpc_i2c_setclock(struct mpc_i2c *i2c)
> +{
> + /* Set clock and filters */
> + if (i2c->flags & FSL_I2C_DEV_SEPARATE_DFSRR) {
> + writeb(0x31, i2c->base + MPC_I2C_FDR);
> + writeb(0x10, i2c->base + MPC_I2C_DFSRR);
> + } else if (i2c->flags & FSL_I2C_DEV_CLOCK_5200)
> + writeb(0x3f, i2c->base + MPC_I2C_FDR);
> + else
> + writel(0x1031, i2c->base + MPC_I2C_FDR);
> +}
> +
> +static void mpc_i2c_start(struct mpc_i2c *i2c)
> +{
> + /* Clear arbitration */
> + writeb(0, i2c->base + MPC_I2C_SR);
> + /* Start with MEN */
> + writeccr(i2c, CCR_MEN);
> +}
> +
> +static void mpc_i2c_stop(struct mpc_i2c *i2c)
> +{
> + writeccr(i2c, CCR_MEN);
> +}
> +
> +static int mpc_write(struct mpc_i2c *i2c, int target,
> + const u8 * data, int length, int restart)
> +{
> + int i;
> + unsigned timeout = i2c->adap.timeout;
> + u32 flags = restart ? CCR_RSTA : 0;
> +
> + /* Start with MEN */
> + if (!restart)
> + writeccr(i2c, CCR_MEN);
> + /* Start as master */
> + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
> + /* Write target byte */
> + writeb((target << 1), i2c->base + MPC_I2C_DR);
> +
> + if (i2c_wait(i2c, timeout, 1) < 0)
> + return -1;
> +
> + for (i = 0; i < length; i++) {
> + /* Write data byte */
> + writeb(data[i], i2c->base + MPC_I2C_DR);
> +
> + if (i2c_wait(i2c, timeout, 1) < 0)
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int mpc_read(struct mpc_i2c *i2c, int target,
> + u8 * data, int length, int restart)
> +{
> + unsigned timeout = i2c->adap.timeout;
> + int i;
> + u32 flags = restart ? CCR_RSTA : 0;
> +
> + /* Start with MEN */
> + if (!restart)
> + writeccr(i2c, CCR_MEN);
> + /* Switch to read - restart */
> + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
> + /* Write target address byte - this time with the read flag set */
> + writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
> +
> + if (i2c_wait(i2c, timeout, 1) < 0)
> + return -1;
> +
> + if (length) {
> + if (length == 1)
> + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
> + else
> + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
> + /* Dummy read */
> + readb(i2c->base + MPC_I2C_DR);
> + }
> +
> + for (i = 0; i < length; i++) {
> + if (i2c_wait(i2c, timeout, 0) < 0)
> + return -1;
> +
> + /* Generate txack on next to last byte */
> + if (i == length - 2)
> + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
> + /* Generate stop on last byte */
> + if (i == length - 1)
> + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);
> + data[i] = readb(i2c->base + MPC_I2C_DR);
> + }
> +
> + return length;
> +}
> +
> +static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
> +{
> + struct i2c_msg *pmsg;
> + int i;
> + int ret = 0;
> + unsigned long orig_jiffies = jiffies;
> + struct mpc_i2c *i2c = i2c_get_adapdata(adap);
> +
> + mpc_i2c_start(i2c);
> +
> + /* Allow bus up to 1s to become not busy */
> + while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
> + if (signal_pending(current)) {
> + pr_debug("I2C: Interrupted\n");
> + writeccr(i2c, 0);
> + return -EINTR;
> + }
> + if (time_after(jiffies, orig_jiffies + HZ)) {
> + pr_debug("I2C: timeout\n");
> + if (readb(i2c->base + MPC_I2C_SR) ==
> + (CSR_MCF | CSR_MBB | CSR_RXAK))
> + mpc_i2c_fixup(i2c);
> + return -EIO;
> + }
> + schedule();
> + }
> +
> + for (i = 0; ret >= 0 && i < num; i++) {
> + pmsg = &msgs[i];
> + pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages\n",
> + pmsg->flags & I2C_M_RD ? "read" : "write",
> + pmsg->len, pmsg->addr, i + 1, num);
> + if (pmsg->flags & I2C_M_RD)
> + ret =
> + mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
> + else
> + ret =
> + mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
> + }
> + mpc_i2c_stop(i2c);
> + return (ret < 0) ? ret : num;
> +}
> +
> +static u32 mpc_functionality(struct i2c_adapter *adap)
> +{
> + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
> +}
> +
> +static const struct i2c_algorithm mpc_algo = {
> + .master_xfer = mpc_xfer,
> + .functionality = mpc_functionality,
> +};
> +
> +static struct i2c_adapter mpc_ops = {
> + .owner = THIS_MODULE,
> + .name = "MPC adapter",
> + .id = I2C_HW_MPC107,
> + .algo = &mpc_algo,
> + .class = I2C_CLASS_HWMON,
> + .timeout = 1,
> + .retries = 1
> +};
> +
> +static int fsl_i2c_probe(struct platform_device *pdev)
> +{
> + int result = 0;
> + struct mpc_i2c *i2c;
> + struct fsl_i2c_platform_data *pdata;
> + struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> + pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
> +
> + if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) {
> + return -ENOMEM;
> + }
> +
> + i2c->irq = platform_get_irq(pdev, 0);
> + if (i2c->irq < 0) {
> + result = -ENXIO;
> + goto fail_get_irq;
> + }
> + i2c->flags = pdata->device_flags;
> + init_waitqueue_head(&i2c->queue);
> +
> + i2c->base = ioremap((phys_addr_t)r->start, MPC_I2C_REGION);
> +
> + if (!i2c->base) {
> + printk(KERN_ERR "i2c-mpc - failed to map controller\n");
> + result = -ENOMEM;
> + goto fail_map;
> + }
> +
> + if (i2c->irq != 0)
> + if ((result = request_irq(i2c->irq, mpc_i2c_isr,
> + IRQF_SHARED, "i2c-mpc", i2c)) < 0) {
> + printk(KERN_ERR
> + "i2c-mpc - failed to attach interrupt\n");
> + goto fail_irq;
> + }
> +
> + mpc_i2c_setclock(i2c);
> + platform_set_drvdata(pdev, i2c);
> +
> + i2c->adap = mpc_ops;
> + i2c->adap.nr = pdev->id;
> + i2c_set_adapdata(&i2c->adap, i2c);
> + i2c->adap.dev.parent = &pdev->dev;
> + if ((result = i2c_add_numbered_adapter(&i2c->adap)) < 0) {
> + printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
> + goto fail_add;
> + }
> +
> + return result;
> +
> + fail_add:
> + if (i2c->irq != 0)
> + free_irq(i2c->irq, i2c);
> + fail_irq:
> + iounmap(i2c->base);
> + fail_map:
> + fail_get_irq:
> + kfree(i2c);
> + return result;
> +};
> +
> +static int fsl_i2c_remove(struct platform_device *pdev)
> +{
> + struct mpc_i2c *i2c = platform_get_drvdata(pdev);
> +
> + i2c_del_adapter(&i2c->adap);
> + platform_set_drvdata(pdev, NULL);
> +
> + if (i2c->irq != 0)
> + free_irq(i2c->irq, i2c);
> +
> + iounmap(i2c->base);
> + kfree(i2c);
> + return 0;
> +};
> +
> +/* Structure for a device driver */
> +static struct platform_driver fsl_i2c_driver = {
> + .probe = fsl_i2c_probe,
> + .remove = fsl_i2c_remove,
> + .driver = {
> + .owner = THIS_MODULE,
> + .name = "fsl-i2c",
> + },
> +};
> +
> +static int __init fsl_i2c_init(void)
> +{
> + return platform_driver_register(&fsl_i2c_driver);
> +}
> +
> +static void __exit fsl_i2c_exit(void)
> +{
> + platform_driver_unregister(&fsl_i2c_driver);
> +}
> +
> +module_init(fsl_i2c_init);
> +module_exit(fsl_i2c_exit);
> +
> +MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
> +MODULE_DESCRIPTION
> + ("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors");
> +MODULE_LICENSE("GPL");
>
> --
> Jon Smirl
> jonsmirl@gmail.com
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* Re: [PATCH] Addition to the i2c series, copy the ppc mpc-i2c driver before changing it on powerpc
From: Tony Breeds @ 2007-12-10 22:42 UTC (permalink / raw)
To: Jon Smirl; +Cc: PowerPC dev list
In-Reply-To: <9e4733910712101420o15b5e908jc7291a0086832467@mail.gmail.com>
On Mon, Dec 10, 2007 at 05:20:08PM -0500, Jon Smirl wrote:
> Copy mpc-i2c to preserve support for ARCH=ppc and allow changes on ARCH=powerpc
>
> Temporarily copy the mpc-i2c driver to continue support for the ppc
> architecture until it is removed in mid-2008. This file should be
> deleted as part of ppc's final removal.
<snip?
>
> diff --git a/Makefile b/Makefile
> index 013b43a..3e714e2 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -35,7 +35,7 @@ MAKEFLAGS += -rR --no-print-directory
> # To put more focus on warnings, be less verbose as default
> # Use 'make V=1' to see the full commands
>
> -ARCH=powerpc
> +ARCH=ppc
> CROSS_COMPILE=powerpc-603e-linux-gnu-
Umm should this hunk be here? My Makefile doen't have these 3 line at
all?
Yours Tony
linux.conf.au http://linux.conf.au/ || http://lca2008.linux.org.au/
Jan 28 - Feb 02 2008 The Australian Linux Technical Conference!
^ permalink raw reply
* [PATCH] Addition to the i2c series, copy the ppc mpc-i2c driver before changing it on powerpc
From: Jon Smirl @ 2007-12-10 22:20 UTC (permalink / raw)
To: PowerPC dev list
Copy mpc-i2c to preserve support for ARCH=ppc and allow changes on ARCH=powerpc
Temporarily copy the mpc-i2c driver to continue support for the ppc
architecture until it is removed in mid-2008. This file should be
deleted as part of ppc's final removal.
Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---
Makefile | 2
arch/ppc/configs/TQM8540_defconfig | 2
arch/ppc/configs/TQM8541_defconfig | 2
arch/ppc/configs/TQM8555_defconfig | 2
arch/ppc/configs/TQM8560_defconfig | 2
arch/ppc/configs/mpc834x_sys_defconfig | 2
arch/ppc/configs/mpc8540_ads_defconfig | 2
arch/ppc/configs/mpc8548_cds_defconfig | 2
arch/ppc/configs/mpc8555_cds_defconfig | 2
arch/ppc/configs/mpc8560_ads_defconfig | 2
drivers/i2c/busses/Kconfig | 16 +
drivers/i2c/busses/Makefile | 1
drivers/i2c/busses/i2c-mpc-ppc.c | 418 ++++++++++++++++++++++++++++++++
13 files changed, 444 insertions(+), 11 deletions(-)
create mode 100644 drivers/i2c/busses/i2c-mpc-ppc.c
diff --git a/Makefile b/Makefile
index 013b43a..3e714e2 100644
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,7 @@ MAKEFLAGS += -rR --no-print-directory
# To put more focus on warnings, be less verbose as default
# Use 'make V=1' to see the full commands
-ARCH=powerpc
+ARCH=ppc
CROSS_COMPILE=powerpc-603e-linux-gnu-
ifdef V
diff --git a/arch/ppc/configs/TQM8540_defconfig
b/arch/ppc/configs/TQM8540_defconfig
index f33f0e7..7098ed0 100644
--- a/arch/ppc/configs/TQM8540_defconfig
+++ b/arch/ppc/configs/TQM8540_defconfig
@@ -684,7 +684,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
diff --git a/arch/ppc/configs/TQM8541_defconfig
b/arch/ppc/configs/TQM8541_defconfig
index e00cd62..2137d01 100644
--- a/arch/ppc/configs/TQM8541_defconfig
+++ b/arch/ppc/configs/TQM8541_defconfig
@@ -687,7 +687,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_MPC8260 is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
diff --git a/arch/ppc/configs/TQM8555_defconfig
b/arch/ppc/configs/TQM8555_defconfig
index 43a0d9d..f2317b6 100644
--- a/arch/ppc/configs/TQM8555_defconfig
+++ b/arch/ppc/configs/TQM8555_defconfig
@@ -687,7 +687,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
diff --git a/arch/ppc/configs/TQM8560_defconfig
b/arch/ppc/configs/TQM8560_defconfig
index a814d17..6c19121 100644
--- a/arch/ppc/configs/TQM8560_defconfig
+++ b/arch/ppc/configs/TQM8560_defconfig
@@ -694,7 +694,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_MPC8260 is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
diff --git a/arch/ppc/configs/mpc834x_sys_defconfig
b/arch/ppc/configs/mpc834x_sys_defconfig
index d90c8a7..cd568d2 100644
--- a/arch/ppc/configs/mpc834x_sys_defconfig
+++ b/arch/ppc/configs/mpc834x_sys_defconfig
@@ -562,7 +562,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
diff --git a/arch/ppc/configs/mpc8540_ads_defconfig
b/arch/ppc/configs/mpc8540_ads_defconfig
index bf676eb..5819835 100644
--- a/arch/ppc/configs/mpc8540_ads_defconfig
+++ b/arch/ppc/configs/mpc8540_ads_defconfig
@@ -452,7 +452,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PIIX4 is not set
diff --git a/arch/ppc/configs/mpc8548_cds_defconfig
b/arch/ppc/configs/mpc8548_cds_defconfig
index f36fc5d..e5b5071 100644
--- a/arch/ppc/configs/mpc8548_cds_defconfig
+++ b/arch/ppc/configs/mpc8548_cds_defconfig
@@ -413,7 +413,7 @@ CONFIG_I2C_CHARDEV=y
#
# I2C Hardware Bus support
#
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PCA_ISA is not set
diff --git a/arch/ppc/configs/mpc8555_cds_defconfig
b/arch/ppc/configs/mpc8555_cds_defconfig
index 4f1e320..08dbab0 100644
--- a/arch/ppc/configs/mpc8555_cds_defconfig
+++ b/arch/ppc/configs/mpc8555_cds_defconfig
@@ -518,7 +518,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
diff --git a/arch/ppc/configs/mpc8560_ads_defconfig
b/arch/ppc/configs/mpc8560_ads_defconfig
index f12d48f..0e0080b 100644
--- a/arch/ppc/configs/mpc8560_ads_defconfig
+++ b/arch/ppc/configs/mpc8560_ads_defconfig
@@ -489,7 +489,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_PPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index c466c6c..bdde307 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -301,7 +301,7 @@ config I2C_POWERMAC
config I2C_MPC
tristate "MPC107/824x/85xx/52xx/86xx"
- depends on PPC32
+ depends on PPC32 && PPC_MERGE
help
If you say yes to this option, support will be included for the
built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
@@ -311,6 +311,20 @@ config I2C_MPC
This driver can also be built as a module. If so, the module
will be called i2c-mpc.
+config I2C_MPC_PPC
+ tristate "MPC107/824x/85xx/52xx/86xx"
+ depends on PPC32 && !PPC_MERGE
+ help
+ If you say yes to this option, support will be included for the
+ built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
+ MPC85xx/MPC8641 family processors. The driver may also work on 52xx
+ family processors, though interrupts are known not to work.
+
+ This version of the driver is scheduled for deletion with the PPC
architecture.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mpc.
+
config I2C_NFORCE2
tristate "Nvidia nForce2, nForce3 and nForce4"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 81d43c2..b7fe095 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o
obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
+obj-$(CONFIG_I2C_MPC_PPC) += i2c-mpc-ppc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
diff --git a/drivers/i2c/busses/i2c-mpc-ppc.c b/drivers/i2c/busses/i2c-mpc-ppc.c
new file mode 100644
index 0000000..d8de4ac
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mpc-ppc.c
@@ -0,0 +1,418 @@
+/*
+ * (C) Copyright 2003-2004
+ * Humboldt Solutions Ltd, adrian@humboldt.co.uk.
+
+ * This is a combined i2c adapter and algorithm driver for the
+ * MPC107/Tsi107 PowerPC northbridge and processors that include
+ * the same I2C unit (8240, 8245, 85xx).
+ *
+ * Release 0.8
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <linux/fsl_devices.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#define MPC_I2C_ADDR 0x00
+#define MPC_I2C_FDR 0x04
+#define MPC_I2C_CR 0x08
+#define MPC_I2C_SR 0x0c
+#define MPC_I2C_DR 0x10
+#define MPC_I2C_DFSRR 0x14
+#define MPC_I2C_REGION 0x20
+
+#define CCR_MEN 0x80
+#define CCR_MIEN 0x40
+#define CCR_MSTA 0x20
+#define CCR_MTX 0x10
+#define CCR_TXAK 0x08
+#define CCR_RSTA 0x04
+
+#define CSR_MCF 0x80
+#define CSR_MAAS 0x40
+#define CSR_MBB 0x20
+#define CSR_MAL 0x10
+#define CSR_SRW 0x04
+#define CSR_MIF 0x02
+#define CSR_RXAK 0x01
+
+struct mpc_i2c {
+ void __iomem *base;
+ u32 interrupt;
+ wait_queue_head_t queue;
+ struct i2c_adapter adap;
+ int irq;
+ u32 flags;
+};
+
+static __inline__ void writeccr(struct mpc_i2c *i2c, u32 x)
+{
+ writeb(x, i2c->base + MPC_I2C_CR);
+}
+
+static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
+{
+ struct mpc_i2c *i2c = dev_id;
+ if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) {
+ /* Read again to allow register to stabilise */
+ i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
+ writeb(0, i2c->base + MPC_I2C_SR);
+ wake_up_interruptible(&i2c->queue);
+ }
+ return IRQ_HANDLED;
+}
+
+/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
+ * the bus, because it wants to send ACK.
+ * Following sequence of enabling/disabling and sending start/stop generates
+ * the pulse, so it's all OK.
+ */
+static void mpc_i2c_fixup(struct mpc_i2c *i2c)
+{
+ writeccr(i2c, 0);
+ udelay(30);
+ writeccr(i2c, CCR_MEN);
+ udelay(30);
+ writeccr(i2c, CCR_MSTA | CCR_MTX);
+ udelay(30);
+ writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
+ udelay(30);
+ writeccr(i2c, CCR_MEN);
+ udelay(30);
+}
+
+static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
+{
+ unsigned long orig_jiffies = jiffies;
+ u32 x;
+ int result = 0;
+
+ if (i2c->irq == 0)
+ {
+ while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
+ schedule();
+ if (time_after(jiffies, orig_jiffies + timeout)) {
+ pr_debug("I2C: timeout\n");
+ writeccr(i2c, 0);
+ result = -EIO;
+ break;
+ }
+ }
+ x = readb(i2c->base + MPC_I2C_SR);
+ writeb(0, i2c->base + MPC_I2C_SR);
+ } else {
+ /* Interrupt mode */
+ result = wait_event_interruptible_timeout(i2c->queue,
+ (i2c->interrupt & CSR_MIF), timeout * HZ);
+
+ if (unlikely(result < 0)) {
+ pr_debug("I2C: wait interrupted\n");
+ writeccr(i2c, 0);
+ } else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
+ pr_debug("I2C: wait timeout\n");
+ writeccr(i2c, 0);
+ result = -ETIMEDOUT;
+ }
+
+ x = i2c->interrupt;
+ i2c->interrupt = 0;
+ }
+
+ if (result < 0)
+ return result;
+
+ if (!(x & CSR_MCF)) {
+ pr_debug("I2C: unfinished\n");
+ return -EIO;
+ }
+
+ if (x & CSR_MAL) {
+ pr_debug("I2C: MAL\n");
+ return -EIO;
+ }
+
+ if (writing && (x & CSR_RXAK)) {
+ pr_debug("I2C: No RXAK\n");
+ /* generate stop */
+ writeccr(i2c, CCR_MEN);
+ return -EIO;
+ }
+ return 0;
+}
+
+static void mpc_i2c_setclock(struct mpc_i2c *i2c)
+{
+ /* Set clock and filters */
+ if (i2c->flags & FSL_I2C_DEV_SEPARATE_DFSRR) {
+ writeb(0x31, i2c->base + MPC_I2C_FDR);
+ writeb(0x10, i2c->base + MPC_I2C_DFSRR);
+ } else if (i2c->flags & FSL_I2C_DEV_CLOCK_5200)
+ writeb(0x3f, i2c->base + MPC_I2C_FDR);
+ else
+ writel(0x1031, i2c->base + MPC_I2C_FDR);
+}
+
+static void mpc_i2c_start(struct mpc_i2c *i2c)
+{
+ /* Clear arbitration */
+ writeb(0, i2c->base + MPC_I2C_SR);
+ /* Start with MEN */
+ writeccr(i2c, CCR_MEN);
+}
+
+static void mpc_i2c_stop(struct mpc_i2c *i2c)
+{
+ writeccr(i2c, CCR_MEN);
+}
+
+static int mpc_write(struct mpc_i2c *i2c, int target,
+ const u8 * data, int length, int restart)
+{
+ int i;
+ unsigned timeout = i2c->adap.timeout;
+ u32 flags = restart ? CCR_RSTA : 0;
+
+ /* Start with MEN */
+ if (!restart)
+ writeccr(i2c, CCR_MEN);
+ /* Start as master */
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+ /* Write target byte */
+ writeb((target << 1), i2c->base + MPC_I2C_DR);
+
+ if (i2c_wait(i2c, timeout, 1) < 0)
+ return -1;
+
+ for (i = 0; i < length; i++) {
+ /* Write data byte */
+ writeb(data[i], i2c->base + MPC_I2C_DR);
+
+ if (i2c_wait(i2c, timeout, 1) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mpc_read(struct mpc_i2c *i2c, int target,
+ u8 * data, int length, int restart)
+{
+ unsigned timeout = i2c->adap.timeout;
+ int i;
+ u32 flags = restart ? CCR_RSTA : 0;
+
+ /* Start with MEN */
+ if (!restart)
+ writeccr(i2c, CCR_MEN);
+ /* Switch to read - restart */
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+ /* Write target address byte - this time with the read flag set */
+ writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
+
+ if (i2c_wait(i2c, timeout, 1) < 0)
+ return -1;
+
+ if (length) {
+ if (length == 1)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
+ else
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
+ /* Dummy read */
+ readb(i2c->base + MPC_I2C_DR);
+ }
+
+ for (i = 0; i < length; i++) {
+ if (i2c_wait(i2c, timeout, 0) < 0)
+ return -1;
+
+ /* Generate txack on next to last byte */
+ if (i == length - 2)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
+ /* Generate stop on last byte */
+ if (i == length - 1)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);
+ data[i] = readb(i2c->base + MPC_I2C_DR);
+ }
+
+ return length;
+}
+
+static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *pmsg;
+ int i;
+ int ret = 0;
+ unsigned long orig_jiffies = jiffies;
+ struct mpc_i2c *i2c = i2c_get_adapdata(adap);
+
+ mpc_i2c_start(i2c);
+
+ /* Allow bus up to 1s to become not busy */
+ while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
+ if (signal_pending(current)) {
+ pr_debug("I2C: Interrupted\n");
+ writeccr(i2c, 0);
+ return -EINTR;
+ }
+ if (time_after(jiffies, orig_jiffies + HZ)) {
+ pr_debug("I2C: timeout\n");
+ if (readb(i2c->base + MPC_I2C_SR) ==
+ (CSR_MCF | CSR_MBB | CSR_RXAK))
+ mpc_i2c_fixup(i2c);
+ return -EIO;
+ }
+ schedule();
+ }
+
+ for (i = 0; ret >= 0 && i < num; i++) {
+ pmsg = &msgs[i];
+ pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages\n",
+ pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->len, pmsg->addr, i + 1, num);
+ if (pmsg->flags & I2C_M_RD)
+ ret =
+ mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+ else
+ ret =
+ mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+ }
+ mpc_i2c_stop(i2c);
+ return (ret < 0) ? ret : num;
+}
+
+static u32 mpc_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm mpc_algo = {
+ .master_xfer = mpc_xfer,
+ .functionality = mpc_functionality,
+};
+
+static struct i2c_adapter mpc_ops = {
+ .owner = THIS_MODULE,
+ .name = "MPC adapter",
+ .id = I2C_HW_MPC107,
+ .algo = &mpc_algo,
+ .class = I2C_CLASS_HWMON,
+ .timeout = 1,
+ .retries = 1
+};
+
+static int fsl_i2c_probe(struct platform_device *pdev)
+{
+ int result = 0;
+ struct mpc_i2c *i2c;
+ struct fsl_i2c_platform_data *pdata;
+ struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
+
+ if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) {
+ return -ENOMEM;
+ }
+
+ i2c->irq = platform_get_irq(pdev, 0);
+ if (i2c->irq < 0) {
+ result = -ENXIO;
+ goto fail_get_irq;
+ }
+ i2c->flags = pdata->device_flags;
+ init_waitqueue_head(&i2c->queue);
+
+ i2c->base = ioremap((phys_addr_t)r->start, MPC_I2C_REGION);
+
+ if (!i2c->base) {
+ printk(KERN_ERR "i2c-mpc - failed to map controller\n");
+ result = -ENOMEM;
+ goto fail_map;
+ }
+
+ if (i2c->irq != 0)
+ if ((result = request_irq(i2c->irq, mpc_i2c_isr,
+ IRQF_SHARED, "i2c-mpc", i2c)) < 0) {
+ printk(KERN_ERR
+ "i2c-mpc - failed to attach interrupt\n");
+ goto fail_irq;
+ }
+
+ mpc_i2c_setclock(i2c);
+ platform_set_drvdata(pdev, i2c);
+
+ i2c->adap = mpc_ops;
+ i2c->adap.nr = pdev->id;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &pdev->dev;
+ if ((result = i2c_add_numbered_adapter(&i2c->adap)) < 0) {
+ printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
+ goto fail_add;
+ }
+
+ return result;
+
+ fail_add:
+ if (i2c->irq != 0)
+ free_irq(i2c->irq, i2c);
+ fail_irq:
+ iounmap(i2c->base);
+ fail_map:
+ fail_get_irq:
+ kfree(i2c);
+ return result;
+};
+
+static int fsl_i2c_remove(struct platform_device *pdev)
+{
+ struct mpc_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ platform_set_drvdata(pdev, NULL);
+
+ if (i2c->irq != 0)
+ free_irq(i2c->irq, i2c);
+
+ iounmap(i2c->base);
+ kfree(i2c);
+ return 0;
+};
+
+/* Structure for a device driver */
+static struct platform_driver fsl_i2c_driver = {
+ .probe = fsl_i2c_probe,
+ .remove = fsl_i2c_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "fsl-i2c",
+ },
+};
+
+static int __init fsl_i2c_init(void)
+{
+ return platform_driver_register(&fsl_i2c_driver);
+}
+
+static void __exit fsl_i2c_exit(void)
+{
+ platform_driver_unregister(&fsl_i2c_driver);
+}
+
+module_init(fsl_i2c_init);
+module_exit(fsl_i2c_exit);
+
+MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
+MODULE_DESCRIPTION
+ ("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors");
+MODULE_LICENSE("GPL");
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply related
* Re: ppc vs powerpc
From: Tony Breeds @ 2007-12-10 22:01 UTC (permalink / raw)
To: Jon Smirl; +Cc: PowerPC dev list
In-Reply-To: <9e4733910712101354i31020c2w72d74bf33ba3e90b@mail.gmail.com>
On Mon, Dec 10, 2007 at 04:54:32PM -0500, Jon Smirl wrote:
> How can I tell a build for ARCH=ppc vs ARCH=powerpc in Kconfig?
IIRC ARCH=powerpc will have CONFIG_PPC_MERGE set, arch=ppc will not.
Yours Tony
linux.conf.au http://linux.conf.au/ || http://lca2008.linux.org.au/
Jan 28 - Feb 02 2008 The Australian Linux Technical Conference!
^ permalink raw reply
* Re: ppc vs powerpc
From: Jon Smirl @ 2007-12-10 21:54 UTC (permalink / raw)
To: Grant Likely; +Cc: PowerPC dev list
In-Reply-To: <fa686aa40712101259h22be4b89ke4f36564a7c1866c@mail.gmail.com>
On 12/10/07, Grant Likely <grant.likely@secretlab.ca> wrote:
> On 12/10/07, Jon Smirl <jonsmirl@gmail.com> wrote:
> > Is the plan for ppc to be completely merged with powerpc and then be
> > eliminated? If so, how close is this to completion?
> >
> > What should we do with ppc users of mpc-i2c? If the plan is to
> > eliminate ppc I would say to just copy the existing driver and then
> > delete the old version when the rest of ppc gets deleted.
>
> arch/ppc is scheduled to be removed middle of 2008. Don't break
> arch/ppc users before then. Ideally there should be overlap between
> the addition of support in arch/powerpc and the removal of support
> from arch/ppc.
How can I tell a build for ARCH=ppc vs ARCH=powerpc in Kconfig?
> Personally, I structure the driver to support both platform bus and
> of_platform bus. It's not hard to do and it keeps things
> understandable. Take a look at drivers/block/xsysace for an example.
>
> Cheers,
> g.
>
>
> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
> grant.likely@secretlab.ca
> (403) 399-0195
>
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: [PATCH] IB/ehca: Serialize HCA-related hCalls on POWER5
From: Roland Dreier @ 2007-12-10 21:47 UTC (permalink / raw)
To: Joachim Fenkes
Cc: Arnd Bergmann, LKML, OF-EWG, linuxppc-dev, Christoph Raisch,
Marcus Eder, OF-General, Stefan Roscher
In-Reply-To: <200712101841.30010.fenkes@de.ibm.com>
> > map_phys_fmr
>
> In fact, we do use hCalls there. Our hardware doesn't actually support FMRs,
> so we translate a "map FMR" into a "reallocate PMR", which doesn't work
> without hCalls. What's more, the hCalls involved (e.g. H_FREE_RESOURCE)
> might well return H_LONG_BUSY, so the whole operation might sleep; no way
> around it.
It's a big problem. If you cannot implement FMRs in such a way that
you can handling having map_phys_fmr being called in a context that
can't sleep, then I think the only option is to remove your FMR
support. It's an optional device feature, so this should be OK
(although the iSER driver currently seems to depend on a device
supporting FMRs, which is probably going to be a problem with iWARP
support in the future anyway).
The fact that consumers can map FMRs from interrupt context, while
holding locks, etc, is pretty fundamental to the use of FMRs so I
don't see any way around the requirement that map_phys_fmr never
sleep.
- R.
^ permalink raw reply
* Re: [PATCH 1/5] PowerPC 74xx: Katana Qp device tree
From: Dale Farnsworth @ 2007-12-10 21:18 UTC (permalink / raw)
To: Linuxppc-dev; +Cc: David Gibson
In-Reply-To: <20071203015018.GC26919@localhost.localdomain>
David Gibson wrote:
> On Thu, Nov 29, 2007 at 06:28:36PM +0300, Andrei Dolnikov wrote:
> > Device tree source file for the Emerson Katana Qp board
[snip]
> > + mv64x60@f8100000 { /* Marvell Discovery */
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > + model = "mv64460"; /* Default */
> > + compatible = "marvell,mv64x60";
[snip]
> > + mdio {
>
> There must be some way of actuall accessing the mdio bus, so this node
> ought to have a 'reg' property and unit address.
There is no way for the cpu to directly access the mdio bus. The
mdio bus is internally accessed by the ethernet MAC. That being the
case, maybe it makes more sense to move the mdio node inside of the
multiethernet node, as follows, but I don't see how we can give it
a reg property or a unit address.
multiethernet@2000 {
reg = <0x2000 0x2000>;
ethernet@0 {
device_type = "network";
compatible = "marvell,mv64360-eth";
reg = <0>;
interrupts = <32>;
interrupt-parent = <&PIC>;
phy = <&PHY0>;
local-mac-address = [ 00 00 00 00 00 00 ];
};
ethernet@1 {
device_type = "network";
compatible = "marvell,mv64360-eth";
reg = <1>;
interrupts = <33>;
interrupt-parent = <&PIC>;
phy = <&PHY1>;
local-mac-address = [ 00 00 00 00 00 00 ];
};
mdio {
#address-cells = <1>;
#size-cells = <0>;
device_type = "mdio";
compatible = "marvell,mv64360-mdio";
PHY0: ethernet-phy@1 {
device_type = "ethernet-phy";
compatible = "broadcom,bcm5421";
interrupts = <76>; /* GPP 12 */
interrupt-parent = <&PIC>;
reg = <1>;
};
PHY1: ethernet-phy@3 {
device_type = "ethernet-phy";
compatible = "broadcom,bcm5421";
interrupts = <76>; /* GPP 12 */
interrupt-parent = <&PIC>;
reg = <3>;
};
};
};
Look OK?
-Dale
^ permalink raw reply
* Re: ppc vs powerpc
From: Jon Smirl @ 2007-12-10 21:04 UTC (permalink / raw)
To: Grant Likely; +Cc: PowerPC dev list
In-Reply-To: <fa686aa40712101259h22be4b89ke4f36564a7c1866c@mail.gmail.com>
On 12/10/07, Grant Likely <grant.likely@secretlab.ca> wrote:
> On 12/10/07, Jon Smirl <jonsmirl@gmail.com> wrote:
> > Is the plan for ppc to be completely merged with powerpc and then be
> > eliminated? If so, how close is this to completion?
> >
> > What should we do with ppc users of mpc-i2c? If the plan is to
> > eliminate ppc I would say to just copy the existing driver and then
> > delete the old version when the rest of ppc gets deleted.
>
> arch/ppc is scheduled to be removed middle of 2008. Don't break
> arch/ppc users before then. Ideally there should be overlap between
> the addition of support in arch/powerpc and the removal of support
> from arch/ppc.
>
> Personally, I structure the driver to support both platform bus and
> of_platform bus. It's not hard to do and it keeps things
> understandable. Take a look at drivers/block/xsysace for an example.
I can look at it but I'm not enthused about writing new code to
support something that is scheduled to be deleted in six months. It
would be much simpler to just copy the old driver. I'm spending way
too much time on what I thought was a fairly simple change.
>
> Cheers,
> g.
>
>
> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
> grant.likely@secretlab.ca
> (403) 399-0195
>
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: ppc vs powerpc
From: Grant Likely @ 2007-12-10 20:59 UTC (permalink / raw)
To: Jon Smirl; +Cc: PowerPC dev list
In-Reply-To: <9e4733910712101254r1bf8925o20ee6eacd3af6a18@mail.gmail.com>
On 12/10/07, Jon Smirl <jonsmirl@gmail.com> wrote:
> Is the plan for ppc to be completely merged with powerpc and then be
> eliminated? If so, how close is this to completion?
>
> What should we do with ppc users of mpc-i2c? If the plan is to
> eliminate ppc I would say to just copy the existing driver and then
> delete the old version when the rest of ppc gets deleted.
arch/ppc is scheduled to be removed middle of 2008. Don't break
arch/ppc users before then. Ideally there should be overlap between
the addition of support in arch/powerpc and the removal of support
from arch/ppc.
Personally, I structure the driver to support both platform bus and
of_platform bus. It's not hard to do and it keeps things
understandable. Take a look at drivers/block/xsysace for an example.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* ppc vs powerpc
From: Jon Smirl @ 2007-12-10 20:54 UTC (permalink / raw)
To: PowerPC dev list
Is the plan for ppc to be completely merged with powerpc and then be
eliminated? If so, how close is this to completion?
What should we do with ppc users of mpc-i2c? If the plan is to
eliminate ppc I would say to just copy the existing driver and then
delete the old version when the rest of ppc gets deleted.
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* [PATCH RFC 7/7] [POWERPC] MPC8360E-RDK: add support for NAND on UPM
From: Anton Vorontsov @ 2007-12-10 20:49 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <20071210204705.GA31263@localhost.localdomain>
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
arch/powerpc/boot/dts/mpc836x_rdk.dts | 24 +++++++++++++++++++++++-
arch/powerpc/platforms/83xx/Kconfig | 2 ++
arch/powerpc/platforms/83xx/mpc836x_rdk.c | 1 +
3 files changed, 26 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc836x_rdk.dts b/arch/powerpc/boot/dts/mpc836x_rdk.dts
index a1b2da6..f57ba53 100644
--- a/arch/powerpc/boot/dts/mpc836x_rdk.dts
+++ b/arch/powerpc/boot/dts/mpc836x_rdk.dts
@@ -115,7 +115,7 @@
device_type = "ipic";
};
- par_io@1400 {
+ qe_pio: par_io@1400 {
reg = <0x1400 0x100>;
num-ports = <7>;
};
@@ -229,4 +229,26 @@
interrupt-parent = <&ipic>;
};
};
+
+ localbus@e0005000 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc8360erdk-localbus",
+ "fsl,mpc8360e-localbus",
+ "fsl,pq2pro-localbus";
+ reg = <0xe0005000 0xd8>;
+ ranges = <1 0 0x60000000 1>;
+
+ nand-flash@1,0 {
+ compatible = "STMicro,NAND512W3A2BN6E", "fsl,upm-nand";
+ reg = <1 0 1>;
+ upm = "A";
+ upm-addr-offset = <16>;
+ upm-cmd-offset = <8>;
+ gpios = <4 18>;
+ gpio-parent = <&qe_pio>;
+ wait-pattern;
+ wait-write;
+ };
+ };
};
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index 98f6358..2fc60c1 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -54,6 +54,7 @@ config MPC836x_RDK
bool "Freescale/Logic MPC836x RDK"
select DEFAULT_UIMAGE
select QUICC_ENGINE
+ select FSL_UPM_LOCKLESS
help
This option enables support for the MPC836x RDK Processor Board,
also known as ZOOM PowerQUICC Kit.
@@ -82,4 +83,5 @@ config PPC_MPC836x
bool
select PPC_UDBG_16550
select PPC_INDIRECT_PCI
+ select FSL_UPM
default y if MPC836x_MDS || MPC836x_RDK
diff --git a/arch/powerpc/platforms/83xx/mpc836x_rdk.c b/arch/powerpc/platforms/83xx/mpc836x_rdk.c
index be9e2fd..4288e16 100644
--- a/arch/powerpc/platforms/83xx/mpc836x_rdk.c
+++ b/arch/powerpc/platforms/83xx/mpc836x_rdk.c
@@ -27,6 +27,7 @@ static struct of_device_id mpc836x_rdk_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
{ .type = "qe", },
+ { .compatible = "fsl,pq2pro-localbus", },
{},
};
--
1.5.2.2
^ permalink raw reply related
* [PATCH RFC 6/7] [POWERPC][NAND] FSL UPM NAND driver
From: Anton Vorontsov @ 2007-12-10 20:49 UTC (permalink / raw)
To: linuxppc-dev; +Cc: tglx, dbrownell, dwmw2
In-Reply-To: <20071210204705.GA31263@localhost.localdomain>
It's using FSL UPM infrastructure. So far only 8 bit accessors
are implemented.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/mtd/nand/Kconfig | 7 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/fsl_upm.c | 310 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 318 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/nand/fsl_upm.c
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 246d451..910b4d5 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -306,4 +306,11 @@ config MTD_ALAUDA
These two (and possibly other) Alauda-based cardreaders for
SmartMedia and xD allow raw flash access.
+config MTD_NAND_FSL_UPM
+ tristate "MTD driver for NAND on Freescale UPM"
+ depends on MTD_NAND && FSL_UPM
+ help
+ Enables support for NAND Flash wired to Freescale processors'
+ localbus with pre-programmed User-Programmable Machine.
+
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 3ad6c01..d553ea3 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -29,5 +29,6 @@ obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_ALAUDA) += alauda.o
+obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
new file mode 100644
index 0000000..a2bddb0
--- /dev/null
+++ b/drivers/mtd/nand/fsl_upm.c
@@ -0,0 +1,310 @@
+/*
+ * Freescale UPM NAND driver.
+ *
+ * Copyright (c) 2007 MontaVista Software, Inc.
+ * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/mtd.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/fsl_upm.h>
+
+struct upm_data {
+ struct of_device *ofdev;
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ int last_ctrl;
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *parts;
+#endif
+
+ struct fsl_upm upm;
+
+ int width;
+ int upm_addr_offset;
+ int upm_cmd_offset;
+ void __iomem *io_base;
+ int rnb_gpio;
+ const u32 *wait_pattern;
+ const u32 *wait_write;
+ int chip_delay;
+};
+
+#define to_upm_data(mtd) container_of(mtd, struct upm_data, mtd)
+
+static int upm_chip_ready(struct mtd_info *mtd)
+{
+ struct upm_data *ud = to_upm_data(mtd);
+
+ if (gpio_get_value(ud->rnb_gpio))
+ return 1;
+
+ dev_vdbg(&ud->ofdev->dev, "busy\n");
+ return 0;
+}
+
+static void upm_wait_rnb(struct upm_data *ud)
+{
+ int cnt = 1000000;
+
+ if (ud->rnb_gpio >= 0) {
+ while (--cnt && !upm_chip_ready(&ud->mtd))
+ cpu_relax();
+ }
+
+ if (!cnt)
+ dev_err(&ud->ofdev->dev, "tired waiting for RNB\n");
+}
+
+static void upm_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct upm_data *ud = to_upm_data(mtd);
+
+ if (!(ctrl & ud->last_ctrl)) {
+ fsl_upm_end_pattern(&ud->upm);
+
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ ud->last_ctrl = ctrl & (NAND_ALE | NAND_CLE);
+ }
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ if (ctrl & NAND_ALE)
+ fsl_upm_start_pattern(&ud->upm, ud->upm_addr_offset);
+ else if (ctrl & NAND_CLE)
+ fsl_upm_start_pattern(&ud->upm, ud->upm_cmd_offset);
+ }
+
+ fsl_upm_run_pattern(&ud->upm, ud->io_base, ud->width, cmd);
+
+ if (ud->wait_pattern)
+ upm_wait_rnb(ud);
+}
+
+static uint8_t upm_read_byte(struct mtd_info *mtd)
+{
+ struct upm_data *ud = to_upm_data(mtd);
+
+ return in_8(ud->chip.IO_ADDR_R);
+}
+
+static void upm_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct upm_data *ud = to_upm_data(mtd);
+ int i;
+
+ for (i = 0; i < len; i++)
+ buf[i] = in_8(ud->chip.IO_ADDR_R);
+}
+
+static void upm_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ struct upm_data *ud = to_upm_data(mtd);
+ int i;
+
+ for (i = 0; i < len; i++) {
+ out_8(ud->chip.IO_ADDR_W, buf[i]);
+ if (ud->wait_write)
+ upm_wait_rnb(ud);
+ }
+}
+
+static int __devinit upm_chip_init(struct upm_data *ud)
+{
+ int ret;
+#ifdef CONFIG_MTD_PARTITIONS
+ static const char *part_types[] = { "cmdlinepart", NULL, };
+#endif
+
+ ud->chip.IO_ADDR_R = ud->io_base;
+ ud->chip.IO_ADDR_W = ud->io_base;
+ ud->chip.cmd_ctrl = upm_cmd_ctrl;
+ ud->chip.chip_delay = ud->chip_delay;
+ ud->chip.read_byte = upm_read_byte;
+ ud->chip.read_buf = upm_read_buf;
+ ud->chip.write_buf = upm_write_buf;
+ ud->chip.ecc.mode = NAND_ECC_SOFT;
+
+ if (ud->rnb_gpio != (unsigned int)-1)
+ ud->chip.dev_ready = upm_chip_ready;
+
+ ud->mtd.priv = &ud->chip;
+ ud->mtd.owner = THIS_MODULE;
+
+ ret = nand_scan(&ud->mtd, 1);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ ret = parse_mtd_partitions(&ud->mtd, part_types, &ud->parts, 0);
+ if (ret > 0)
+ return add_mtd_partitions(&ud->mtd, ud->parts, ret);
+#endif
+ return add_mtd_device(&ud->mtd);
+}
+
+static int __devinit upm_chip_probe(struct of_device *ofdev,
+ const struct of_device_id *ofid)
+{
+ struct upm_data *ud;
+ struct resource io_res;
+ const u32 *prop;
+ int ret;
+
+ ud = kzalloc(sizeof(*ud), GFP_KERNEL);
+ if (!ud)
+ return -ENOMEM;
+
+ ret = of_address_to_resource(ofdev->node, 0, &io_res);
+ if (ret) {
+ dev_err(&ofdev->dev, "can't get IO base\n");
+ goto err;
+ }
+
+ ud->width = io_res.end - io_res.start + 1;
+ if (ud->width != 1) {
+ dev_err(&ofdev->dev, "> 8 bit accessors not implemented\n");
+ ret = -ENOSYS;
+ goto err;
+ }
+ ud->width *= 8;
+
+ prop = of_get_property(ofdev->node, "upm", NULL);
+ if (!prop) {
+ dev_err(&ofdev->dev, "can't get UPM to use\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = fsl_upm_get_for(ofdev->node, (const char *)prop, &ud->upm);
+ if (ret) {
+ dev_err(&ofdev->dev, "can't get FSL UPM\n");
+ goto err;
+ }
+
+ prop = of_get_property(ofdev->node, "upm-addr-offset", NULL);
+ if (!prop) {
+ dev_err(&ofdev->dev, "can't get UPM address offset\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ ud->upm_addr_offset = *prop;
+
+ prop = of_get_property(ofdev->node, "upm-cmd-offset", NULL);
+ if (!prop) {
+ dev_err(&ofdev->dev, "can't get UPM command offset\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ ud->upm_cmd_offset = *prop;
+
+ ud->rnb_gpio = of_get_gpio(ofdev->node, 0);
+ if (ud->rnb_gpio >= 0) {
+ ret = gpio_request(ud->rnb_gpio, ofdev->dev.bus_id);
+ if (ret) {
+ dev_err(&ofdev->dev, "can't request RNB gpio\n");
+ goto err;
+ }
+ } else if (ud->rnb_gpio == -EINVAL) {
+ dev_err(&ofdev->dev, "specified RNB gpio is invalid\n");
+ goto err;
+ }
+
+ ud->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start,
+ io_res.end - io_res.start + 1);
+ if (!ud->io_base) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ud->ofdev = ofdev;
+ ud->last_ctrl = NAND_CLE;
+ ud->wait_pattern = of_get_property(ofdev->node, "wait-pattern", NULL);
+ ud->wait_write = of_get_property(ofdev->node, "wait-write", NULL);
+
+ prop = of_get_property(ofdev->node, "chip-delay", NULL);
+ if (prop)
+ ud->chip_delay = *prop;
+ else
+ ud->chip_delay = 50;
+
+ ret = upm_chip_init(ud);
+ if (ret)
+ goto err;
+
+ dev_set_drvdata(&ofdev->dev, ud);
+
+ return 0;
+
+err:
+ if (fsl_upm_got(&ud->upm))
+ fsl_upm_free(&ud->upm);
+
+ if (ud->rnb_gpio >= 0)
+ gpio_free(ud->rnb_gpio);
+
+ kfree(ud);
+
+ return ret;
+}
+
+static int __devexit upm_chip_remove(struct of_device *ofdev)
+{
+ struct upm_data *ud = dev_get_drvdata(&ofdev->dev);
+
+ nand_release(&ud->mtd);
+
+ fsl_upm_free(&ud->upm);
+
+ if (ud->rnb_gpio != (unsigned int)-1)
+ gpio_free(ud->rnb_gpio);
+
+ kfree(ud);
+
+ return 0;
+}
+
+static struct of_device_id of_upm_nand_match[] = {
+ { .compatible = "fsl,upm-nand" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_upm_nand_match);
+
+static struct of_platform_driver of_upm_chip_driver = {
+ .name = "fsl_upm_nand",
+ .match_table = of_upm_nand_match,
+ .probe = upm_chip_probe,
+ .remove = __devexit_p(upm_chip_remove),
+};
+
+static int __init upm_nand_init(void)
+{
+ return of_register_platform_driver(&of_upm_chip_driver);
+}
+
+static void __exit upm_nand_exit(void)
+{
+ of_unregister_platform_driver(&of_upm_chip_driver);
+}
+
+module_init(upm_nand_init);
+module_exit(upm_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_DESCRIPTION("Driver for NAND chips working through Freescale "
+ "LocalBus User-Programmable Machine");
--
1.5.2.2
^ permalink raw reply related
* [PATCH RFC 5/7] [POWERPC] FSL UPM: routines to manage FSL UPMs
From: Anton Vorontsov @ 2007-12-10 20:49 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <20071210204705.GA31263@localhost.localdomain>
Here are few routines needed to manage FSL UPMs properly. FSL UPM
infrastructure also supports lockless variant, to use when we're
pretty sure that only one UPM is used on the board.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
arch/powerpc/Kconfig | 7 +++
arch/powerpc/sysdev/Makefile | 1 +
arch/powerpc/sysdev/fsl_upm.c | 74 +++++++++++++++++++++++++++++
include/asm-powerpc/fsl_upm.h | 102 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 184 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/sysdev/fsl_upm.c
create mode 100644 include/asm-powerpc/fsl_upm.h
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 596982f..1d47a35 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -464,6 +464,13 @@ config FSL_PCI
bool
select PPC_INDIRECT_PCI
+config FSL_UPM
+ bool
+
+config FSL_UPM_LOCKLESS
+ depends on FSL_UPM
+ bool
+
# Yes MCA RS/6000s exist but Linux-PPC does not currently support any
config MCA
bool
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 99a77d7..98dbfdd 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_U3_DART) += dart_iommu.o
obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o
obj-$(CONFIG_FSL_PCI) += fsl_pci.o
+obj-$(CONFIG_FSL_UPM) += fsl_upm.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
diff --git a/arch/powerpc/sysdev/fsl_upm.c b/arch/powerpc/sysdev/fsl_upm.c
new file mode 100644
index 0000000..98d079d
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_upm.c
@@ -0,0 +1,74 @@
+/*
+ * Freescale UPM routines.
+ *
+ * Copyright (c) 2007 MontaVista Software, Inc.
+ * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <asm/fsl_upm.h>
+
+int fsl_upm_get_for(struct device_node *node, const char *name,
+ struct fsl_upm *upm)
+{
+ int ret;
+ struct device_node *lbus;
+ struct resource lbc_res;
+ ptrdiff_t mxmr_offs;
+
+ lbus = of_get_parent(node);
+ if (!lbus) {
+ pr_err("FSL UPM: can't get parent local bus node\n");
+ return -ENOENT;
+ }
+
+ ret = of_address_to_resource(lbus, 0, &lbc_res);
+ if (ret) {
+ pr_err("FSL UPM: can't get parent local bus base\n");
+ return -ENOMEM;
+ }
+
+ switch (name[0]) {
+ case 'A':
+ mxmr_offs = LBC_MAMR;
+ break;
+ case 'B':
+ mxmr_offs = LBC_MBMR;
+ break;
+ case 'C':
+ mxmr_offs = LBC_MCMR;
+ break;
+ default:
+ pr_err("FSL UPM: unknown UPM requested\n");
+ return -EINVAL;
+ break;
+ }
+
+ upm->lbc_base = ioremap_nocache(lbc_res.start,
+ lbc_res.end - lbc_res.start + 1);
+ if (!upm->lbc_base)
+ return -ENOMEM;
+
+ upm->mxmr = upm->lbc_base + mxmr_offs;
+ upm->mar = upm->lbc_base + LBC_MAR;
+
+ return 0;
+}
+
+#ifndef CONFIG_FSL_UPM_LOCKLESS
+spinlock_t upm_lock;
+unsigned long upm_lock_flags;
+
+static int __init fsl_upm_init(void)
+{
+ spin_lock_init(&upm_lock);
+ return 0;
+}
+arch_initcall(fsl_upm_init);
+#endif
diff --git a/include/asm-powerpc/fsl_upm.h b/include/asm-powerpc/fsl_upm.h
new file mode 100644
index 0000000..19f5f9d
--- /dev/null
+++ b/include/asm-powerpc/fsl_upm.h
@@ -0,0 +1,102 @@
+/*
+ * Freescale UPM routines.
+ *
+ * Copyright (c) 2007 MontaVista Software, Inc.
+ * Copyright (c) 2007 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 __ASM_POWERPC_FSL_UPM
+#define __ASM_POWERPC_FSL_UPM
+
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+#define LBC_MAR 0x68
+#define LBC_MAMR 0x70
+#define LBC_MBMR 0x74
+#define LBC_MCMR 0x78
+
+#define LBC_MXMR_RUNP 0x30000000
+
+struct fsl_upm {
+ void __iomem *lbc_base;
+ void __iomem *mxmr;
+ void __iomem *mar;
+};
+
+#ifndef CONFIG_FSL_UPM_LOCKLESS
+extern spinlock_t upm_lock;
+extern unsigned long upm_lock_flags;
+
+static inline void upm_do_lock(void)
+{
+ spin_lock_irqsave(&upm_lock, upm_lock_flags);
+}
+
+static inline void upm_do_unlock(void)
+{
+ spin_unlock_irqrestore(&upm_lock, upm_lock_flags);
+}
+#else /* CONFIG_FSL_UPM_LOCKLESS */
+static inline void upm_do_lock(void) {}
+static inline void upm_do_unlock(void) {}
+#endif /* CONFIG_FSL_UPM_LOCKLESS */
+
+extern int fsl_upm_get_for(struct device_node *node, const char *name,
+ struct fsl_upm *upm);
+
+static inline void fsl_upm_free(struct fsl_upm *upm)
+{
+ iounmap(upm->lbc_base);
+}
+
+static inline int fsl_upm_got(struct fsl_upm *upm)
+{
+ return !!upm->lbc_base;
+}
+
+static inline void fsl_upm_start_pattern(struct fsl_upm *upm, u32 pat_offset)
+{
+ upm_do_lock();
+ out_be32(upm->mxmr, LBC_MXMR_RUNP | pat_offset);
+}
+
+static inline void fsl_upm_end_pattern(struct fsl_upm *upm)
+{
+ out_be32(upm->mxmr, 0x0);
+
+ while (in_be32(upm->mxmr) != 0x0)
+ cpu_relax();
+
+ upm_do_unlock();
+}
+
+static inline int fsl_upm_run_pattern(struct fsl_upm *upm,
+ void __iomem *io_base,
+ int width, u32 cmd)
+{
+ out_be32(upm->mar, cmd << (32 - width));
+ switch (width) {
+ case 8:
+ out_8(io_base, 0x0);
+ break;
+ case 16:
+ out_be16(io_base, 0x0);
+ break;
+ case 32:
+ out_be32(io_base, 0x0);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+#endif /* __ASM_POWERPC_FSL_UPM */
--
1.5.2.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox