Re: [PATCH 1/2] i2c-mv64xxx: Add I2C Transaction Generator support

2013-06-07 Thread Russell King - ARM Linux
On Fri, Jun 07, 2013 at 05:42:22PM +0200, Gregory CLEMENT wrote:
> From: Zbigniew Bodek 
> 
> The I2C Transaction Generator offloads CPU from managing I2C
> transfer step by step.
> 
> This feature is currently only available on Armada XP, so usage of
> this mechanism is activated through device tree.
> 
> [gregory.clem...@free-electrons.com: Rewrite some part to be applied
> on the the code modified by Russell King's fixes]
> [gregory.clem...@free-electrons.com: Merge and split the commits to
> push them to the accurate maintainer i2c and of]]
> [gregory.clem...@free-electrons.com: Reword the commit log]
> 
> Signed-off-by: Piotr Ziecik 
> Signed-off-by: Gregory CLEMENT 
> ---
>  drivers/i2c/busses/i2c-mv64xxx.c | 143 
> +--
>  1 file changed, 139 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-mv64xxx.c 
> b/drivers/i2c/busses/i2c-mv64xxx.c
> index 6356439..5376dc3 100644
> --- a/drivers/i2c/busses/i2c-mv64xxx.c
> +++ b/drivers/i2c/busses/i2c-mv64xxx.c
> @@ -24,7 +24,7 @@
>  #include 
>  #include 
>  
> -/* Register defines */
> +/* Register defines (I2C port) */
>  #define  MV64XXX_I2C_REG_SLAVE_ADDR  0x00
>  #define  MV64XXX_I2C_REG_DATA0x04
>  #define  MV64XXX_I2C_REG_CONTROL 0x08
> @@ -59,6 +59,29 @@
>  #define  MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK0xe8
>  #define  MV64XXX_I2C_STATUS_NO_STATUS0xf8
>  
> +/* Register defines (I2C bridge) */
> +#define  MV64XXX_I2C_REG_TX_DATA_LO  0xC0
> +#define  MV64XXX_I2C_REG_TX_DATA_HI  0xC4
> +#define  MV64XXX_I2C_REG_RX_DATA_LO  0xC8
> +#define  MV64XXX_I2C_REG_RX_DATA_HI  0xCC
> +#define  MV64XXX_I2C_REG_BRIDGE_CONTROL  0xD0
> +#define  MV64XXX_I2C_REG_BRIDGE_STATUS   0xD4
> +#define  MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE   0xD8
> +#define  MV64XXX_I2C_REG_BRIDGE_INTR_MASK0xDC
> +#define  MV64XXX_I2C_REG_BRIDGE_TIMING   0xE0
> +
> +/* Bridge Control values */
> +#define  MV64XXX_I2C_BRIDGE_CONTROL_WR   0x0001
> +#define  MV64XXX_I2C_BRIDGE_CONTROL_RD   0x0002
> +#define  MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT   2
> +#define  MV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT 0x1000
> +#define  MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT13
> +#define  MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT16
> +#define  MV64XXX_I2C_BRIDGE_CONTROL_ENABLE   0x0008
> +
> +/* Bridge Status values */
> +#define  MV64XXX_I2C_BRIDGE_STATUS_ERROR 0x0001
> +
>  /* Driver states */
>  enum {
>   MV64XXX_I2C_STATE_INVALID,
> @@ -110,6 +133,7 @@ struct mv64xxx_i2c_data {
>   spinlock_t  lock;
>   struct i2c_msg  *msg;
>   struct i2c_adapter  adapter;
> + int bridge_enabled;
>  };
>  
>  static void
> @@ -157,6 +181,16 @@ mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
>   writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
>   writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
>   drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
> +
> + if (drv_data->bridge_enabled) {
> + writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
> + writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_TIMING);
> + writel(0, drv_data->reg_base +
> + MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
> + writel(0, drv_data->reg_base +
> + MV64XXX_I2C_REG_BRIDGE_INTR_MASK);
> + }
> +
>   drv_data->state = MV64XXX_I2C_STATE_IDLE;
>  }
>  
> @@ -368,6 +402,19 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
>   irqreturn_t rc = IRQ_NONE;
>  
>   spin_lock_irqsave(_data->lock, flags);
> +
> + if (drv_data->bridge_enabled) {
> + if (readl(drv_data->reg_base +
> + MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE)) {
> + writel(0, drv_data->reg_base +
> + MV64XXX_I2C_REG_BRIDGE_CONTROL);
> + writel(0, drv_data->reg_base +
> + MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
> + drv_data->block = 0;
> + wake_up(_data->waitq);
> + rc = IRQ_HANDLED;
> + }
> + }
>   while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) &
>   MV64XXX_I2C_REG_CONTROL_IFLG) {
>   status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS);
> @@ -446,6 +493,81 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data 
> *drv_data, struct i2c_msg *msg,
>   return drv_data->rc;
>  }
>  
> 

Re: [PATCH 1/2] i2c-mv64xxx: Add I2C Transaction Generator support

2013-06-07 Thread Thomas Petazzoni
Dear Gregory CLEMENT,

On Fri,  7 Jun 2013 17:42:22 +0200, Gregory CLEMENT wrote:

>  /* Driver states */
>  enum {
>   MV64XXX_I2C_STATE_INVALID,
> @@ -110,6 +133,7 @@ struct mv64xxx_i2c_data {
>   spinlock_t  lock;
>   struct i2c_msg  *msg;
>   struct i2c_adapter  adapter;
> + int bridge_enabled;

bool ?

> @@ -528,6 +652,7 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
>  {
>   u32 bus_freq, tclk;
>   int rc = 0;
> + const char *bridge_status;
>  
>   /* CLK is mandatory when using DT to describe the i2c bus. We
>* need to know tclk in order to calculate bus clock
> @@ -554,6 +679,15 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
>* So hard code the value to 1 second.
>*/
>   drv_data->adapter.timeout = HZ;
> +
> + /*
> +  * Acquire information on Transaction Generator support.
> +  */
> + bridge_status = of_get_property(np, "", NULL);

It is not clear to me what this new bridge_status local variable is
doing.

> + if (of_property_read_bool(np, "i2c,i2c-bridge"))
> + drv_data->bridge_enabled = 1;
> + else
> + drv_data->bridge_enabled = 0;

This could be written directly as:

drv_data->bridge_enabled = of_property_read_bool(np, "i2c,i2c-bridge");

Thanks,

Thomas
-- 
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/2] i2c-mv64xxx: Add I2C Transaction Generator support

2013-06-07 Thread Gregory CLEMENT
From: Zbigniew Bodek 

The I2C Transaction Generator offloads CPU from managing I2C
transfer step by step.

This feature is currently only available on Armada XP, so usage of
this mechanism is activated through device tree.

[gregory.clem...@free-electrons.com: Rewrite some part to be applied
on the the code modified by Russell King's fixes]
[gregory.clem...@free-electrons.com: Merge and split the commits to
push them to the accurate maintainer i2c and of]]
[gregory.clem...@free-electrons.com: Reword the commit log]

Signed-off-by: Piotr Ziecik 
Signed-off-by: Gregory CLEMENT 
---
 drivers/i2c/busses/i2c-mv64xxx.c | 143 +--
 1 file changed, 139 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 6356439..5376dc3 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -24,7 +24,7 @@
 #include 
 #include 
 
-/* Register defines */
+/* Register defines (I2C port) */
 #defineMV64XXX_I2C_REG_SLAVE_ADDR  0x00
 #defineMV64XXX_I2C_REG_DATA0x04
 #defineMV64XXX_I2C_REG_CONTROL 0x08
@@ -59,6 +59,29 @@
 #defineMV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK0xe8
 #defineMV64XXX_I2C_STATUS_NO_STATUS0xf8
 
+/* Register defines (I2C bridge) */
+#defineMV64XXX_I2C_REG_TX_DATA_LO  0xC0
+#defineMV64XXX_I2C_REG_TX_DATA_HI  0xC4
+#defineMV64XXX_I2C_REG_RX_DATA_LO  0xC8
+#defineMV64XXX_I2C_REG_RX_DATA_HI  0xCC
+#defineMV64XXX_I2C_REG_BRIDGE_CONTROL  0xD0
+#defineMV64XXX_I2C_REG_BRIDGE_STATUS   0xD4
+#defineMV64XXX_I2C_REG_BRIDGE_INTR_CAUSE   0xD8
+#defineMV64XXX_I2C_REG_BRIDGE_INTR_MASK0xDC
+#defineMV64XXX_I2C_REG_BRIDGE_TIMING   0xE0
+
+/* Bridge Control values */
+#defineMV64XXX_I2C_BRIDGE_CONTROL_WR   0x0001
+#defineMV64XXX_I2C_BRIDGE_CONTROL_RD   0x0002
+#defineMV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT   2
+#defineMV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT 0x1000
+#defineMV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT13
+#defineMV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT16
+#defineMV64XXX_I2C_BRIDGE_CONTROL_ENABLE   0x0008
+
+/* Bridge Status values */
+#defineMV64XXX_I2C_BRIDGE_STATUS_ERROR 0x0001
+
 /* Driver states */
 enum {
MV64XXX_I2C_STATE_INVALID,
@@ -110,6 +133,7 @@ struct mv64xxx_i2c_data {
spinlock_t  lock;
struct i2c_msg  *msg;
struct i2c_adapter  adapter;
+   int bridge_enabled;
 };
 
 static void
@@ -157,6 +181,16 @@ mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+
+   if (drv_data->bridge_enabled) {
+   writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
+   writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_TIMING);
+   writel(0, drv_data->reg_base +
+   MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
+   writel(0, drv_data->reg_base +
+   MV64XXX_I2C_REG_BRIDGE_INTR_MASK);
+   }
+
drv_data->state = MV64XXX_I2C_STATE_IDLE;
 }
 
@@ -368,6 +402,19 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
irqreturn_t rc = IRQ_NONE;
 
spin_lock_irqsave(_data->lock, flags);
+
+   if (drv_data->bridge_enabled) {
+   if (readl(drv_data->reg_base +
+   MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE)) {
+   writel(0, drv_data->reg_base +
+   MV64XXX_I2C_REG_BRIDGE_CONTROL);
+   writel(0, drv_data->reg_base +
+   MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
+   drv_data->block = 0;
+   wake_up(_data->waitq);
+   rc = IRQ_HANDLED;
+   }
+   }
while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) &
MV64XXX_I2C_REG_CONTROL_IFLG) {
status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS);
@@ -446,6 +493,81 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, 
struct i2c_msg *msg,
return drv_data->rc;
 }
 
+static int
+mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg)
+{
+   unsigned long data_reg_hi = 0;
+   unsigned long data_reg_lo = 0;
+   

[PATCH 1/2] i2c-mv64xxx: Add I2C Transaction Generator support

2013-06-07 Thread Gregory CLEMENT
From: Zbigniew Bodek z...@semihalf.com

The I2C Transaction Generator offloads CPU from managing I2C
transfer step by step.

This feature is currently only available on Armada XP, so usage of
this mechanism is activated through device tree.

[gregory.clem...@free-electrons.com: Rewrite some part to be applied
on the the code modified by Russell King's fixes]
[gregory.clem...@free-electrons.com: Merge and split the commits to
push them to the accurate maintainer i2c and of]]
[gregory.clem...@free-electrons.com: Reword the commit log]

Signed-off-by: Piotr Ziecik ko...@semihalf.com
Signed-off-by: Gregory CLEMENT gregory.clem...@free-electrons.com
---
 drivers/i2c/busses/i2c-mv64xxx.c | 143 +--
 1 file changed, 139 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 6356439..5376dc3 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -24,7 +24,7 @@
 #include linux/clk.h
 #include linux/err.h
 
-/* Register defines */
+/* Register defines (I2C port) */
 #defineMV64XXX_I2C_REG_SLAVE_ADDR  0x00
 #defineMV64XXX_I2C_REG_DATA0x04
 #defineMV64XXX_I2C_REG_CONTROL 0x08
@@ -59,6 +59,29 @@
 #defineMV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK0xe8
 #defineMV64XXX_I2C_STATUS_NO_STATUS0xf8
 
+/* Register defines (I2C bridge) */
+#defineMV64XXX_I2C_REG_TX_DATA_LO  0xC0
+#defineMV64XXX_I2C_REG_TX_DATA_HI  0xC4
+#defineMV64XXX_I2C_REG_RX_DATA_LO  0xC8
+#defineMV64XXX_I2C_REG_RX_DATA_HI  0xCC
+#defineMV64XXX_I2C_REG_BRIDGE_CONTROL  0xD0
+#defineMV64XXX_I2C_REG_BRIDGE_STATUS   0xD4
+#defineMV64XXX_I2C_REG_BRIDGE_INTR_CAUSE   0xD8
+#defineMV64XXX_I2C_REG_BRIDGE_INTR_MASK0xDC
+#defineMV64XXX_I2C_REG_BRIDGE_TIMING   0xE0
+
+/* Bridge Control values */
+#defineMV64XXX_I2C_BRIDGE_CONTROL_WR   0x0001
+#defineMV64XXX_I2C_BRIDGE_CONTROL_RD   0x0002
+#defineMV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT   2
+#defineMV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT 0x1000
+#defineMV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT13
+#defineMV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT16
+#defineMV64XXX_I2C_BRIDGE_CONTROL_ENABLE   0x0008
+
+/* Bridge Status values */
+#defineMV64XXX_I2C_BRIDGE_STATUS_ERROR 0x0001
+
 /* Driver states */
 enum {
MV64XXX_I2C_STATE_INVALID,
@@ -110,6 +133,7 @@ struct mv64xxx_i2c_data {
spinlock_t  lock;
struct i2c_msg  *msg;
struct i2c_adapter  adapter;
+   int bridge_enabled;
 };
 
 static void
@@ -157,6 +181,16 @@ mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
writel(0, drv_data-reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
drv_data-reg_base + MV64XXX_I2C_REG_CONTROL);
+
+   if (drv_data-bridge_enabled) {
+   writel(0, drv_data-reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
+   writel(0, drv_data-reg_base + MV64XXX_I2C_REG_BRIDGE_TIMING);
+   writel(0, drv_data-reg_base +
+   MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
+   writel(0, drv_data-reg_base +
+   MV64XXX_I2C_REG_BRIDGE_INTR_MASK);
+   }
+
drv_data-state = MV64XXX_I2C_STATE_IDLE;
 }
 
@@ -368,6 +402,19 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
irqreturn_t rc = IRQ_NONE;
 
spin_lock_irqsave(drv_data-lock, flags);
+
+   if (drv_data-bridge_enabled) {
+   if (readl(drv_data-reg_base +
+   MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE)) {
+   writel(0, drv_data-reg_base +
+   MV64XXX_I2C_REG_BRIDGE_CONTROL);
+   writel(0, drv_data-reg_base +
+   MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
+   drv_data-block = 0;
+   wake_up(drv_data-waitq);
+   rc = IRQ_HANDLED;
+   }
+   }
while (readl(drv_data-reg_base + MV64XXX_I2C_REG_CONTROL) 
MV64XXX_I2C_REG_CONTROL_IFLG) {
status = readl(drv_data-reg_base + MV64XXX_I2C_REG_STATUS);
@@ -446,6 +493,81 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, 
struct i2c_msg *msg,
return drv_data-rc;
 }
 
+static int
+mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg)
+{
+   

Re: [PATCH 1/2] i2c-mv64xxx: Add I2C Transaction Generator support

2013-06-07 Thread Thomas Petazzoni
Dear Gregory CLEMENT,

On Fri,  7 Jun 2013 17:42:22 +0200, Gregory CLEMENT wrote:

  /* Driver states */
  enum {
   MV64XXX_I2C_STATE_INVALID,
 @@ -110,6 +133,7 @@ struct mv64xxx_i2c_data {
   spinlock_t  lock;
   struct i2c_msg  *msg;
   struct i2c_adapter  adapter;
 + int bridge_enabled;

bool ?

 @@ -528,6 +652,7 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
  {
   u32 bus_freq, tclk;
   int rc = 0;
 + const char *bridge_status;
  
   /* CLK is mandatory when using DT to describe the i2c bus. We
* need to know tclk in order to calculate bus clock
 @@ -554,6 +679,15 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
* So hard code the value to 1 second.
*/
   drv_data-adapter.timeout = HZ;
 +
 + /*
 +  * Acquire information on Transaction Generator support.
 +  */
 + bridge_status = of_get_property(np, , NULL);

It is not clear to me what this new bridge_status local variable is
doing.

 + if (of_property_read_bool(np, i2c,i2c-bridge))
 + drv_data-bridge_enabled = 1;
 + else
 + drv_data-bridge_enabled = 0;

This could be written directly as:

drv_data-bridge_enabled = of_property_read_bool(np, i2c,i2c-bridge);

Thanks,

Thomas
-- 
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 1/2] i2c-mv64xxx: Add I2C Transaction Generator support

2013-06-07 Thread Russell King - ARM Linux
On Fri, Jun 07, 2013 at 05:42:22PM +0200, Gregory CLEMENT wrote:
 From: Zbigniew Bodek z...@semihalf.com
 
 The I2C Transaction Generator offloads CPU from managing I2C
 transfer step by step.
 
 This feature is currently only available on Armada XP, so usage of
 this mechanism is activated through device tree.
 
 [gregory.clem...@free-electrons.com: Rewrite some part to be applied
 on the the code modified by Russell King's fixes]
 [gregory.clem...@free-electrons.com: Merge and split the commits to
 push them to the accurate maintainer i2c and of]]
 [gregory.clem...@free-electrons.com: Reword the commit log]
 
 Signed-off-by: Piotr Ziecik ko...@semihalf.com
 Signed-off-by: Gregory CLEMENT gregory.clem...@free-electrons.com
 ---
  drivers/i2c/busses/i2c-mv64xxx.c | 143 
 +--
  1 file changed, 139 insertions(+), 4 deletions(-)
 
 diff --git a/drivers/i2c/busses/i2c-mv64xxx.c 
 b/drivers/i2c/busses/i2c-mv64xxx.c
 index 6356439..5376dc3 100644
 --- a/drivers/i2c/busses/i2c-mv64xxx.c
 +++ b/drivers/i2c/busses/i2c-mv64xxx.c
 @@ -24,7 +24,7 @@
  #include linux/clk.h
  #include linux/err.h
  
 -/* Register defines */
 +/* Register defines (I2C port) */
  #define  MV64XXX_I2C_REG_SLAVE_ADDR  0x00
  #define  MV64XXX_I2C_REG_DATA0x04
  #define  MV64XXX_I2C_REG_CONTROL 0x08
 @@ -59,6 +59,29 @@
  #define  MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK0xe8
  #define  MV64XXX_I2C_STATUS_NO_STATUS0xf8
  
 +/* Register defines (I2C bridge) */
 +#define  MV64XXX_I2C_REG_TX_DATA_LO  0xC0
 +#define  MV64XXX_I2C_REG_TX_DATA_HI  0xC4
 +#define  MV64XXX_I2C_REG_RX_DATA_LO  0xC8
 +#define  MV64XXX_I2C_REG_RX_DATA_HI  0xCC
 +#define  MV64XXX_I2C_REG_BRIDGE_CONTROL  0xD0
 +#define  MV64XXX_I2C_REG_BRIDGE_STATUS   0xD4
 +#define  MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE   0xD8
 +#define  MV64XXX_I2C_REG_BRIDGE_INTR_MASK0xDC
 +#define  MV64XXX_I2C_REG_BRIDGE_TIMING   0xE0
 +
 +/* Bridge Control values */
 +#define  MV64XXX_I2C_BRIDGE_CONTROL_WR   0x0001
 +#define  MV64XXX_I2C_BRIDGE_CONTROL_RD   0x0002
 +#define  MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT   2
 +#define  MV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT 0x1000
 +#define  MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT13
 +#define  MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT16
 +#define  MV64XXX_I2C_BRIDGE_CONTROL_ENABLE   0x0008
 +
 +/* Bridge Status values */
 +#define  MV64XXX_I2C_BRIDGE_STATUS_ERROR 0x0001
 +
  /* Driver states */
  enum {
   MV64XXX_I2C_STATE_INVALID,
 @@ -110,6 +133,7 @@ struct mv64xxx_i2c_data {
   spinlock_t  lock;
   struct i2c_msg  *msg;
   struct i2c_adapter  adapter;
 + int bridge_enabled;
  };
  
  static void
 @@ -157,6 +181,16 @@ mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
   writel(0, drv_data-reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
   writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
   drv_data-reg_base + MV64XXX_I2C_REG_CONTROL);
 +
 + if (drv_data-bridge_enabled) {
 + writel(0, drv_data-reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
 + writel(0, drv_data-reg_base + MV64XXX_I2C_REG_BRIDGE_TIMING);
 + writel(0, drv_data-reg_base +
 + MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
 + writel(0, drv_data-reg_base +
 + MV64XXX_I2C_REG_BRIDGE_INTR_MASK);
 + }
 +
   drv_data-state = MV64XXX_I2C_STATE_IDLE;
  }
  
 @@ -368,6 +402,19 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
   irqreturn_t rc = IRQ_NONE;
  
   spin_lock_irqsave(drv_data-lock, flags);
 +
 + if (drv_data-bridge_enabled) {
 + if (readl(drv_data-reg_base +
 + MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE)) {
 + writel(0, drv_data-reg_base +
 + MV64XXX_I2C_REG_BRIDGE_CONTROL);
 + writel(0, drv_data-reg_base +
 + MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
 + drv_data-block = 0;
 + wake_up(drv_data-waitq);
 + rc = IRQ_HANDLED;
 + }
 + }
   while (readl(drv_data-reg_base + MV64XXX_I2C_REG_CONTROL) 
   MV64XXX_I2C_REG_CONTROL_IFLG) {
   status = readl(drv_data-reg_base + MV64XXX_I2C_REG_STATUS);
 @@ -446,6 +493,81 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data 
 *drv_data, struct i2c_msg *msg,
   return drv_data-rc;
  }
  
 +static int