[PATCH 4/4] i2c: imx: disable clock when it's possible to save power.
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
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
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
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
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
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
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.
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