* [PATCH 1/4] i2c: imx: check busy bit when START/STOP
@ 2009-09-30 5:55 Richard Zhao
[not found] ` <1254290106-29272-1-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
0 siblings, 1 reply; 8+ messages in thread
From: Richard Zhao @ 2009-09-30 5:55 UTC (permalink / raw)
To: kernel-bIcnvbaLZ9MEGnE8C9+IrQ
Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, 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 <linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
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__, i);
--
1.6.0.4
^ permalink raw reply related [flat|nested] 8+ messages in thread[parent not found: <1254290106-29272-1-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* [PATCH 2/4] i2c: imx: only imx1 needs disable delay [not found] ` <1254290106-29272-1-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2009-09-30 5:55 ` Richard Zhao [not found] ` <1254290106-29272-2-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Richard Zhao @ 2009-09-30 5:55 UTC (permalink / raw) To: kernel-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Richard Zhao check cpu_is_mx1() when set disable_delay. Signed-off-by: Richard Zhao <linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 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 = (500000U * 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 = (500000U * 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 ^ permalink raw reply related [flat|nested] 8+ messages in thread
[parent not found: <1254290106-29272-2-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* [PATCH 3/4] i2c: imx: add macros and printk to make debug easy [not found] ` <1254290106-29272-2-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2009-09-30 5:55 ` Richard Zhao [not found] ` <1254290106-29272-3-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Richard Zhao @ 2009-09-30 5:55 UTC (permalink / raw) To: kernel-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, 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 <linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 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); dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n", i2c_imx->adapter.name); - dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); + dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); return 0; /* Return OK */ -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 8+ messages in thread
[parent not found: <1254290106-29272-3-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* [PATCH 4/4] i2c: imx: disable clock when it's possible to save power. [not found] ` <1254290106-29272-3-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2009-09-30 5:55 ` Richard Zhao 0 siblings, 0 replies; 8+ messages in thread From: Richard Zhao @ 2009-09-30 5:55 UTC (permalink / raw) To: kernel-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Richard Zhao Enable clock before START, disable it after STOP. Signed-off-by: Richard Zhao <linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 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 int disable_delay; + unsigned int ifdr; /* 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 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 1/4] i2c: imx: check busy bit when START/STOP @ 2009-10-01 1:13 Richard Zhao 2009-10-01 1:13 ` [PATCH 2/4] i2c: imx: only imx1 needs disable delay Richard Zhao 0 siblings, 1 reply; 8+ messages in thread From: Richard Zhao @ 2009-10-01 1:13 UTC (permalink / raw) To: kernel-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ, 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 <linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 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__, i); -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/4] i2c: imx: only imx1 needs disable delay @ 2009-10-01 1:13 ` Richard Zhao 2009-10-01 1:13 ` [PATCH 3/4] i2c: imx: add macros and printk to make debug easy Richard Zhao 0 siblings, 1 reply; 8+ messages in thread From: Richard Zhao @ 2009-10-01 1:13 UTC (permalink / raw) To: kernel-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ, Richard Zhao check cpu_is_mx1() when set disable_delay. Signed-off-by: Richard Zhao <linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 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 = (500000U * 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 = (500000U * 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 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/4] i2c: imx: add macros and printk to make debug easy @ 2009-10-01 1:13 ` Richard Zhao [not found] ` <1254359613-21210-3-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Richard Zhao @ 2009-10-01 1:13 UTC (permalink / raw) To: kernel-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ, 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 <linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 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); dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n", i2c_imx->adapter.name); - dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); + dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); return 0; /* Return OK */ -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 8+ messages in thread
[parent not found: <1254359613-21210-3-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* [PATCH 4/4] i2c: imx: disable clock when it's possible to save power. [not found] ` <1254359613-21210-3-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2009-10-01 1:13 ` Richard Zhao [not found] ` <1254359613-21210-4-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Richard Zhao @ 2009-10-01 1:13 UTC (permalink / raw) To: kernel-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ, Richard Zhao Enable clock before START, disable it after STOP. Signed-off-by: Richard Zhao <linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 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 int disable_delay; + unsigned int ifdr; /* 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 ^ permalink raw reply related [flat|nested] 8+ messages in thread
[parent not found: <1254359613-21210-4-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH 4/4] i2c: imx: disable clock when it's possible to save power. [not found] ` <1254359613-21210-4-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2009-10-01 7:34 ` Sascha Hauer [not found] ` <20091001073434.GY27039-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Sascha Hauer @ 2009-10-01 7:34 UTC (permalink / raw) To: Richard Zhao Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ On Thu, Oct 01, 2009 at 09:13:33AM +0800, Richard Zhao wrote: > Enable clock before START, disable it after STOP. The clk_diable/enable calls in suspend/resume should be removed also. Sascha > > Signed-off-by: Richard Zhao <linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > > 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 int disable_delay; > + unsigned int ifdr; /* 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 > > -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <20091001073434.GY27039-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>]
* Re: [PATCH 4/4] i2c: imx: disable clock when it's possible to save power. [not found] ` <20091001073434.GY27039-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org> @ 2009-10-01 7:56 ` Richard Zhao [not found] ` <4e090d470910010056n56bff9f4l1fec703c2dde9edf-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Richard Zhao @ 2009-10-01 7:56 UTC (permalink / raw) To: Sascha Hauer Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ On Thu, Oct 1, 2009 at 3:34 PM, Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org> wrote: > On Thu, Oct 01, 2009 at 09:13:33AM +0800, Richard Zhao wrote: >> Enable clock before START, disable it after STOP. > > The clk_diable/enable calls in suspend/resume should be removed also. > > Sascha > >> >> Signed-off-by: Richard Zhao <linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> >> >> 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 int disable_delay; >> + unsigned int ifdr; /* 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 >> >> > > -- > Pengutronix e.K. | | > Industrial Linux Solutions | http://www.pengutronix.de/ | > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | > Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | > I don't think we have any suspend/resume routine. And we won't need it any more. Thanks Richard ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <4e090d470910010056n56bff9f4l1fec703c2dde9edf-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 4/4] i2c: imx: disable clock when it's possible to save power. [not found] ` <4e090d470910010056n56bff9f4l1fec703c2dde9edf-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2009-10-01 8:00 ` Sascha Hauer 0 siblings, 0 replies; 8+ messages in thread From: Sascha Hauer @ 2009-10-01 8:00 UTC (permalink / raw) To: Richard Zhao Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ On Thu, Oct 01, 2009 at 03:56:29PM +0800, Richard Zhao wrote: > On Thu, Oct 1, 2009 at 3:34 PM, Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org> wrote: > > On Thu, Oct 01, 2009 at 09:13:33AM +0800, Richard Zhao wrote: > >> Enable clock before START, disable it after STOP. > > > > The clk_diable/enable calls in suspend/resume should be removed also. > > > > Sascha > > > >> > >> Signed-off-by: Richard Zhao <linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > >> > >> 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 int disable_delay; > >> + unsigned int ifdr; /* 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 > >> > >> > > > > -- > > Pengutronix e.K. | | > > Industrial Linux Solutions | http://www.pengutronix.de/ | > > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | > > Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | > > > > I don't think we have any suspend/resume routine. And we won't need it any more. Ups, my bad. I have it in my local tree and didn't realize it isn't upstream. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2009-10-01 8:00 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-09-30 5:55 [PATCH 1/4] i2c: imx: check busy bit when START/STOP Richard Zhao
[not found] ` <1254290106-29272-1-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2009-09-30 5:55 ` [PATCH 2/4] i2c: imx: only imx1 needs disable delay Richard Zhao
[not found] ` <1254290106-29272-2-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2009-09-30 5:55 ` [PATCH 3/4] i2c: imx: add macros and printk to make debug easy Richard Zhao
[not found] ` <1254290106-29272-3-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2009-09-30 5:55 ` [PATCH 4/4] i2c: imx: disable clock when it's possible to save power Richard Zhao
-- strict thread matches above, loose matches on Subject: below --
2009-10-01 1:13 [PATCH 1/4] i2c: imx: check busy bit when START/STOP Richard Zhao
2009-10-01 1:13 ` [PATCH 2/4] i2c: imx: only imx1 needs disable delay Richard Zhao
2009-10-01 1:13 ` [PATCH 3/4] i2c: imx: add macros and printk to make debug easy Richard Zhao
[not found] ` <1254359613-21210-3-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2009-10-01 1:13 ` [PATCH 4/4] i2c: imx: disable clock when it's possible to save power Richard Zhao
[not found] ` <1254359613-21210-4-git-send-email-linuxzsc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2009-10-01 7:34 ` Sascha Hauer
[not found] ` <20091001073434.GY27039-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-10-01 7:56 ` Richard Zhao
[not found] ` <4e090d470910010056n56bff9f4l1fec703c2dde9edf-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2009-10-01 8:00 ` Sascha Hauer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox