All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 8/12] drivers: PMC MSP71xx TWI driver]
@ 2007-03-21  0:42 Marc St-Jean
  2007-03-21 15:34 ` Jean Delvare
  0 siblings, 1 reply; 6+ messages in thread
From: Marc St-Jean @ 2007-03-21  0:42 UTC (permalink / raw)
  To: Jean Delvare; +Cc: linux-mips, i2c



Jean Delvare wrote:
> Marc,
> 
>  > ----- Forwarded message from Marc St-Jean <stjeanma@pmc-sierra.com> 
> -----
>  >
>  > From: Marc St-Jean <stjeanma@pmc-sierra.com>
>  > Date: Fri, 16 Mar 2007 15:39:51 -0600
>  > To:   akpm@linux-foundation.org
>  > Cc:   linux-mips@linux-mips.org
>  > Subject: [PATCH 8/12] drivers: PMC MSP71xx TWI driver
>  >
>  > [PATCH 8/12] drivers: PMC MSP71xx TWI driver
>  >
>  > Patch to add TWI driver for the PMC-Sierra MSP71xx devices.
>  >
>  > Reposting patches as a single set at the request of akpm.
>  > Only 9 of 12 will be posted at this time, 3 more to follow
>  > when cleanups are complete.
>  >
>  > CCing linux-mips.org since minor changes have occured
>  > during cleanup of driver patches for other lists.
>  >
>  > Thanks,
>  > Marc
>  >
>  > Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
>  > ---
>  > Re-posting patch with recommended changes:
>  > -No changes.
>  >
>  >  drivers/i2c/algos/Kconfig           |    9
>  >  drivers/i2c/algos/Makefile          |    1
>  >  drivers/i2c/algos/i2c-algo-pmctwi.c |  197 ++++++++++++++++
>  >  drivers/i2c/busses/Kconfig          |    7
>  >  drivers/i2c/busses/Makefile         |    1
>  >  drivers/i2c/busses/i2c-pmcmsp.c     |  419 
> ++++++++++++++++++++++++++++++++++++
>  >  include/linux/i2c-algo-pmctwi.h     |  135 +++++++++++
>  >  7 files changed, 768 insertions(+), 1 deletion(-)
> 
> Why are you making a separate algorithm driver? This should really only
> be done when the algorithm is very generic. This is the exception, not
> the rule. These days I tend to move algorithm code back into the only
> bus driver that uses them (i2c-algo-sibyte done recently, i2c-algo-sgi
> is next on my list.)

I believe it was done to separate the algorithm for the TWI sub-system,
which is used in several devices, from the device family code. If this
is no longer acceptable I will merge the algo code with the adapter.


>  > diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
>  > index af02034..794f7bb 100644
>  > --- a/drivers/i2c/algos/Kconfig
>  > +++ b/drivers/i2c/algos/Kconfig
>  > @@ -49,5 +49,12 @@ config I2C_ALGO_SGI
>  >         Supports the SGI interfaces like the ones found on SGI Indy VINO
>  >         or SGI O2 MACE.
>  > 
>  > -endmenu
>  > +config I2C_ALGO_PMCTWI
>  > +     tristate "I2C PMC TWI interfaces"
>  > +     depends on I2C && PMC_MSP
> 
> As a matter of fact, each time an algorithm depends on specific
> hardware, you can be reasonably certain that it should NOT be made a
> generic algorithm driver.

OK.

>  > +     help
>  > +       Implements the PMC TWI SoC algorithm for various 
> implementations.
>  > 
>  > +       Be sure to select the proper bus for your platform below.
>  > +
>  > +endmenu
> 
> -- 
> Jean Delvare
> 

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

* Re: [PATCH 8/12] drivers: PMC MSP71xx TWI driver]
  2007-03-21  0:42 [PATCH 8/12] drivers: PMC MSP71xx TWI driver] Marc St-Jean
@ 2007-03-21 15:34 ` Jean Delvare
  0 siblings, 0 replies; 6+ messages in thread
From: Jean Delvare @ 2007-03-21 15:34 UTC (permalink / raw)
  To: Marc St-Jean; +Cc: linux-mips, i2c

Hi Marc,

On Tue, 20 Mar 2007 16:42:39 -0800, Marc St-Jean wrote:
> Jean Delvare wrote:
> > Why are you making a separate algorithm driver? This should really only
> > be done when the algorithm is very generic. This is the exception, not
> > the rule. These days I tend to move algorithm code back into the only
> > bus driver that uses them (i2c-algo-sibyte done recently, i2c-algo-sgi
> > is next on my list.)
> 
> I believe it was done to separate the algorithm for the TWI sub-system,
> which is used in several devices, from the device family code. If this
> is no longer acceptable I will merge the algo code with the adapter.

You should be able to have a single i2c bus driver handling all the
different devices, by using the platform data to provide the
device-specific configuration. The i2c-algorithm concept is quite old,
now that we have a clean new device driver model it should no longer be
necessary in most cases.

-- 
Jean Delvare

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

* Re: [PATCH 8/12] drivers: PMC MSP71xx TWI driver]
  2007-03-19 10:41   ` Ladislav Michl
@ 2007-03-19 13:36     ` Jean Delvare
  0 siblings, 0 replies; 6+ messages in thread
From: Jean Delvare @ 2007-03-19 13:36 UTC (permalink / raw)
  To: Ladislav Michl; +Cc: Ralf Baechle, Marc St-Jean, akpm, linux-mips, i2c

Hi Ladislav,

On Mon, 19 Mar 2007 11:41:55 +0100, Ladislav Michl wrote:
> On Sat, Mar 17, 2007 at 08:52:44AM +0100, Jean Delvare wrote:
> [snip]
> > Why are you making a separate algorithm driver? This should really only
> > be done when the algorithm is very generic. This is the exception, not
> > the rule. These days I tend to move algorithm code back into the only
> > bus driver that uses them (i2c-algo-sibyte done recently, i2c-algo-sgi
> > is next on my list.)
> 
> Please remove i2c-algo-sgi from your list. This algorithm is used by
> the VINO asic (drivers/media/video/vino.c) present in SGI Indy machines as
> well as by the MACE asic (no driver exist yet) present in SGI O2 machines.

OK, thanks for the info. It's hard to tell for sure without seeing the
missing code for the MACE, but I still think that the split between the
different source files is not correct. I think that you want to have
one platform-based i2c bus driver (not just algorithm), which works
with both the VINO and the MACE, one dedicated driver for the Indy
which glues the I2C bus, the SAA7191 and the Indycam together, and
another dedicated driver for the O2 which glues the I2C bus and whatever
chips are on it, together.

BTW, the vino driver is on my (now very short) list of drivers which
create i2c busses without a valid parent. It doesn't seem to fit in the
Linux 2.6 device driver model at all. If you have supported hardware,
could you please fix this? You probably simply need to create a
platform driver and device for the VINO chip, and use that as the
parent of the i2c bus.

> You may consider applying this patch (also removes trailing whitespace).
> 
> Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
> 
> --- linux-omap-2.6.git/drivers/i2c/algos/i2c-algo-sgi.c.orig	2007-03-19 11:26:30.000000000 +0100
> +++ linux-omap-2.6.git/drivers/i2c/algos/i2c-algo-sgi.c	2007-03-19 11:39:00.000000000 +0100
> @@ -1,6 +1,7 @@
>  /*
> - * i2c-algo-sgi.c: i2c driver algorithms for SGI adapters.
> - * 
> + * i2c-algo-sgi.c: i2c driver algorithm used by the VINO (SGI Indy) and
> + * MACE (SGI O2) chips.
> + *
>   * This file is subject to the terms and conditions of the GNU General Public
>   * License version 2 as published by the Free Software Foundation.
>   *
> @@ -162,8 +163,8 @@
>  	.functionality	= sgi_func,
>  };
>  
> -/* 
> - * registering functions to load algorithms at runtime 
> +/*
> + * registering functions to load algorithms at runtime
>   */
>  int i2c_sgi_add_bus(struct i2c_adapter *adap)
>  {

OK, I'll apply this, it cannot hurt.

Thanks,
-- 
Jean Delvare

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

* Re: [PATCH 8/12] drivers: PMC MSP71xx TWI driver]
  2007-03-17  7:52 ` Jean Delvare
@ 2007-03-19 10:41   ` Ladislav Michl
  2007-03-19 13:36     ` Jean Delvare
  0 siblings, 1 reply; 6+ messages in thread
From: Ladislav Michl @ 2007-03-19 10:41 UTC (permalink / raw)
  To: Jean Delvare; +Cc: Ralf Baechle, Marc St-Jean, akpm, linux-mips, i2c

On Sat, Mar 17, 2007 at 08:52:44AM +0100, Jean Delvare wrote:
[snip]
> Why are you making a separate algorithm driver? This should really only
> be done when the algorithm is very generic. This is the exception, not
> the rule. These days I tend to move algorithm code back into the only
> bus driver that uses them (i2c-algo-sibyte done recently, i2c-algo-sgi
> is next on my list.)

Please remove i2c-algo-sgi from your list. This algorithm is used by
the VINO asic (drivers/media/video/vino.c) present in SGI Indy machines as
well as by the MACE asic (no driver exist yet) present in SGI O2 machines.
You may consider applying this patch (also removes trailing whitespace).

Signed-off-by: Ladislav Michl <ladis@linux-mips.org>

--- linux-omap-2.6.git/drivers/i2c/algos/i2c-algo-sgi.c.orig	2007-03-19 11:26:30.000000000 +0100
+++ linux-omap-2.6.git/drivers/i2c/algos/i2c-algo-sgi.c	2007-03-19 11:39:00.000000000 +0100
@@ -1,6 +1,7 @@
 /*
- * i2c-algo-sgi.c: i2c driver algorithms for SGI adapters.
- * 
+ * i2c-algo-sgi.c: i2c driver algorithm used by the VINO (SGI Indy) and
+ * MACE (SGI O2) chips.
+ *
  * This file is subject to the terms and conditions of the GNU General Public
  * License version 2 as published by the Free Software Foundation.
  *
@@ -162,8 +163,8 @@
 	.functionality	= sgi_func,
 };
 
-/* 
- * registering functions to load algorithms at runtime 
+/*
+ * registering functions to load algorithms at runtime
  */
 int i2c_sgi_add_bus(struct i2c_adapter *adap)
 {

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

* Re: [PATCH 8/12] drivers: PMC MSP71xx TWI driver]
  2007-03-16 23:03 Ralf Baechle
@ 2007-03-17  7:52 ` Jean Delvare
  2007-03-19 10:41   ` Ladislav Michl
  0 siblings, 1 reply; 6+ messages in thread
From: Jean Delvare @ 2007-03-17  7:52 UTC (permalink / raw)
  To: 200703162139.l2GLdpuH001568
  Cc: Ralf Baechle, Marc St-Jean, akpm, linux-mips, i2c

Marc,

> ----- Forwarded message from Marc St-Jean <stjeanma@pmc-sierra.com> -----
> 
> From:	Marc St-Jean <stjeanma@pmc-sierra.com>
> Date:	Fri, 16 Mar 2007 15:39:51 -0600
> To:	akpm@linux-foundation.org
> Cc:	linux-mips@linux-mips.org
> Subject: [PATCH 8/12] drivers: PMC MSP71xx TWI driver
> 
> [PATCH 8/12] drivers: PMC MSP71xx TWI driver
> 
> Patch to add TWI driver for the PMC-Sierra MSP71xx devices.
> 
> Reposting patches as a single set at the request of akpm.
> Only 9 of 12 will be posted at this time, 3 more to follow
> when cleanups are complete.
> 
> CCing linux-mips.org since minor changes have occured
> during cleanup of driver patches for other lists.
> 
> Thanks,
> Marc
> 
> Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
> ---
> Re-posting patch with recommended changes:
> -No changes.
> 
>  drivers/i2c/algos/Kconfig           |    9 
>  drivers/i2c/algos/Makefile          |    1 
>  drivers/i2c/algos/i2c-algo-pmctwi.c |  197 ++++++++++++++++
>  drivers/i2c/busses/Kconfig          |    7 
>  drivers/i2c/busses/Makefile         |    1 
>  drivers/i2c/busses/i2c-pmcmsp.c     |  419 ++++++++++++++++++++++++++++++++++++
>  include/linux/i2c-algo-pmctwi.h     |  135 +++++++++++
>  7 files changed, 768 insertions(+), 1 deletion(-)

Why are you making a separate algorithm driver? This should really only
be done when the algorithm is very generic. This is the exception, not
the rule. These days I tend to move algorithm code back into the only
bus driver that uses them (i2c-algo-sibyte done recently, i2c-algo-sgi
is next on my list.)

> 
> diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
> index af02034..794f7bb 100644
> --- a/drivers/i2c/algos/Kconfig
> +++ b/drivers/i2c/algos/Kconfig
> @@ -49,5 +49,12 @@ config I2C_ALGO_SGI
>  	  Supports the SGI interfaces like the ones found on SGI Indy VINO
>  	  or SGI O2 MACE.
>  
> -endmenu
> +config I2C_ALGO_PMCTWI
> +	tristate "I2C PMC TWI interfaces"
> +	depends on I2C && PMC_MSP

As a matter of fact, each time an algorithm depends on specific
hardware, you can be reasonably certain that it should NOT be made a
generic algorithm driver.

> +	help
> +	  Implements the PMC TWI SoC algorithm for various implementations.
>  
> +	  Be sure to select the proper bus for your platform below.
> +
> +endmenu

-- 
Jean Delvare

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

* [PATCH 8/12] drivers: PMC MSP71xx TWI driver]
@ 2007-03-16 23:03 Ralf Baechle
  2007-03-17  7:52 ` Jean Delvare
  0 siblings, 1 reply; 6+ messages in thread
From: Ralf Baechle @ 2007-03-16 23:03 UTC (permalink / raw)
  To: Marc St-Jean, akpm, khali; +Cc: linux-mips, i2c

Resending this cc'ed to the I2C list and maintainer Jean Delvare.

At a quick glance it looks like a fair driver but it will need some changes
to work for Linux 2.6.22 but I'll leave the details to Jean Delvare.

  Ralf

----- Forwarded message from Marc St-Jean <stjeanma@pmc-sierra.com> -----

From:	Marc St-Jean <stjeanma@pmc-sierra.com>
Date:	Fri, 16 Mar 2007 15:39:51 -0600
To:	akpm@linux-foundation.org
Cc:	linux-mips@linux-mips.org
Subject: [PATCH 8/12] drivers: PMC MSP71xx TWI driver

[PATCH 8/12] drivers: PMC MSP71xx TWI driver

Patch to add TWI driver for the PMC-Sierra MSP71xx devices.

Reposting patches as a single set at the request of akpm.
Only 9 of 12 will be posted at this time, 3 more to follow
when cleanups are complete.

CCing linux-mips.org since minor changes have occured
during cleanup of driver patches for other lists.

Thanks,
Marc

Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
---
Re-posting patch with recommended changes:
-No changes.

 drivers/i2c/algos/Kconfig           |    9 
 drivers/i2c/algos/Makefile          |    1 
 drivers/i2c/algos/i2c-algo-pmctwi.c |  197 ++++++++++++++++
 drivers/i2c/busses/Kconfig          |    7 
 drivers/i2c/busses/Makefile         |    1 
 drivers/i2c/busses/i2c-pmcmsp.c     |  419 ++++++++++++++++++++++++++++++++++++
 include/linux/i2c-algo-pmctwi.h     |  135 +++++++++++
 7 files changed, 768 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index af02034..794f7bb 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -49,5 +49,12 @@ config I2C_ALGO_SGI
 	  Supports the SGI interfaces like the ones found on SGI Indy VINO
 	  or SGI O2 MACE.
 
-endmenu
+config I2C_ALGO_PMCTWI
+	tristate "I2C PMC TWI interfaces"
+	depends on I2C && PMC_MSP
+	help
+	  Implements the PMC TWI SoC algorithm for various implementations.
 
+	  Be sure to select the proper bus for your platform below.
+
+endmenu
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
index cac1051..2645d00 100644
--- a/drivers/i2c/algos/Makefile
+++ b/drivers/i2c/algos/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bit.o
 obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
 obj-$(CONFIG_I2C_ALGOPCA)	+= i2c-algo-pca.o
 obj-$(CONFIG_I2C_ALGO_SGI)	+= i2c-algo-sgi.o
+obj-$(CONFIG_I2C_ALGO_PMCTWI)	+= i2c-algo-pmctwi.o
 
 ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/algos/i2c-algo-pmctwi.c b/drivers/i2c/algos/i2c-algo-pmctwi.c
new file mode 100644
index 0000000..160f0e9
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-pmctwi.c
@@ -0,0 +1,197 @@
+/*
+ * Device-independent algorithm for using PMC-TWI SoC busses.
+ *
+ * See drivers/i2c/busses/i2c-pmcmsp.c for an example implementation.
+ *
+ * Copyright 2005-2007 PMC-Sierra, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pmctwi.h>
+
+/* 
+ * Sends an i2c command out on the adapter
+ * Return -1 on error.
+ */
+static int pmctwi_master_xfer(struct i2c_adapter *adap,
+				struct i2c_msg *m, int num)
+{
+	struct pmctwi_data *busops = adap->algo_data;
+	int i, ret = 0, dual, probe;
+	struct i2c_msg *cmsg, *nmsg;
+	u8 detect_buffer[] = { 0 };
+
+	for (i = 0; i < num; i++) {
+		struct pmctwi_cmd cmd;
+		struct pmctwi_cfg oldcfg, newcfg;
+
+		probe = 0;
+		dual = 0;
+		cmsg = m + i;
+		nmsg = NULL;
+
+		if ((num - i) >= 2) {
+			/* Check for a dual write-then-read command */
+			nmsg = cmsg + 1;
+			dual = !((cmsg->flags & I2C_M_RD)) &&
+			       (nmsg->flags & I2C_M_RD) &&
+			       (cmsg->addr == nmsg->addr);
+		}
+
+		if (dual)
+			dev_dbg(&adap->dev, "Doing ops %d&%d of %d\n",
+				(i + 1), (i + 2), num);
+		else
+			dev_dbg(&adap->dev, "Doing op %d of %d\n",
+				(i + 1), num);
+
+		if (dual) {
+			cmd.type = PMCTWI_CMD_WRITE_READ;
+			cmd.write_len = cmsg->len;
+			cmd.write_data = (u8*)cmsg->buf;
+			cmd.read_len = nmsg->len;
+			cmd.read_data = (u8*)nmsg->buf;
+		} else if (cmsg->flags & I2C_M_RD) {
+			cmd.type = PMCTWI_CMD_READ;
+			cmd.read_len = cmsg->len;
+			cmd.read_data = (u8*)cmsg->buf;
+			cmd.write_len = 0;
+			cmd.write_data = NULL;
+		} else {
+			cmd.type = PMCTWI_CMD_WRITE;
+			cmd.read_len = 0;
+			cmd.read_data = NULL;
+			cmd.write_len = cmsg->len;
+			cmd.write_data = (u8*)cmsg->buf;
+		}
+
+		if (cmsg->len == 0) {
+			if (cmsg->flags & I2C_M_RD) {
+				dev_dbg(&adap->dev,
+					"Read of 0 bytes!  (illegal!)\n");
+				return -1;
+			} else {
+				dev_dbg(&adap->dev,
+					"Probing for slave at 0x%02x\n",
+					(cmsg->addr & 0xff));
+				probe = 1;
+
+				/*
+				 * Probe is a special read of 1 byte.
+				 * We don't care about the result, we just
+				 * want to see that it is successful.
+				 */
+				cmd.write_len = 1;
+				cmd.write_data = detect_buffer;
+				cmd.read_len = 1;
+				cmd.read_data = NULL;
+			}
+		}
+
+		cmd.addr = cmsg->addr;
+
+		if (probe || (cmsg->flags & I2C_M_TEN)) {
+			busops->get_twi_config(&newcfg, busops->data);
+			busops->get_twi_config(&oldcfg, busops->data);
+
+			/* For probes, we don't want any retries */
+			if (probe)
+				newcfg.nak = 0;
+
+			/* Set the special 10-bit address flag, if required */
+			if (cmsg->flags & I2C_M_TEN)
+				newcfg.add10 = 1;
+
+			busops->set_twi_config(&newcfg, busops->data);
+		}
+
+		ret = busops->xfer_cmd(&cmd, busops->data);
+
+		if (probe || (cmsg->flags & I2C_M_TEN))
+			busops->set_twi_config(&oldcfg, busops->data);
+
+		switch (ret) {
+		case PMCTWI_XFER_LOST_ARBITRATION:
+			dev_dbg(&adap->dev, "We lost arbitration: "
+				"Could not become bus master\n");
+			break;
+		case PMCTWI_XFER_NO_RESPONSE:
+			dev_dbg(&adap->dev, "No response\n");
+			break;
+		case PMCTWI_XFER_DATA_COLLISION:
+			dev_dbg(&adap->dev, "Data collision\n");
+			break;
+		case PMCTWI_XFER_BUSY:
+			dev_dbg(&adap->dev, "Port was busy\n");
+			/*
+			 *  TODO: We could potentially loop and retry
+			 *        in this case
+			 */
+			break;
+		case PMCTWI_XFER_TIMEOUT:
+			dev_dbg(&adap->dev, "Transfer timeout\n");
+			break;
+		}
+		if (ret != PMCTWI_XFER_OK) {
+			if (probe)
+				dev_dbg(&adap->dev, "Probe failed\n");
+			return -1;
+		}
+
+		if (dual) {
+			dev_dbg(&adap->dev,
+				"SMBus read 0x%02x from reg 0x%02x\n",
+				nmsg->buf[0], cmsg->buf[0]);
+
+			/* Skip one more ahead, since we just did 2 commands */
+			i++;
+		} else {
+			if (probe)
+				dev_dbg(&adap->dev, "Probe successful\n");
+			else
+				dev_dbg(&adap->dev,
+					"I2C %s %d bytes successfully\n",
+					(cmsg->flags & I2C_M_RD) ?
+						"read" : "wrote",
+					cmsg->len);
+		}
+	}
+
+	return 0;
+}
+
+static u32 pmctwi_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+}
+
+struct i2c_algorithm pmctwi_algorithm = {
+	.master_xfer	= pmctwi_master_xfer,
+	.smbus_xfer	= NULL,
+	.algo_control	= NULL,	/* TODO: someday */
+	.functionality	= pmctwi_i2c_func,
+};
+
+EXPORT_SYMBOL(pmctwi_algorithm);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 4d44a2d..f2998b8 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -573,4 +573,11 @@ config I2C_PNX
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-pnx.
 
+config I2C_PMCMSP
+	tristate "PMC MSP I2C Controller"
+	depends on I2C && PMC_MSP
+	select I2C_ALGO_PMCTWI
+	help
+	  Supports the special PMC TWI SoC chip on the MSP platform
+
 endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 03505aa..8923878 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT)	+= i2c-parport-light.o
 obj-$(CONFIG_I2C_PASEMI)	+= i2c-pasemi.o
 obj-$(CONFIG_I2C_PCA_ISA)	+= i2c-pca-isa.o
 obj-$(CONFIG_I2C_PIIX4)		+= i2c-piix4.o
+obj-$(CONFIG_I2C_PMCMSP)	+= i2c-pmcmsp.o
 obj-$(CONFIG_I2C_PNX)		+= i2c-pnx.o
 obj-$(CONFIG_I2C_PROSAVAGE)	+= i2c-prosavage.o
 obj-$(CONFIG_I2C_PXA)		+= i2c-pxa.o
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
new file mode 100644
index 0000000..a8b9cfa
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -0,0 +1,419 @@
+/*
+ * Specific bus support for PMC-TWI compliant implementation on 7120 chip
+ *
+ * Copyright 2005-2007 PMC-Sierra, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pmctwi.h>
+#include <linux/mutex.h>
+
+#include <asm/io.h>
+
+#include <msp_regs.h>
+#include <msp_cic_int.h>
+
+#define MSP_TW_SF_CLK_REG_OFFSET	0x00
+#define MSP_TW_HS_CLK_REG_OFFSET	0x04
+#define MSP_TW_CFG_REG_OFFSET		0x08
+#define MSP_TW_CMD_REG_OFFSET		0x0c
+#define MSP_TW_ADD_REG_OFFSET		0x10
+#define MSP_TW_DAT_0_REG_OFFSET		0x14
+#define MSP_TW_DAT_1_REG_OFFSET		0x18
+#define MSP_TW_INT_STS_REG_OFFSET	0x1c
+#define MSP_TW_INT_MSK_REG_OFFSET	0x20
+#define MSP_TW_BUSY_REG_OFFSET		0x24
+#define MSP_TW_REG_SIZE			0x28
+
+#define MSP_TW_INT_STS_DONE		(1 << 0)
+#define MSP_TW_INT_STS_LOST_ARBITRATION	(1 << 1)
+#define MSP_TW_INT_STS_NO_RESPONSE	(1 << 2)
+#define MSP_TW_INT_STS_DATA_COLLISION	(1 << 3)
+#define MSP_TW_INT_STS_BUSY		(1 << 4)
+#define MSP_TW_INT_STS_ALL		0x1f
+
+#define MSP_MAX_BYTES_PER_RW		8
+#define MSP_MAX_POLL			5
+#define MSP_POLL_DELAY			10
+#define MSP_IRQ_TIMEOUT			(MSP_MAX_POLL * MSP_POLL_DELAY)
+
+#define MSP_TW_IRQ 			MSP_INT_2WIRE
+/* Use the following instead to disable interrupt mode */
+/* #define MSP_TW_IRQ 			0 */
+
+/* IO Operation macros */
+#define pmcmsp_twi_readl	__raw_readl
+#define pmcmsp_twi_writel	__raw_writel
+
+struct pmcmsp_priv_data {
+	void __iomem *iobase;			/* iomapped base for IO */
+	enum pmctwi_xfer_result last_result;	/* result of last xfer */
+	int irq;				/* IRQ to use (0 disables) */
+	struct completion wait;			/* Completion struct for xfer */
+	struct mutex lock;			/* Used for threadsafeness */
+};
+
+static struct i2c_adapter pmcmsp_twi_adapter;
+
+/* The default settings */
+const static struct pmctwi_clockcfg pmctwi_defclockcfg = {
+	.standard = {
+		.filter = 0x3,
+		.clock = 0x1f,
+	},
+	.highspeed = {
+		.filter = 0x3,
+		.clock = 0x1f,
+	},
+};
+
+const static struct pmctwi_cfg pmctwi_deftwicfg = {
+	.arbf		= 0x03,
+	.nak		= 0x03,
+	.add10		= 0x00,
+	.mst_code	= 0x00,
+	.arb		= 0x01,
+	.highspeed	= 0x00,
+};
+
+/*
+ * Gets the current clock configuration
+ */
+static void pmcmsp_get_clock_config(struct pmctwi_clockcfg *cfg, void *data)
+{
+	struct pmcmsp_priv_data *p = data;
+	
+	mutex_lock(&p->lock);
+	pmctwi_reg_to_clock(pmcmsp_twi_readl(p->iobase +
+				MSP_TW_SF_CLK_REG_OFFSET),
+				&(cfg->standard));
+	pmctwi_reg_to_clock(pmcmsp_twi_readl(p->iobase +
+				MSP_TW_HS_CLK_REG_OFFSET),
+				&(cfg->highspeed));
+	mutex_unlock(&p->lock);
+}
+
+/*
+ * Sets the current clock configuration
+ */
+static void pmcmsp_set_clock_config(const struct pmctwi_clockcfg *cfg,
+					void *data)
+{
+	struct pmcmsp_priv_data *p = data;
+	
+	mutex_lock(&p->lock);
+	pmcmsp_twi_writel(pmctwi_clock_to_reg(&(cfg->standard)),
+				p->iobase + MSP_TW_SF_CLK_REG_OFFSET);
+	pmcmsp_twi_writel(pmctwi_clock_to_reg(&(cfg->highspeed)),
+				p->iobase + MSP_TW_HS_CLK_REG_OFFSET);
+	mutex_unlock(&p->lock);
+}
+
+/*
+ * Gets the current TWI bus configuration
+ */
+static void pmcmsp_get_twi_config(struct pmctwi_cfg *cfg, void *data)
+{
+	struct pmcmsp_priv_data *p = data;
+	
+	mutex_lock(&p->lock);
+	pmctwi_reg_to_cfg(pmcmsp_twi_readl(
+				p->iobase + MSP_TW_CFG_REG_OFFSET), cfg);
+	mutex_unlock(&p->lock);
+}
+
+/*
+ * Sets the current TWI bus configuration
+ */
+static void pmcmsp_set_twi_config(const struct pmctwi_cfg *cfg, void *data)
+{
+	struct pmcmsp_priv_data *p = data;
+	
+	mutex_lock(&p->lock);
+	pmcmsp_twi_writel(pmctwi_cfg_to_reg(cfg),
+				p->iobase + MSP_TW_CFG_REG_OFFSET);
+	mutex_unlock(&p->lock);
+}
+
+/*
+ * Parses the 'int_sts' register and returns a well-defined error code
+ */
+static enum pmctwi_xfer_result pmcmsp_get_result(u32 reg)
+{
+	if (reg & MSP_TW_INT_STS_LOST_ARBITRATION) {
+		dev_dbg(&pmcmsp_twi_adapter.dev,
+			"  Result: Lost arbitration\n");
+		return PMCTWI_XFER_LOST_ARBITRATION;
+	} else if (reg & MSP_TW_INT_STS_NO_RESPONSE) {
+		dev_dbg(&pmcmsp_twi_adapter.dev,
+			"  Result: No response\n");
+		return PMCTWI_XFER_NO_RESPONSE;
+	} else if (reg & MSP_TW_INT_STS_DATA_COLLISION) {
+		dev_dbg(&pmcmsp_twi_adapter.dev,
+			"  Result: Data collision\n");
+		return PMCTWI_XFER_DATA_COLLISION;
+	} else if (reg & MSP_TW_INT_STS_BUSY) {
+		dev_dbg(&pmcmsp_twi_adapter.dev,
+			"  Result: Bus busy\n");
+		return PMCTWI_XFER_BUSY;
+	}
+
+	dev_dbg(&pmcmsp_twi_adapter.dev, "  Result: Operation succeeded\n");
+	return PMCTWI_XFER_OK;
+}
+
+/*
+ * Polls the 'busy' register until the command is complete
+ * Note: Assumes p->lock is held.
+ */
+static void pmcmsp_poll_complete(struct pmcmsp_priv_data* p)
+{
+	int i;
+	u32 val = 0;
+	
+	for (i = 0; i < MSP_MAX_POLL; i++) {
+		val = pmcmsp_twi_readl(p->iobase + MSP_TW_BUSY_REG_OFFSET);
+		if (val == 0) {
+			u32 reason = pmcmsp_twi_readl(p->iobase +
+						MSP_TW_INT_STS_REG_OFFSET);
+			pmcmsp_twi_writel(reason, p->iobase +
+						MSP_TW_INT_STS_REG_OFFSET);
+			p->last_result = pmcmsp_get_result(reason);
+			return;
+		}
+		udelay(MSP_POLL_DELAY);
+	}
+
+	dev_dbg(&pmcmsp_twi_adapter.dev, "  Result: Poll timeout\n");
+	p->last_result = PMCTWI_XFER_TIMEOUT;
+}
+
+/*
+ * In interrupt mode, handle the interrupt
+ * Note: Assumes p->lock is held.
+ */
+static irqreturn_t pmcmsp_interrupt(int irq, void* data)
+{
+	struct pmcmsp_priv_data *p = data;
+	
+	u32 reason = pmcmsp_twi_readl(p->iobase + MSP_TW_INT_STS_REG_OFFSET);
+	pmcmsp_twi_writel(reason, p->iobase + MSP_TW_INT_STS_REG_OFFSET);
+
+	dev_dbg(&pmcmsp_twi_adapter.dev, "    Got interrupt 0x%08x\n",
+			reason);
+	if (!(reason & MSP_TW_INT_STS_DONE))
+		return IRQ_NONE;
+
+	p->last_result = pmcmsp_get_result(reason);
+	complete(&p->wait);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Do the transfer (low level):
+ *  - May use interrupt-driven or polling, depending on if an IRQ is
+ *  presently registered
+ * Note: Assumes p->lock is held
+ */
+static enum pmctwi_xfer_result pmcmsp_do_xfer(u32 reg,
+					struct pmcmsp_priv_data *p)
+{
+	dev_dbg(&pmcmsp_twi_adapter.dev, "  Writing cmd reg 0x%08x\n", reg);
+	pmcmsp_twi_writel(reg, p->iobase + MSP_TW_CMD_REG_OFFSET);
+	if (p->irq) {
+		unsigned long timeleft = wait_for_completion_timeout(
+						&p->wait, MSP_IRQ_TIMEOUT);
+		if (timeleft == 0) {
+			dev_dbg(&pmcmsp_twi_adapter.dev,
+				"  Result: IRQ timeout\n");
+			complete(&p->wait);
+			p->last_result = PMCTWI_XFER_TIMEOUT;
+		}
+	} else
+		pmcmsp_poll_complete(p);
+
+	return p->last_result;
+}
+
+/*
+ * Helper routine, converts 'pmctwi_cmd' struct to register format
+ */
+static inline u32 pmcmsp_cmd_to_reg(const struct pmctwi_cmd *cmd)
+{
+	return (u32)(((cmd->type & 0x3) << 8) |
+			(((cmd->write_len - 1) & 0x7) << 4) |
+			(((cmd->read_len - 1) & 0x7) << 0));
+}
+
+/*
+ * Do the transfer (high level)
+ */
+static enum pmctwi_xfer_result pmcmsp_xfer_cmd(struct pmctwi_cmd *cmd,
+						void *data)
+{
+	struct pmcmsp_priv_data *p = data;
+	u64 *write_data, *read_data;
+	enum pmctwi_xfer_result retval;
+
+	write_data = (u64*)cmd->write_data;
+	read_data = (u64*)cmd->read_data;
+
+	if ((cmd->type == PMCTWI_CMD_WRITE && cmd->write_len == 0) ||
+	    (cmd->type == PMCTWI_CMD_READ && cmd->read_len == 0) ||
+	    (cmd->type == PMCTWI_CMD_WRITE_READ &&
+	    (cmd->read_len == 0 || cmd->write_len == 0))) {
+		printk(KERN_ERR "%s: Cannot transfer less than 1 byte\n",
+		        __FUNCTION__);
+		return -1;
+	}
+
+	if ((cmd->read_len > MSP_MAX_BYTES_PER_RW) ||
+	    (cmd->write_len > MSP_MAX_BYTES_PER_RW)) {
+		printk(KERN_ERR "%s: Cannot transfer more than %d bytes\n",
+			__FUNCTION__, MSP_MAX_BYTES_PER_RW);
+	}
+
+	mutex_lock(&p->lock);
+	dev_dbg(&pmcmsp_twi_adapter.dev, "Setting address to 0x%08x\n",
+		cmd->addr);
+	pmcmsp_twi_writel(cmd->addr, p->iobase + MSP_TW_ADD_REG_OFFSET);
+
+	if ((cmd->type == PMCTWI_CMD_WRITE) ||
+	    (cmd->type == PMCTWI_CMD_WRITE_READ)) {
+		u64 tmp = be64_to_cpu(*write_data);
+		tmp >>= (8 - cmd->write_len) * 8;
+		dev_dbg(&pmcmsp_twi_adapter.dev, "Writing 0x%016llx\n", tmp);
+		pmcmsp_twi_writel((u32)(tmp & 0x00000000ffffffffLL),
+				p->iobase + MSP_TW_DAT_0_REG_OFFSET);
+		if (cmd->write_len > 4)
+			pmcmsp_twi_writel((u32)(tmp >> 32),
+					p->iobase + MSP_TW_DAT_1_REG_OFFSET);
+	}
+
+	retval = pmcmsp_do_xfer(pmcmsp_cmd_to_reg(cmd), p);
+
+	if ((cmd->type == PMCTWI_CMD_READ) ||
+	    (cmd->type == PMCTWI_CMD_WRITE_READ)) {
+		int i;
+		u64 rmsk = ~(0xffffffffffffffffLL << (cmd->read_len*8));
+		u64 tmp = (u64)pmcmsp_twi_readl(p->iobase +
+					MSP_TW_DAT_0_REG_OFFSET);
+		if (cmd->read_len > 4)
+			tmp |= (u64)pmcmsp_twi_readl(p->iobase +
+					MSP_TW_DAT_1_REG_OFFSET) << 32;
+		tmp &= rmsk;
+		dev_dbg(&pmcmsp_twi_adapter.dev, "Read 0x%016llx\n", tmp);
+		
+		for (i = 0; i < cmd->read_len; i++)
+			cmd->read_data[i] = (u8)((tmp >> i) & 0xff);
+	}
+	mutex_unlock(&p->lock);
+	
+	return retval;
+}
+
+static struct pmcmsp_priv_data pmcmsp_priv;
+
+static struct pmctwi_data pmcmsp_twi_algdata = {
+	.data			= (void*)&pmcmsp_priv,
+	.get_clock_config	= pmcmsp_get_clock_config,
+	.set_clock_config	= pmcmsp_set_clock_config,
+	.get_twi_config		= pmcmsp_get_twi_config,
+	.set_twi_config		= pmcmsp_set_twi_config,
+	.xfer_cmd		= pmcmsp_xfer_cmd,
+};
+
+static struct i2c_adapter pmcmsp_twi_adapter = {
+	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON,
+	.algo		= &pmctwi_algorithm,
+	.algo_data	= &pmcmsp_twi_algdata,
+	.name		= "PMC MSP TWI/SMB/I2C driver",
+};
+
+static int __init pmcmsp_twi_init(void)
+{
+	pmcmsp_priv.iobase = ioremap(MSP_TWI_BASE, MSP_TW_REG_SIZE);
+	if (pmcmsp_priv.iobase == NULL)
+		return -ENOMEM;
+
+	init_completion(&pmcmsp_priv.wait); 
+	mutex_init(&pmcmsp_priv.lock);
+	pmcmsp_priv.irq = MSP_TW_IRQ;
+
+	if (pmcmsp_priv.irq) {
+		int rc = request_irq(pmcmsp_priv.irq, pmcmsp_interrupt,
+				SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
+				"TWI", &pmcmsp_priv);
+		if (rc == 0) {
+			/*
+			 * Enable 'DONE' interrupt only
+			 *
+			 * If you enable all interrupts, you will get one on
+			 * error and another when the operation completes.
+			 * This way you only have to handle one interrupt,
+			 * but you can still check all result flags.
+			 */
+			pmcmsp_twi_writel(MSP_TW_INT_STS_DONE,
+					pmcmsp_priv.iobase +
+					MSP_TW_INT_MSK_REG_OFFSET);
+		} else {
+			printk(KERN_WARNING
+				"Could not assign TWI IRQ handler "
+				"to irq %d (continuing with poll)\n",
+				pmcmsp_priv.irq);
+			pmcmsp_priv.irq = 0;
+		}
+	}
+
+	pmcmsp_set_clock_config(&pmctwi_defclockcfg, &pmcmsp_priv);
+	pmcmsp_set_twi_config(&pmctwi_deftwicfg, &pmcmsp_priv);
+
+	printk(KERN_WARNING "Registering MSP7120 I2C adapter\n");
+
+	return i2c_add_adapter(&pmcmsp_twi_adapter);
+}
+
+static void __exit pmcmsp_twi_exit(void)
+{
+	if (pmcmsp_priv.irq) {
+		pmcmsp_twi_writel(0,
+			pmcmsp_priv.iobase + MSP_TW_INT_MSK_REG_OFFSET);
+		free_irq(pmcmsp_priv.irq, &pmcmsp_priv);
+	}
+	i2c_del_adapter(&pmcmsp_twi_adapter);
+}
+
+MODULE_DESCRIPTION("PMC MSP TWI/SMB/I2C driver");
+MODULE_LICENSE("GPL");
+
+module_init(pmcmsp_twi_init);
+module_exit(pmcmsp_twi_exit);
diff --git a/include/linux/i2c-algo-pmctwi.h b/include/linux/i2c-algo-pmctwi.h
new file mode 100644
index 0000000..7b6ca58
--- /dev/null
+++ b/include/linux/i2c-algo-pmctwi.h
@@ -0,0 +1,135 @@
+/*
+ * Device-independent algorithm for using PMC-TWI SoC busses.
+ *
+ * See drivers/i2c/busses/i2c-pmcmsp.c for an example implementation.
+ *
+ * Copyright 2005-2007 PMC-Sierra, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef I2C_ALGO_PMCTWI_H
+#define I2C_ALGO_PMCTWI_H
+
+#include <linux/i2c.h>
+
+/* TWI command type */
+enum pmctwi_cmd_type {
+	PMCTWI_CMD_WRITE	= 0, /* Write only */
+	PMCTWI_CMD_READ		= 1, /* Read only */
+	PMCTWI_CMD_WRITE_READ	= 2, /* Write then Read */
+	PMCTWI_CMD_RESERVED	= 3,
+};
+
+/* Corresponds to a PMCTWI clock configuration register */
+struct pmctwi_clock {
+	u8 filter;	/* Bits 15:12,	default = 0x03 */
+	u16 clock;	/* Bits 9:0,	default = 0x001f */
+};
+
+static inline u32 pmctwi_clock_to_reg(const struct pmctwi_clock *clock) {
+	return (u32)(((clock->filter & 0xf) << 12) |
+			(clock->clock & 0x03ff));
+}
+
+static inline void pmctwi_reg_to_clock(u32 reg, struct pmctwi_clock *clock) {
+	clock->filter = (u8)((reg >> 12) & 0xf);
+	clock->clock = (u16)(reg & 0x03ff);
+}
+
+struct pmctwi_clockcfg {
+	struct pmctwi_clock standard;	/* The standard/fast clock config */
+	struct pmctwi_clock highspeed;	/* The highspeed clock config */
+};
+
+/* Corresponds to the main TWI configuration register */
+struct pmctwi_cfg {
+	u8 arbf;	/* Bits 15:12,	default=0x03 */
+	u8 nak;		/* Bits 11:8,	default=0x03 */
+	u8 add10;	/* Bit 7,	default=0x00 */
+	u8 mst_code;	/* Bits 6:4,	default=0x00 */
+	u8 arb;		/* Bit 1,	default=0x01 */
+	u8 highspeed;	/* Bit 0,	default=0x00 */
+};
+
+static inline u32 pmctwi_cfg_to_reg(const struct pmctwi_cfg *cfg) {
+	return (u32)(((cfg->arbf & 0xf) << 12) |
+			((cfg->nak & 0xf) << 8) |
+			((cfg->add10 & 0x1) << 7) |
+			((cfg->mst_code & 0x7) << 4) |
+			((cfg->arb & 0x1) << 1) |
+			((cfg->highspeed & 0x1) << 0));
+}
+
+static inline void pmctwi_reg_to_cfg(u32 reg, struct pmctwi_cfg *cfg) {
+	cfg->arbf = (u8)((reg >> 12) & 0xf);
+	cfg->nak = (u8)((reg >> 8) & 0xf);
+	cfg->add10 = (u8)((reg >> 7) & 0x1);
+	cfg->mst_code = (u8)((reg >> 4) & 0x7);
+	cfg->arb = (u8)((reg >> 1) & 0x1);
+	cfg->highspeed = (u8)(reg & 0x1);
+}
+
+/* A single pmctwi command to issue */
+struct pmctwi_cmd {
+	u16 addr;	/* The slave address (7 or 10 bits) */
+	enum pmctwi_cmd_type type;	/* The command type */
+	u8 write_len;	/* Number of bytes in the write buffer */
+	u8 read_len;	/* Number of bytes in the read buffer */
+	u8*write_data;	/* Buffer of characters to send */
+	u8 *read_data;	/* Buffer to fill with incoming data */
+};
+
+/* The possible results of the xferCmd */
+enum pmctwi_xfer_result {
+	PMCTWI_XFER_OK	= 0,
+	PMCTWI_XFER_TIMEOUT,
+	PMCTWI_XFER_BUSY,
+	PMCTWI_XFER_DATA_COLLISION,
+	PMCTWI_XFER_NO_RESPONSE,
+	PMCTWI_XFER_LOST_ARBITRATION,
+};
+
+/* The set of operations each bus must implement to use this algorithm */
+struct pmctwi_data {
+	void *data;	/* Optional bus-specific data */
+
+	/* Get both clock configuration registers */
+	void (*get_clock_config)(struct pmctwi_clockcfg *cfg, void *data);
+
+	/* Set both clock configuration registers */
+	void (*set_clock_config)(const struct pmctwi_clockcfg *cfg,
+					void *data);
+
+	/* Get the TWI configuration register */
+	void (*get_twi_config)(struct pmctwi_cfg *cfg, void *data);
+
+	/* Set the TWI configuration register */
+	void (*set_twi_config)(const struct pmctwi_cfg *cfg, void *data);
+
+	/* Send the command, reading and/or writing all data specified */
+	enum pmctwi_xfer_result (*xfer_cmd)(struct pmctwi_cmd *cmd,
+						void *data);
+};
+
+extern struct i2c_algorithm pmctwi_algorithm;
+
+#endif /* I2C_ALGO_PMCTWI_H */

----- End forwarded message -----

  Ralf

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

end of thread, other threads:[~2007-03-21 15:36 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-03-21  0:42 [PATCH 8/12] drivers: PMC MSP71xx TWI driver] Marc St-Jean
2007-03-21 15:34 ` Jean Delvare
  -- strict thread matches above, loose matches on Subject: below --
2007-03-16 23:03 Ralf Baechle
2007-03-17  7:52 ` Jean Delvare
2007-03-19 10:41   ` Ladislav Michl
2007-03-19 13:36     ` Jean Delvare

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.