[PATCH 4/4] i2c: imx: disable clock when it's possible to save power.

2009-09-30 Thread Richard Zhao
Enable clock before START, disable it after STOP.

Signed-off-by: Richard Zhao 

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 87faea4..72ddea3 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -120,6 +120,7 @@ struct imx_i2c_struct {
wait_queue_head_t   queue;
unsigned long   i2csr;
unsigned intdisable_delay;
+   unsigned intifdr; /* IMX_I2C_IFDR */
 };
 
 /** Functions for IMX I2C adapter driver 
***
@@ -210,6 +211,8 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
 
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
 
+   clk_enable(i2c_imx->clk);
+   writeb(i2c_imx->ifdr, i2c_imx->base + IMX_I2C_IFDR);
/* Enable I2C controller */
writeb(0, i2c_imx->base + IMX_I2C_I2SR);
writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
@@ -254,6 +257,7 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
 
/* Disable I2C controller */
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
+   clk_disable(i2c_imx->clk);
 }
 
 static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
@@ -273,8 +277,8 @@ static void __init i2c_imx_set_clk(struct imx_i2c_struct 
*i2c_imx,
else
for (i = 0; i2c_clk_div[i][0] < div; i++);
 
-   /* Write divider value to register */
-   writeb(i2c_clk_div[i][1], i2c_imx->base + IMX_I2C_IFDR);
+   /* Store divider value */
+   i2c_imx->ifdr = i2c_clk_div[i][1];
 
if (cpu_is_mx1()) {
/*
@@ -555,7 +559,6 @@ static int __init i2c_imx_probe(struct platform_device 
*pdev)
dev_err(&pdev->dev, "can't get I2C clock\n");
goto fail3;
}
-   clk_enable(i2c_imx->clk);
 
/* Request IRQ */
ret = request_irq(i2c_imx->irq, i2c_imx_isr, 0, pdev->name, i2c_imx);
@@ -604,7 +607,6 @@ static int __init i2c_imx_probe(struct platform_device 
*pdev)
 fail5:
free_irq(i2c_imx->irq, i2c_imx);
 fail4:
-   clk_disable(i2c_imx->clk);
clk_put(i2c_imx->clk);
 fail3:
release_mem_region(i2c_imx->res->start, resource_size(res));
@@ -641,8 +643,6 @@ static int __exit i2c_imx_remove(struct platform_device 
*pdev)
if (pdata && pdata->exit)
pdata->exit(&pdev->dev);
 
-   /* Disable I2C clock */
-   clk_disable(i2c_imx->clk);
clk_put(i2c_imx->clk);
 
release_mem_region(i2c_imx->res->start, resource_size(i2c_imx->res));
-- 
1.6.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/4] i2c: imx: only imx1 needs disable delay

2009-09-30 Thread Richard Zhao
check cpu_is_mx1() when set disable_delay.

Signed-off-by: Richard Zhao 

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 156cc95..c1e541c 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -254,14 +254,16 @@ static void __init i2c_imx_set_clk(struct imx_i2c_struct 
*i2c_imx,
/* Write divider value to register */
writeb(i2c_clk_div[i][1], i2c_imx->base + IMX_I2C_IFDR);
 
-   /*
-* There dummy delay is calculated.
-* It should be about one I2C clock period long.
-* This delay is used in I2C bus disable function
-* to fix chip hardware bug.
-*/
-   i2c_imx->disable_delay = (50U * i2c_clk_div[i][0]
-   + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2);
+   if (cpu_is_mx1()) {
+   /*
+* There dummy delay is calculated.
+* It should be about one I2C clock period long.
+* This delay is used in I2C bus disable function
+* to fix chip hardware bug.
+*/
+   i2c_imx->disable_delay = (50U * i2c_clk_div[i][0]
+   + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2);
+   }
 
/* dev_dbg() can't be used, because adapter is not yet registered */
 #ifdef CONFIG_I2C_DEBUG_BUS
-- 
1.6.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/4] i2c: imx: add macros and printk to make debug easy

2009-09-30 Thread Richard Zhao
When CONFIG_I2C_DEBUG_BUS is enabled, it helps dump registers at operation
fail condition, and print i2c_msg to xfer.

Signed-off-by: Richard Zhao 

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index c1e541c..87faea4 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -125,6 +125,20 @@ struct imx_i2c_struct {
 /** Functions for IMX I2C adapter driver 
***
 
***/
 
+#ifdef CONFIG_I2C_DEBUG_BUS
+#define reg_dump(i2c_imx) \
+{ \
+   printk(KERN_DEBUG "fun %s:%d ", __func__, __LINE__); \
+   printk(KERN_DEBUG "IADR %02x IFDR %02x I2CR %02x I2SR %02x\n", \
+   readb(i2c_imx->base + IMX_I2C_IADR), \
+   readb(i2c_imx->base + IMX_I2C_IFDR), \
+   readb(i2c_imx->base + IMX_I2C_I2CR), \
+   readb(i2c_imx->base + IMX_I2C_I2SR)); \
+}
+#else
+#define reg_dump(i2c_imx)
+#endif
+
 static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
 {
unsigned long orig_jiffies = jiffies;
@@ -146,6 +160,7 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, 
int for_busy)
if (time_after(jiffies, orig_jiffies + HZ / 1000)) {
dev_dbg(&i2c_imx->adapter.dev,
"<%s> I2C bus is busy\n", __func__);
+   reg_dump(i2c_imx);
return -EIO;
}
schedule();
@@ -164,9 +179,11 @@ static int i2c_imx_trx_complete(struct imx_i2c_struct 
*i2c_imx)
 
if (unlikely(result < 0)) {
dev_dbg(&i2c_imx->adapter.dev, "<%s> result < 0\n", __func__);
+   reg_dump(i2c_imx);
return result;
} else if (unlikely(!(i2c_imx->i2csr & I2SR_IIF))) {
dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__);
+   reg_dump(i2c_imx);
return -ETIMEDOUT;
}
dev_dbg(&i2c_imx->adapter.dev, "<%s> TRX complete\n", __func__);
@@ -178,6 +195,7 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
 {
if (readb(i2c_imx->base + IMX_I2C_I2SR) & I2SR_RXAK) {
dev_dbg(&i2c_imx->adapter.dev, "<%s> No ACK\n", __func__);
+   reg_dump(i2c_imx);
return -EIO;  /* No ACK */
}
 
@@ -197,17 +215,20 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
 
result = i2c_imx_bus_busy(i2c_imx, 0);
-   if (result)
+   if (result) {
+   reg_dump(i2c_imx);
return result;
+   }
 
/* Start I2C transaction */
temp = readb(i2c_imx->base + IMX_I2C_I2CR);
temp |= I2CR_MSTA;
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
result = i2c_imx_bus_busy(i2c_imx, 1);
-   if (result)
+   if (result) {
+   reg_dump(i2c_imx);
return result;
-
+   }
temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
return result;
@@ -228,7 +249,8 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
 */
udelay(i2c_imx->disable_delay);
 
-   i2c_imx_bus_busy(i2c_imx, 0);
+   if (i2c_imx_bus_busy(i2c_imx, 0))
+   reg_dump(i2c_imx);
 
/* Disable I2C controller */
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
@@ -389,7 +411,18 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
 
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
-
+#ifdef CONFIG_I2C_DEBUG_BUS
+   for (i = 0; i < num; i++) {
+   printk(KERN_DEBUG "msg%d addr %02x RD %d cnt %d d:", i,
+   msgs[i].addr, msgs[i].flags & I2C_M_RD, msgs[i].len);
+   if (!(msgs[i].flags & I2C_M_RD)) {
+   int j;
+   for (j = 0; j < msgs[i].len; j++)
+   printk("%02x ", msgs[i].buf[j]);
+   }
+   printk("\n");
+   }
+#endif
/* Start I2C transfer */
result = i2c_imx_start(i2c_imx);
if (result)
@@ -404,8 +437,10 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
temp |= I2CR_RSTA;
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
result =  i2c_imx_bus_busy(i2c_imx, 1);
-   if (result)
+   if (result) {
+   reg_dump(i2c_imx);
goto fail0;
+   }
}
dev_dbg(&i2c_imx->adapter.dev,
"<%s> transfer message: %d\n", __func__, i);
@@ -562,7 +597,7 @@ static int __init i2c_imx_probe(struct platform_device 
*pdev)
res_size, i2c_imx->res->start);

[PATCH 1/4] i2c: imx: check busy bit when START/STOP

2009-09-30 Thread Richard Zhao
After START/RESTART, wait for busy bit to be set and
after STOP, wait for busy bit to be clear.

Signed-off-by: Richard Zhao 

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 4afba3e..156cc95 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -125,14 +125,19 @@ struct imx_i2c_struct {
 /** Functions for IMX I2C adapter driver 
***
 
***/
 
-static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
 {
unsigned long orig_jiffies = jiffies;
+   unsigned int temp;
 
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
 
-   /* wait for bus not busy */
-   while (readb(i2c_imx->base + IMX_I2C_I2SR) & I2SR_IBB) {
+   temp = readb(i2c_imx->base + IMX_I2C_I2SR);
+   while (1) {
+   if (for_busy && (temp & I2SR_IBB))
+   break;
+   if (!for_busy && !(temp & I2SR_IBB))
+   break;
if (signal_pending(current)) {
dev_dbg(&i2c_imx->adapter.dev,
"<%s> I2C Interrupted\n", __func__);
@@ -144,6 +149,7 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx)
return -EIO;
}
schedule();
+   temp = readb(i2c_imx->base + IMX_I2C_I2SR);
}
 
return 0;
@@ -179,20 +185,32 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
return 0;
 }
 
-static void i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
 {
unsigned int temp = 0;
+   int result;
 
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
 
/* Enable I2C controller */
+   writeb(0, i2c_imx->base + IMX_I2C_I2SR);
writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
+
+   result = i2c_imx_bus_busy(i2c_imx, 0);
+   if (result)
+   return result;
+
/* Start I2C transaction */
temp = readb(i2c_imx->base + IMX_I2C_I2CR);
temp |= I2CR_MSTA;
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+   result = i2c_imx_bus_busy(i2c_imx, 1);
+   if (result)
+   return result;
+
temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+   return result;
 }
 
 static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
@@ -202,16 +220,16 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
/* Stop I2C transaction */
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
temp = readb(i2c_imx->base + IMX_I2C_I2CR);
-   temp &= ~I2CR_MSTA;
+   temp &= ~(I2CR_MSTA | I2CR_MTX);
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
-   /* setup chip registers to defaults */
-   writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
-   writeb(0, i2c_imx->base + IMX_I2C_I2SR);
/*
 * This delay caused by an i.MXL hardware bug.
 * If no (or too short) delay, no "STOP" bit will be generated.
 */
udelay(i2c_imx->disable_delay);
+
+   i2c_imx_bus_busy(i2c_imx, 0);
+
/* Disable I2C controller */
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
 }
@@ -344,7 +362,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, 
struct i2c_msg *msgs)
dev_dbg(&i2c_imx->adapter.dev,
"<%s> clear MSTA\n", __func__);
temp = readb(i2c_imx->base + IMX_I2C_I2CR);
-   temp &= ~I2CR_MSTA;
+   temp &= ~(I2CR_MSTA | I2CR_MTX);
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
} else if (i == (msgs->len - 2)) {
dev_dbg(&i2c_imx->adapter.dev,
@@ -370,14 +388,11 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
 
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
 
-   /* Check if i2c bus is not busy */
-   result = i2c_imx_bus_busy(i2c_imx);
+   /* Start I2C transfer */
+   result = i2c_imx_start(i2c_imx);
if (result)
goto fail0;
 
-   /* Start I2C transfer */
-   i2c_imx_start(i2c_imx);
-
/* read/write data */
for (i = 0; i < num; i++) {
if (i) {
@@ -386,6 +401,9 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
temp = readb(i2c_imx->base + IMX_I2C_I2CR);
temp |= I2CR_RSTA;
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+   result =  i2c_imx_bus_busy(i2c_imx, 1);
+   if (result)
+   goto fail0;
}
dev_dbg(&i2c_imx->adapter.dev,
"<%s> transfer message: %d\n", __func

Re: [PATCH] I2C: OMAP3: PM: (re)init for every transfer to support off-mode

2009-09-30 Thread Kevin Hilman
On Mon, Aug 3, 2009 at 3:11 PM, Kevin Hilman
 wrote:
> Ben Dooks wrote:
>>
>> On Tue, Jul 21, 2009 at 04:09:03PM -0700, Kevin Hilman wrote:
>>>
>>> From: Rajendra Nayak 
>>>
>>> Because of OMAP off-mode, powerdomain can go off when I2C is idle.
>>> Save enough state, and do a re-init for each transfer.
>>>
>>> Additional save/restore state added by Jagadeesh Bhaskar Pakaravoor
>>> (SYSC_REG) and Aaro Koskinen (wakeup sources.)
>>>
>>> Also, The OMAP3430 TRM states:
>>>
>>> "During active mode (I2Ci.I2C_CON[15] I2C_EN bit is set to 1), make no
>>> changes to the I2Ci.I2C_SCLL and I2Ci.I2C_SCLH registers.  Changes may
>>> result in unpredictable behavior."
>>>
>>> Hence, the I2C_EN bit should be clearer when modifying these
>>> registers. Please note that clearing the entire I2C_CON register to
>>> disable the I2C module is safe, because the I2C_CON register is
>>> re-configured for each transfer.
>>
>> should this be applied as a bugfix, or kept for next merge window?
>
> next merge window is fine.
>

Ben,

It doesn't look like this made it in during the 2.6.32 merge window.
Can you queue it for the -rc series?

Kevin

>>> Signed-off-by: Jouni Hogander 
>>> Signed-off-by: Rajendra Nayak 
>>> Cc: Jagadeesh Bhaskar Pakaravoor 
>>> Cc: Aaro Koskinen 
>>> Cc: Jon Hunter 
>>> Cc: Hu Tao 
>>> Cc: Xiaolong Chen 
>>> Signed-off-by: Kevin Hilman 
>>> ---
>>> This patch has been tested extensively as part of the OMAP 'PM branch'
>>>
>>>  drivers/i2c/busses/i2c-omap.c |   64
>>> ++--
>>>  1 files changed, 41 insertions(+), 23 deletions(-)
>>>
>>> diff --git a/drivers/i2c/busses/i2c-omap.c
>>> b/drivers/i2c/busses/i2c-omap.c
>>> index ad8d201..bb8ae50 100644
>>> --- a/drivers/i2c/busses/i2c-omap.c
>>> +++ b/drivers/i2c/busses/i2c-omap.c
>>> @@ -178,6 +178,12 @@ struct omap_i2c_dev {
>>>        unsigned                b_hw:1;         /* bad h/w fixes */
>>>        unsigned                idle:1;
>>>        u16                     iestate;        /* Saved interrupt
>>> register */
>>> +       u16                     pscstate;
>>> +       u16                     scllstate;
>>> +       u16                     sclhstate;
>>> +       u16                     bufstate;
>>> +       u16                     syscstate;
>>> +       u16                     westate;
>>>  };
>>>   static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
>>> @@ -230,9 +236,18 @@ static void omap_i2c_unidle(struct omap_i2c_dev
>>> *dev)
>>>          clk_enable(dev->iclk);
>>>        clk_enable(dev->fclk);
>>> +       if (cpu_is_omap34xx()) {
>>> +               omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
>>> +               omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
>>> +               omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG,
>>> dev->scllstate);
>>> +               omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG,
>>> dev->sclhstate);
>>> +               omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate);
>>> +               omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
>>> dev->syscstate);
>>> +               omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
>>> +               omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
>>> OMAP_I2C_CON_EN);
>>> +       }
>>>        dev->idle = 0;
>>> -       if (dev->iestate)
>>> -               omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
>>> +       omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
>>>  }
>>>   static void omap_i2c_idle(struct omap_i2c_dev *dev)
>>> @@ -258,7 +273,7 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
>>>   static int omap_i2c_init(struct omap_i2c_dev *dev)
>>>  {
>>> -       u16 psc = 0, scll = 0, sclh = 0;
>>> +       u16 psc = 0, scll = 0, sclh = 0, buf = 0;
>>>        u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
>>>        unsigned long fclk_rate = 1200;
>>>        unsigned long timeout;
>>> @@ -287,24 +302,22 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
>>>                                           SYSC_AUTOIDLE_MASK);
>>>                  } else if (dev->rev >= OMAP_I2C_REV_ON_3430) {
>>> -                       u32 v;
>>> -
>>> -                       v = SYSC_AUTOIDLE_MASK;
>>> -                       v |= SYSC_ENAWAKEUP_MASK;
>>> -                       v |= (SYSC_IDLEMODE_SMART <<
>>> +                       dev->syscstate = SYSC_AUTOIDLE_MASK;
>>> +                       dev->syscstate |= SYSC_ENAWAKEUP_MASK;
>>> +                       dev->syscstate |= (SYSC_IDLEMODE_SMART <<
>>>                              __ffs(SYSC_SIDLEMODE_MASK));
>>> -                       v |= (SYSC_CLOCKACTIVITY_FCLK <<
>>> +                       dev->syscstate |= (SYSC_CLOCKACTIVITY_FCLK <<
>>>                              __ffs(SYSC_CLOCKACTIVITY_MASK));
>>>  -                       omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, v);
>>> +                       omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
>>> +                                                       dev->syscstate);
>>>        

[PATCH] i2c: Bus drivers don't have to support I2C_M_REV_DIR_ADDR

2009-09-30 Thread Jean Delvare
I2C bus drivers don't have to support I2C_M_REV_DIR_ADDR. It is a
deviation from the I2C specification, which only makes sense to
implement when really needed.

Signed-off-by: Jean Delvare 
Cc: Ben Dooks 
---
 drivers/i2c/busses/i2c-iop3xx.c   |6 --
 drivers/i2c/busses/i2c-mv64xxx.c  |3 ---
 drivers/i2c/busses/i2c-powermac.c |2 --
 3 files changed, 11 deletions(-)

--- linux-2.6.32-rc1.orig/drivers/i2c/busses/i2c-iop3xx.c   2009-06-10 
05:05:27.0 +0200
+++ linux-2.6.32-rc1/drivers/i2c/busses/i2c-iop3xx.c2009-09-30 
21:34:01.0 +0200
@@ -56,12 +56,6 @@ iic_cook_addr(struct i2c_msg *msg)
if (msg->flags & I2C_M_RD)
addr |= 1;
 
-   /*
-* Read or Write?
-*/
-   if (msg->flags & I2C_M_REV_DIR_ADDR)
-   addr ^= 1;
-
return addr;   
 }
 
--- linux-2.6.32-rc1.orig/drivers/i2c/busses/i2c-mv64xxx.c  2009-09-28 
10:28:36.0 +0200
+++ linux-2.6.32-rc1/drivers/i2c/busses/i2c-mv64xxx.c   2009-09-30 
21:33:45.0 +0200
@@ -338,9 +338,6 @@ mv64xxx_i2c_prepare_for_io(struct mv64xx
if (msg->flags & I2C_M_RD)
dir = 1;
 
-   if (msg->flags & I2C_M_REV_DIR_ADDR)
-   dir ^= 1;
-
if (msg->flags & I2C_M_TEN) {
drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
drv_data->addr2 = (u32)msg->addr & 0xff;
--- linux-2.6.32-rc1.orig/drivers/i2c/busses/i2c-powermac.c 2009-09-30 
20:29:42.0 +0200
+++ linux-2.6.32-rc1/drivers/i2c/busses/i2c-powermac.c  2009-09-30 
21:33:39.0 +0200
@@ -156,8 +156,6 @@ static int i2c_powermac_master_xfer(str
return -EINVAL;
read = (msgs->flags & I2C_M_RD) != 0;
addrdir = (msgs->addr << 1) | read;
-   if (msgs->flags & I2C_M_REV_DIR_ADDR)
-   addrdir ^= 1;
 
rc = pmac_i2c_open(bus, 0);
if (rc)


-- 
Jean Delvare
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] i2c-powermac: Reject unsupported I2C transactions

2009-09-30 Thread Jean Delvare
The i2c-powermac driver doesn't support arbitrary multi-message I2C
transactions, only SMBus ones. Make it clear by returning an error if
a multi-message I2C transaction is attempted. This is better than only
processing the first message, because most callers won't recover from
the short transaction. Anyone wishing to issue multi-message
transactions should use the SMBus API instead of the raw I2C API.

Signed-off-by: Jean Delvare 
Cc: Benjamin Herrenschmidt 
Cc: Paul Mackerras 
---
 drivers/i2c/busses/i2c-powermac.c |6 ++
 1 file changed, 6 insertions(+)

--- linux-2.6.32-rc1.orig/drivers/i2c/busses/i2c-powermac.c 2009-06-10 
05:05:27.0 +0200
+++ linux-2.6.32-rc1/drivers/i2c/busses/i2c-powermac.c  2009-09-30 
20:29:42.0 +0200
@@ -146,6 +146,12 @@ static int i2c_powermac_master_xfer(   str
int read;
int addrdir;
 
+   if (num != 1) {
+   dev_err(&adap->dev,
+   "Multi-message I2C transactions not supported\n");
+   return -EOPNOTSUPP;
+   }
+
if (msgs->flags & I2C_M_TEN)
return -EINVAL;
read = (msgs->flags & I2C_M_RD) != 0;


-- 
Jean Delvare
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [2.6.31] ir-kbd-i2c oops.

2009-09-30 Thread Paweł Sikora
On Tuesday 29 September 2009 16:16:29 Jean Delvare wrote:
> On Wed, 16 Sep 2009 10:03:32 +0200, Paweł Sikora wrote:
> > On Wednesday 16 September 2009 08:57:01 Jean Delvare wrote:
> > > Hi Pawel,
> > >
> > > I think this would be fixed by the following patch:
> > > http://patchwork.kernel.org/patch/45707/
> >
> > still oopses. this time i've attached full dmesg.
> 
> Any news on this? Do you have a refined list of kernels which have the
> bug and kernels which do not?

afaics in the 2.6.2{7,8}, the remote sends some noises to pc.
effect: random characters on terminal and unusable login prompt.

now in the 2.6.31, the kernel module oopses during udev loading.
so i've renamed the .ko to prevent loading.

> Tried 2.6.32-rc1? Tried the v4l-dvb repository?

no.

> I am also skeptical about the +0x64/0x1a52, ir_input_init() is a rather
> small function and I fail to see how it could be 6738 bytes in binary size.

i've attached asm dump of ir-common.ko
i found the '41 c7 80 cc ...' code in dump at adress 0x83e.

ir-common.ko: file format elf64-x86-64


Disassembly of section .text:

 :
   0:   31 c0   xor%eax,%eax
   2:   ba 01 00 00 00  mov$0x1,%edx
   7:   eb 09   jmp12 
   9:   0f 1f 80 00 00 00 00nopl   0x0(%rax)
  10:   d1 ef   shr%edi
  12:   40 f6 c6 01 test   $0x1,%sil
  16:   74 0d   je 25 
  18:   89 c1   mov%eax,%ecx
  1a:   09 d1   or %edx,%ecx
  1c:   40 f6 c7 01 test   $0x1,%dil
  20:   0f 45 c1cmovne %ecx,%eax
  23:   01 d2   add%edx,%edx
  25:   d1 ee   shr%esi
  27:   75 e7   jne10 
  29:   f3 c3   repz retq 
  2b:   0f 1f 44 00 00  nopl   0x0(%rax,%rax,1)

0030 :
  30:   41 55   push   %r13
  32:   c1 e6 05shl$0x5,%esi
  35:   85 f6   test   %esi,%esi
  37:   41 54   push   %r12
  39:   55  push   %rbp
  3a:   53  push   %rbx
  3b:   89 cb   mov%ecx,%ebx
  3d:   7e 58   jle97 
  3f:   31 c0   xor%eax,%eax
  41:   45 31 c0xor%r8d,%r8d
  44:   41 bb 1f 00 00 00   mov$0x1f,%r11d
  4a:   41 ba 01 00 00 00   mov$0x1,%r10d
  50:   eb 12   jmp64 
  52:   66 0f 1f 44 00 00   nopw   0x0(%rax,%rax,1)
  58:   41 83 c0 01 add$0x1,%r8d
  5c:   83 c0 01add$0x1,%eax
  5f:   41 39 f0cmp%esi,%r8d
  62:   7d 33   jge97 
  64:   44 89 c1mov%r8d,%ecx
  67:   45 89 c1mov%r8d,%r9d
  6a:   44 89 ddmov%r11d,%ebp
  6d:   83 e1 1fand$0x1f,%ecx
  70:   41 c1 f9 05 sar$0x5,%r9d
  74:   45 89 d5mov%r10d,%r13d
  77:   29 cd   sub%ecx,%ebp
  79:   4d 63 c9movslq %r9d,%r9
  7c:   89 e9   mov%ebp,%ecx
  7e:   41 d3 e5shl%cl,%r13d
  81:   46 85 2c 8f test   %r13d,(%rdi,%r9,4)
  85:   75 d1   jne58 
  87:   83 f8 1ccmp$0x1c,%eax
  8a:   7f 1c   jg a8 
  8c:   41 83 c0 01 add$0x1,%r8d
  90:   31 c0   xor%eax,%eax
  92:   41 39 f0cmp%esi,%r8d
  95:   7c cd   jl 64 
  97:   b8 ff ff ff ff  mov$0x,%eax
  9c:   5b  pop%rbx
  9d:   5d  pop%rbp
  9e:   41 5c   pop%r12
  a0:   41 5d   pop%r13
  a2:   c3  retq   
  a3:   0f 1f 44 00 00  nopl   0x0(%rax,%rax,1)
  a8:   41 39 f0cmp%esi,%r8d
  ab:   7d ea   jge97 
  ad:   31 c0   xor%eax,%eax
  af:   41 bb 1f 00 00 00   mov$0x1f,%r11d
  b5:   41 ba 01 00 00 00   mov$0x1,%r10d
  bb:   eb 26   jmpe3 
  bd:   0f 1f 00nopl   (%rax)
  c0:   44 89 c1mov%r8d,%ecx
  c3:   45 89 c1mov%r8d,%r9d
  c6:   44 89 ddmov%r11d,%ebp
  c9:   83 e1 1fand$0x1f,%ecx
  cc:   41 c1 f9 05 sar$0x5,%r9d
  d0:   45 89 d5mov%r10d,%r13d
  d3:   29 cd   sub%ecx,%ebp
  d5:   4d 63 c9movslq %r9d,%r9
  d8:   89 e9   mov%ebp,%ecx
  da:   41 d3 e5shl%cl,%r13d
  dd:   46 85 2c 8f test   %r13d,(%rdi,%r9,4)
  e1:   75 0c   jneef 
  e3:   41 83 c0 01 add$0x1,%r8d
  e7:   83 c0 01add$0x1,%eax
  ea:   41 39 f0