From d9ebd04d3476634c29ce0feffbc982e1cb25ed80 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:27:55 +0530 Subject: i2c: omap: switch to devm_* API that helps deleting some boiler plate code and lets driver-core manage our resources for us. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 5d19a49803c1..2d9b03c94614 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -943,7 +943,7 @@ omap_i2c_probe(struct platform_device *pdev) { struct omap_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *mem, *irq, *ioarea; + struct resource *mem, *irq; struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; @@ -962,17 +962,16 @@ omap_i2c_probe(struct platform_device *pdev) return -ENODEV; } - ioarea = request_mem_region(mem->start, resource_size(mem), - pdev->name); - if (!ioarea) { - dev_err(&pdev->dev, "I2C region already claimed\n"); - return -EBUSY; + dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); + if (!dev) { + dev_err(&pdev->dev, "Menory allocation failed\n"); + return -ENOMEM; } - dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL); - if (!dev) { - r = -ENOMEM; - goto err_release_region; + dev->base = devm_request_and_ioremap(&pdev->dev, mem); + if (!dev->base) { + dev_err(&pdev->dev, "I2C region already claimed\n"); + return -ENOMEM; } match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); @@ -995,11 +994,6 @@ omap_i2c_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev->irq = irq->start; - dev->base = ioremap(mem->start, resource_size(mem)); - if (!dev->base) { - r = -ENOMEM; - goto err_free_mem; - } platform_set_drvdata(pdev, dev); init_completion(&dev->cmd_complete); @@ -1057,7 +1051,8 @@ omap_i2c_probe(struct platform_device *pdev) isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr : omap_i2c_isr; - r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev); + r = devm_request_irq(&pdev->dev, dev->irq, isr, IRQF_NO_SUSPEND, + pdev->name, dev); if (r) { dev_err(dev->dev, "failure requesting irq %i\n", dev->irq); @@ -1081,7 +1076,7 @@ omap_i2c_probe(struct platform_device *pdev) r = i2c_add_numbered_adapter(adap); if (r) { dev_err(dev->dev, "failure adding adapter\n"); - goto err_free_irq; + goto err_unuse_clocks; } of_i2c_register_devices(adap); @@ -1090,18 +1085,12 @@ omap_i2c_probe(struct platform_device *pdev) return 0; -err_free_irq: - free_irq(dev->irq, dev); err_unuse_clocks: omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(dev->dev); - iounmap(dev->base); pm_runtime_disable(&pdev->dev); err_free_mem: platform_set_drvdata(pdev, NULL); - kfree(dev); -err_release_region: - release_mem_region(mem->start, resource_size(mem)); return r; } @@ -1109,12 +1098,10 @@ err_release_region: static int __devexit omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); - struct resource *mem; int ret; platform_set_drvdata(pdev, NULL); - free_irq(dev->irq, dev); i2c_del_adapter(&dev->adapter); ret = pm_runtime_get_sync(&pdev->dev); if (IS_ERR_VALUE(ret)) @@ -1123,10 +1110,6 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev) omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - iounmap(dev->base); - kfree(dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, resource_size(mem)); return 0; } -- cgit v1.2.3 From baf3d7b7210c705bf8ca7afb03cd7f0b61d27058 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:27:56 +0530 Subject: i2c: omap: simplify num_bytes handling trivial patch, no functional changes If the fifo is disabled or fifo_size is 0 the num_bytes is set to 1. Else it is set to fifo_size or in case of a draining interrupt the remaining bytes in the buff stat. So the zero check is redundant and can be safely optimised. Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 2d9b03c94614..236cb38bb859 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -812,8 +812,7 @@ complete: OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F; } - while (num_bytes) { - num_bytes--; + while (num_bytes--) { w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); if (dev->buf_len) { *dev->buf++ = w; @@ -855,8 +854,7 @@ complete: OMAP_I2C_BUFSTAT_REG) & 0x3F; } - while (num_bytes) { - num_bytes--; + while (num_bytes--) { w = 0; if (dev->buf_len) { w = *dev->buf++; -- cgit v1.2.3 From 2049b5bcdd2172424c1ffc9b87d8f40020e9ebd6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:27:57 +0530 Subject: i2c: omap: decrease indentation level on data handling The patch intends to decrease the indentation level on the data handling by using the fact that else of if (dev->buf_len) is same as if (!dev->buf_len) if (dev->buf_len) { aaa; } else { bbb; break; } to if (!dev->buf_len) { bbb; break; } aaa; Hence no functional changes. Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 63 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 32 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 236cb38bb859..0dd647abb89d 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -813,22 +813,7 @@ complete: >> 8) & 0x3F; } while (num_bytes--) { - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - if (dev->buf_len) { - *dev->buf++ = w; - dev->buf_len--; - /* - * Data reg in 2430, omap3 and - * omap4 is 8 bit wide - */ - if (dev->flags & - OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; - } - } - } else { + if (!dev->buf_len) { if (stat & OMAP_I2C_STAT_RRDY) dev_err(dev->dev, "RRDY IRQ while no data" @@ -839,6 +824,21 @@ complete: " requested\n"); break; } + + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); + *dev->buf++ = w; + dev->buf_len--; + /* + * Data reg in 2430, omap3 and + * omap4 is 8 bit wide + */ + if (dev->flags & + OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } } omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); @@ -855,22 +855,7 @@ complete: & 0x3F; } while (num_bytes--) { - w = 0; - if (dev->buf_len) { - w = *dev->buf++; - dev->buf_len--; - /* - * Data reg in 2430, omap3 and - * omap4 is 8 bit wide - */ - if (dev->flags & - OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - w |= *dev->buf++ << 8; - dev->buf_len--; - } - } - } else { + if (!dev->buf_len) { if (stat & OMAP_I2C_STAT_XRDY) dev_err(dev->dev, "XRDY IRQ while no " @@ -882,6 +867,20 @@ complete: break; } + w = *dev->buf++; + dev->buf_len--; + /* + * Data reg in 2430, omap3 and + * omap4 is 8 bit wide + */ + if (dev->flags & + OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + w |= *dev->buf++ << 8; + dev->buf_len--; + } + } + if ((dev->errata & I2C_OMAP_ERRATA_I462) && errata_omap3_i462(dev, &stat, &err)) goto complete; -- cgit v1.2.3 From c55edb99028f4d2cd5ad4700447451725835a7bc Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:27:58 +0530 Subject: i2c: omap: add blank lines trivial patch to aid readability. No functional changes. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0dd647abb89d..30ea63c24b5d 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -786,6 +786,7 @@ complete: dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; } + /* * ProDB0017052: Clear ARDY bit twice */ @@ -798,6 +799,7 @@ complete: omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } + if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { u8 num_bytes = 1; @@ -844,6 +846,7 @@ complete: stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); continue; } + if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) { u8 num_bytes = 1; if (dev->fifo_size) { @@ -891,10 +894,12 @@ complete: stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); continue; } + if (stat & OMAP_I2C_STAT_ROVR) { dev_err(dev->dev, "Receive overrun\n"); dev->cmd_err |= OMAP_I2C_STAT_ROVR; } + if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); dev->cmd_err |= OMAP_I2C_STAT_XUDF; -- cgit v1.2.3 From 540a4790f7da0d3ca5ad9d726f198a5eb4db05ec Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:27:59 +0530 Subject: i2c: omap: simplify omap_i2c_ack_stat() stat & BIT(1) is the same as BIT(1), so let's simplify things a bit by removing "stat &" from all omap_i2c_ack_stat() calls. Code snippet (extremely simplified): if (stat & NACK) { ... omap_i2c_ack_stat(dev, stat & NACK); } if (stat & RDR) { ... omap_i2c_ack_stat(dev, stat & RDR); } and so on. The tricky place is only WRT errata handling, for example: if (*stat & (NACK | AL)) { omap_i2c_ack_stat(dev, *stat & (XRDY | XDR)); ... } but in this case, the errata says we must clear XRDY and XDR if that errata triggers, so if they just got enabled or not, it doesn't matter. Another tricky place is RDR | RRDY (likewise for XDR | XRDY): if (stat & (RDR | RRDY)) { ... omap_i2c_ack_stat(dev, stat & (RDR | RRDY)); } again here there will be no issues because those IRQs never fire simultaneously and one will only after after we have handled the previous, that's because the same FIFO is used anyway and we won't shift data into FIFO until we tell the IP "hey, I'm done with the FIFO, you can shift more data" Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar [Added the explaination from the discurssion to the commit logs] Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 30ea63c24b5d..f24eae9f7f1e 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -731,7 +731,7 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) { if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY | + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); return -ETIMEDOUT; } @@ -792,10 +792,11 @@ complete: */ if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, stat & - (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | - OMAP_I2C_STAT_ARDY)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + OMAP_I2C_STAT_RDR | + OMAP_I2C_STAT_XRDY | + OMAP_I2C_STAT_XDR | + OMAP_I2C_STAT_ARDY)); omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } @@ -842,8 +843,8 @@ complete: } } } - omap_i2c_ack_stat(dev, - stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + OMAP_I2C_STAT_RDR)); continue; } @@ -890,8 +891,8 @@ complete: omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } - omap_i2c_ack_stat(dev, - stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | + OMAP_I2C_STAT_XDR)); continue; } -- cgit v1.2.3 From 6d9939f651419a63e091105663821f9c7d3fec37 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:00 +0530 Subject: i2c: omap: split out [XR]DR and [XR]RDY While they do pretty much the same thing, there are a few peculiarities. Specially WRT erratas, it's best to split those out and re-factor the read/write loop to another function which both cases call. This last part will be done on another patch. While at that, also avoid an unncessary register read since dev->fifo_len will always contain the correct amount of data to be transferred. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 126 ++++++++++++++++++++++++++++++------------ 1 file changed, 92 insertions(+), 34 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index f24eae9f7f1e..815577b1c89f 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -801,36 +801,62 @@ complete: return IRQ_HANDLED; } - if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { + if (stat & OMAP_I2C_STAT_RDR) { u8 num_bytes = 1; + if (dev->fifo_size) + num_bytes = dev->buf_len; + + while (num_bytes--) { + if (!dev->buf_len) { + dev_err(dev->dev, + "RDR IRQ while no data" + " requested\n"); + break; + } + + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); + *dev->buf++ = w; + dev->buf_len--; + + /* + * Data reg in 2430, omap3 and + * omap4 is 8 bit wide + */ + if (dev->flags & + OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } + } + if (dev->errata & I2C_OMAP_ERRATA_I207) i2c_omap_errata_i207(dev, stat); - if (dev->fifo_size) { - if (stat & OMAP_I2C_STAT_RRDY) - num_bytes = dev->fifo_size; - else /* read RXSTAT on RDR interrupt */ - num_bytes = (omap_i2c_read_reg(dev, - OMAP_I2C_BUFSTAT_REG) - >> 8) & 0x3F; - } + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); + continue; + } + + if (stat & OMAP_I2C_STAT_RRDY) { + u8 num_bytes = 1; + + if (dev->fifo_size) + num_bytes = dev->fifo_size; + while (num_bytes--) { if (!dev->buf_len) { - if (stat & OMAP_I2C_STAT_RRDY) - dev_err(dev->dev, + dev_err(dev->dev, "RRDY IRQ while no data" - " requested\n"); - if (stat & OMAP_I2C_STAT_RDR) - dev_err(dev->dev, - "RDR IRQ while no data" - " requested\n"); + " requested\n"); break; } w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); *dev->buf++ = w; dev->buf_len--; + /* * Data reg in 2430, omap3 and * omap4 is 8 bit wide @@ -843,36 +869,68 @@ complete: } } } - omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | - OMAP_I2C_STAT_RDR)); + + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY); continue; } - if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) { + if (stat & OMAP_I2C_STAT_XDR) { u8 num_bytes = 1; - if (dev->fifo_size) { - if (stat & OMAP_I2C_STAT_XRDY) - num_bytes = dev->fifo_size; - else /* read TXSTAT on XDR interrupt */ - num_bytes = omap_i2c_read_reg(dev, - OMAP_I2C_BUFSTAT_REG) - & 0x3F; + + if (dev->fifo_size) + num_bytes = dev->buf_len; + + while (num_bytes--) { + if (!dev->buf_len) { + dev_err(dev->dev, + "XDR IRQ while no " + "data to send\n"); + break; + } + + w = *dev->buf++; + dev->buf_len--; + + /* + * Data reg in 2430, omap3 and + * omap4 is 8 bit wide + */ + if (dev->flags & + OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + w |= *dev->buf++ << 8; + dev->buf_len--; + } + } + + if ((dev->errata & I2C_OMAP_ERRATA_I462) && + errata_omap3_i462(dev, &stat, &err)) + goto complete; + + omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } + + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR); + continue; + } + + if (stat & OMAP_I2C_STAT_XRDY) { + u8 num_bytes = 1; + + if (dev->fifo_size) + num_bytes = dev->fifo_size; + while (num_bytes--) { if (!dev->buf_len) { - if (stat & OMAP_I2C_STAT_XRDY) - dev_err(dev->dev, + dev_err(dev->dev, "XRDY IRQ while no " "data to send\n"); - if (stat & OMAP_I2C_STAT_XDR) - dev_err(dev->dev, - "XDR IRQ while no " - "data to send\n"); break; } w = *dev->buf++; dev->buf_len--; + /* * Data reg in 2430, omap3 and * omap4 is 8 bit wide @@ -891,8 +949,8 @@ complete: omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } - omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | - OMAP_I2C_STAT_XDR)); + + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY); continue; } -- cgit v1.2.3 From 4151e74177b68c40079d8fe98f2fda4b9792a998 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:01 +0530 Subject: i2c: omap: improve i462 errata handling Make it not depend on ISR's local variables in order to make it easier to re-factor the transmit data loop. Also since we are waiting for XUDF(Transmitter underflow) just before writing data lets not flag the underflow. This is anyways going to go once we write the data. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 815577b1c89f..fb5722186d95 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -725,27 +725,30 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id) * data to DATA_REG. Otherwise some data bytes can be lost while transferring * them from the memory to the I2C interface. */ -static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) +static int errata_omap3_i462(struct omap_i2c_dev *dev) { unsigned long timeout = 10000; + u16 stat; - while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) { - if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { + do { + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + if (stat & OMAP_I2C_STAT_XUDF) + break; + + if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - return -ETIMEDOUT; + return -EIO; } cpu_relax(); - *stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); - } + } while (--timeout); if (!timeout) { dev_err(dev->dev, "timeout waiting on XUDF bit\n"); return 0; } - *err |= OMAP_I2C_STAT_XUDF; return 0; } @@ -903,9 +906,16 @@ complete: } } - if ((dev->errata & I2C_OMAP_ERRATA_I462) && - errata_omap3_i462(dev, &stat, &err)) - goto complete; + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + stat = omap_i2c_read_reg(dev, + OMAP_I2C_STAT_REG); + + if (ret < 0) + goto complete; + } omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } @@ -943,9 +953,16 @@ complete: } } - if ((dev->errata & I2C_OMAP_ERRATA_I462) && - errata_omap3_i462(dev, &stat, &err)) - goto complete; + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + stat = omap_i2c_read_reg(dev, + OMAP_I2C_STAT_REG); + + if (ret < 0) + goto complete; + } omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } -- cgit v1.2.3 From 3312d25e1abdc41be8a75a1b2c3ccaa39a14ed99 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:02 +0530 Subject: i2c: omap: re-factor receive/transmit data loop re-factor the common parts to a separate function, so that code is easier to read and understand. No functional changes. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 204 +++++++++++++++++------------------------- 1 file changed, 82 insertions(+), 122 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index fb5722186d95..2c7d7cc30e95 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -752,12 +752,81 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev) return 0; } +static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, + bool is_rdr) +{ + u16 w; + + while (num_bytes--) { + if (!dev->buf_len) { + dev_err(dev->dev, "%s without data", + is_rdr ? "RDR" : "RRDY"); + break; + } + + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); + *dev->buf++ = w; + dev->buf_len--; + + /* + * Data reg in 2430, omap3 and + * omap4 is 8 bit wide + */ + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } + } +} + +static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, + bool is_xdr) +{ + u16 w; + + while (num_bytes--) { + if (!dev->buf_len) { + dev_err(dev->dev, "%s without data", + is_xdr ? "XDR" : "XRDY"); + break; + } + + w = *dev->buf++; + dev->buf_len--; + + /* + * Data reg in 2430, omap3 and + * omap4 is 8 bit wide + */ + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + w |= *dev->buf++ << 8; + dev->buf_len--; + } + } + + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + if (ret < 0) + return ret; + } + + omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); + } + + return 0; +} + static irqreturn_t omap_i2c_isr(int this_irq, void *dev_id) { struct omap_i2c_dev *dev = dev_id; u16 bits; - u16 stat, w; + u16 stat; int err, count = 0; if (pm_runtime_suspended(dev->dev)) @@ -810,30 +879,7 @@ complete: if (dev->fifo_size) num_bytes = dev->buf_len; - while (num_bytes--) { - if (!dev->buf_len) { - dev_err(dev->dev, - "RDR IRQ while no data" - " requested\n"); - break; - } - - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - *dev->buf++ = w; - dev->buf_len--; - - /* - * Data reg in 2430, omap3 and - * omap4 is 8 bit wide - */ - if (dev->flags & - OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; - } - } - } + omap_i2c_receive_data(dev, num_bytes, true); if (dev->errata & I2C_OMAP_ERRATA_I207) i2c_omap_errata_i207(dev, stat); @@ -848,77 +894,22 @@ complete: if (dev->fifo_size) num_bytes = dev->fifo_size; - while (num_bytes--) { - if (!dev->buf_len) { - dev_err(dev->dev, - "RRDY IRQ while no data" - " requested\n"); - break; - } - - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - *dev->buf++ = w; - dev->buf_len--; - - /* - * Data reg in 2430, omap3 and - * omap4 is 8 bit wide - */ - if (dev->flags & - OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; - } - } - } - + omap_i2c_receive_data(dev, num_bytes, false); omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY); continue; } if (stat & OMAP_I2C_STAT_XDR) { u8 num_bytes = 1; + int ret; if (dev->fifo_size) num_bytes = dev->buf_len; - while (num_bytes--) { - if (!dev->buf_len) { - dev_err(dev->dev, - "XDR IRQ while no " - "data to send\n"); - break; - } - - w = *dev->buf++; - dev->buf_len--; - - /* - * Data reg in 2430, omap3 and - * omap4 is 8 bit wide - */ - if (dev->flags & - OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - w |= *dev->buf++ << 8; - dev->buf_len--; - } - } - - if (dev->errata & I2C_OMAP_ERRATA_I462) { - int ret; - - ret = errata_omap3_i462(dev); - stat = omap_i2c_read_reg(dev, - OMAP_I2C_STAT_REG); - - if (ret < 0) - goto complete; - } - - omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); - } + ret = omap_i2c_transmit_data(dev, num_bytes, true); + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + if (ret < 0) + goto complete; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR); continue; @@ -926,46 +917,15 @@ complete: if (stat & OMAP_I2C_STAT_XRDY) { u8 num_bytes = 1; + int ret; if (dev->fifo_size) num_bytes = dev->fifo_size; - while (num_bytes--) { - if (!dev->buf_len) { - dev_err(dev->dev, - "XRDY IRQ while no " - "data to send\n"); - break; - } - - w = *dev->buf++; - dev->buf_len--; - - /* - * Data reg in 2430, omap3 and - * omap4 is 8 bit wide - */ - if (dev->flags & - OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - w |= *dev->buf++ << 8; - dev->buf_len--; - } - } - - if (dev->errata & I2C_OMAP_ERRATA_I462) { - int ret; - - ret = errata_omap3_i462(dev); - stat = omap_i2c_read_reg(dev, - OMAP_I2C_STAT_REG); - - if (ret < 0) - goto complete; - } - - omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); - } + ret = omap_i2c_transmit_data(dev, num_bytes, false); + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + if (ret < 0) + goto complete; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY); continue; -- cgit v1.2.3 From 66b9298878742f08cb6e79b7c7d5632d782fd1e1 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:03 +0530 Subject: i2c: omap: switch over to do {} while loop this will make sure that we execute at least once. No functional changes otherwise. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 2c7d7cc30e95..40451341c479 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -827,20 +827,28 @@ omap_i2c_isr(int this_irq, void *dev_id) struct omap_i2c_dev *dev = dev_id; u16 bits; u16 stat; - int err, count = 0; + int err = 0, count = 0; if (pm_runtime_suspended(dev->dev)) return IRQ_NONE; - bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) { + do { + bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + stat &= bits; + + if (!stat) { + /* my work here is done */ + return IRQ_HANDLED; + } + dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat); if (count++ == 100) { dev_warn(dev->dev, "Too much work in one IRQ\n"); - break; + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } - err = 0; complete: /* * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be @@ -940,7 +948,7 @@ complete: dev_err(dev->dev, "Transmit underflow\n"); dev->cmd_err |= OMAP_I2C_STAT_XUDF; } - } + } while (stat); return count ? IRQ_HANDLED : IRQ_NONE; } -- cgit v1.2.3 From 1d7afc95946487945cc7f5019b41255b72224b70 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:04 +0530 Subject: i2c: omap: ack IRQ in parts According to flow diagrams on OMAP TRMs, we should ACK the IRQ as they happen. Signed-off-by: Felipe Balbi [Ack the stat OMAP_I2C_STAT_AL in case of arbitration lost] Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 40451341c479..bac1f11cc64b 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -850,21 +850,19 @@ omap_i2c_isr(int this_irq, void *dev_id) } complete: - /* - * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be - * acked after the data operation is complete. - * Ref: TRM SWPU114Q Figure 18-31 - */ - omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat & - ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - - if (stat & OMAP_I2C_STAT_NACK) + if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; + } if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } /* @@ -941,12 +939,18 @@ complete: if (stat & OMAP_I2C_STAT_ROVR) { dev_err(dev->dev, "Receive overrun\n"); - dev->cmd_err |= OMAP_I2C_STAT_ROVR; + err |= OMAP_I2C_STAT_ROVR; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); - dev->cmd_err |= OMAP_I2C_STAT_XUDF; + err |= OMAP_I2C_STAT_XUDF; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } } while (stat); -- cgit v1.2.3 From ac79e4b24972c69debef90a5e16b145e59222388 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:05 +0530 Subject: i2c: omap: switch to platform_get_irq() that's a nice helper from drivers core which will give us the exact IRQ number, instead of a pointer to an IRQ resource. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index bac1f11cc64b..0da8169ca5b4 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -993,11 +993,12 @@ omap_i2c_probe(struct platform_device *pdev) { struct omap_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *mem, *irq; + struct resource *mem; struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; irq_handler_t isr; + int irq; int r; /* NOTE: driver uses the static register mapping */ @@ -1006,10 +1007,11 @@ omap_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no mem resource?\n"); return -ENODEV; } - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); - return -ENODEV; + return irq; } dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); @@ -1043,7 +1045,7 @@ omap_i2c_probe(struct platform_device *pdev) } dev->dev = &pdev->dev; - dev->irq = irq->start; + dev->irq = irq; platform_set_drvdata(pdev, dev); init_completion(&dev->cmd_complete); -- cgit v1.2.3 From 079d8af24b948261e1dae5d7df6b31b7bf205cb4 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:06 +0530 Subject: i2c: omap: bus: add a receiver flag that way we can ignore TX IRQs while in receiver mode and ignore RX IRQs while in transmitter mode. Signed-off-by: Felipe Balbi [Remove unnecessary braces] Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0da8169ca5b4..3be147ab4eb9 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -199,6 +199,7 @@ struct omap_i2c_dev { */ u8 rev; unsigned b_hw:1; /* bad h/w fixes */ + unsigned receiver:1; /* true when we're in receiver mode */ u16 iestate; /* Saved interrupt register */ u16 pscstate; u16 scllstate; @@ -492,6 +493,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; + dev->receiver = !!(msg->flags & I2C_M_RD); w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -837,6 +839,12 @@ omap_i2c_isr(int this_irq, void *dev_id) stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); stat &= bits; + /* If we're in receiver mode, ignore XDR/XRDY */ + if (dev->receiver) + stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY); + else + stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY); + if (!stat) { /* my work here is done */ return IRQ_HANDLED; -- cgit v1.2.3 From 3ff4443f888207359a561db60a9cb96aa136b8f3 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:07 +0530 Subject: i2c: omap: simplify errata check omap_i2c_dev is allocated with kzalloc(), so we need not initialize b_hw to zero. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 3be147ab4eb9..7918e48c7fd3 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1095,9 +1095,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev >= OMAP_I2C_REV_ON_3630_4430) - dev->b_hw = 0; /* Disable hardware fixes */ - else + if (dev->rev < OMAP_I2C_REV_ON_3630_4430) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ -- cgit v1.2.3 From 6a85ced2cf299b916c04499b2c3d7b353cc2101f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:08 +0530 Subject: i2c: omap: always return IRQ_HANDLED Always return IRQ_HANDLED otherwise we could get our IRQ line disabled due to many spurious IRQs. Signed-off-by: Felipe Balbi [Trivial changes to commitlogs] Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 7918e48c7fd3..96fd528e888a 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -962,7 +962,7 @@ complete: } } while (stat); - return count ? IRQ_HANDLED : IRQ_NONE; + return IRQ_HANDLED; } static const struct i2c_algorithm omap_i2c_algo = { -- cgit v1.2.3 From 4a7ec4eda58269a507501f240955d99312fdfd5f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:09 +0530 Subject: i2c: omap: simplify IRQ exit path instead of having multiple return points, use a goto statement to make that clearer. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 96fd528e888a..4af123fab63c 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -853,24 +853,21 @@ omap_i2c_isr(int this_irq, void *dev_id) dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat); if (count++ == 100) { dev_warn(dev->dev, "Too much work in one IRQ\n"); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } complete: if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } /* @@ -883,8 +880,7 @@ complete: OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_ARDY)); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } if (stat & OMAP_I2C_STAT_RDR) { @@ -949,19 +945,19 @@ complete: dev_err(dev->dev, "Receive overrun\n"); err |= OMAP_I2C_STAT_ROVR; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); err |= OMAP_I2C_STAT_XUDF; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } } while (stat); +out: + omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } -- cgit v1.2.3 From dd74548ddece4b9d68e5528287a272fa552c81d0 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:10 +0530 Subject: i2c: omap: resize fifos before each message This patch will try to avoid the usage of draining feature by reconfiguring the FIFO the start condition of each message based on the message's size. By doing that, we will be better utilizing the FIFO when doing big transfers. While at that also drop the now unneeded check for dev->buf_len as we always know the amount of data to be transmitted. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 83 ++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 32 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 4af123fab63c..f33bc5a55074 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -193,6 +193,7 @@ struct omap_i2c_dev { u8 *regs; size_t buf_len; struct i2c_adapter adapter; + u8 threshold; u8 fifo_size; /* use as flag and value * fifo_size==0 implies no fifo * if set, should be trsh+1 @@ -418,13 +419,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); - if (dev->fifo_size) { - /* Note: setup required fifo size - 1. RTRSH and XTRSH */ - buf = (dev->fifo_size - 1) << 8 | OMAP_I2C_BUF_RXFIF_CLR | - (dev->fifo_size - 1) | OMAP_I2C_BUF_TXFIF_CLR; - omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); - } - /* Take the I2C module out of reset: */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); @@ -462,6 +456,45 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) return 0; } +static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) +{ + u16 buf; + + if (dev->flags & OMAP_I2C_FLAG_NO_FIFO) + return; + + /* + * Set up notification threshold based on message size. We're doing + * this to try and avoid draining feature as much as possible. Whenever + * we have big messages to transfer (bigger than our total fifo size) + * then we might use draining feature to transfer the remaining bytes. + */ + + dev->threshold = clamp(size, (u8) 1, dev->fifo_size); + + buf = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG); + + if (is_rx) { + /* Clear RX Threshold */ + buf &= ~(0x3f << 8); + buf |= ((dev->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR; + } else { + /* Clear TX Threshold */ + buf &= ~0x3f; + buf |= (dev->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR; + } + + omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); + + if (dev->rev < OMAP_I2C_REV_ON_3630_4430) + dev->b_hw = 1; /* Enable hardware fixes */ + + /* calculate wakeup latency constraint for MPU */ + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (1000000 * dev->threshold) / + (1000 * dev->speed / 8); +} + /* * Low level master read/write transaction. */ @@ -478,6 +511,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, if (msg->len == 0) return -EINVAL; + dev->receiver = !!(msg->flags & I2C_M_RD); + omap_i2c_resize_fifo(dev, msg->len, dev->receiver); + omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr); /* REVISIT: Could the STB bit of I2C_CON be used with probing? */ @@ -493,7 +529,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; - dev->receiver = !!(msg->flags & I2C_M_RD); w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -760,12 +795,6 @@ static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, u16 w; while (num_bytes--) { - if (!dev->buf_len) { - dev_err(dev->dev, "%s without data", - is_rdr ? "RDR" : "RRDY"); - break; - } - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); *dev->buf++ = w; dev->buf_len--; @@ -775,10 +804,8 @@ static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, * omap4 is 8 bit wide */ if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; - } + *dev->buf++ = w >> 8; + dev->buf_len--; } } } @@ -789,12 +816,6 @@ static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, u16 w; while (num_bytes--) { - if (!dev->buf_len) { - dev_err(dev->dev, "%s without data", - is_xdr ? "XDR" : "XRDY"); - break; - } - w = *dev->buf++; dev->buf_len--; @@ -803,10 +824,8 @@ static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, * omap4 is 8 bit wide */ if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - w |= *dev->buf++ << 8; - dev->buf_len--; - } + w |= *dev->buf++ << 8; + dev->buf_len--; } if (dev->errata & I2C_OMAP_ERRATA_I462) { @@ -901,8 +920,8 @@ complete: if (stat & OMAP_I2C_STAT_RRDY) { u8 num_bytes = 1; - if (dev->fifo_size) - num_bytes = dev->fifo_size; + if (dev->threshold) + num_bytes = dev->threshold; omap_i2c_receive_data(dev, num_bytes, false); omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY); @@ -929,8 +948,8 @@ complete: u8 num_bytes = 1; int ret; - if (dev->fifo_size) - num_bytes = dev->fifo_size; + if (dev->threshold) + num_bytes = dev->threshold; ret = omap_i2c_transmit_data(dev, num_bytes, false); stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); -- cgit v1.2.3 From b07be0f3b9e1bed6cbd29117d7f0519d114fbd82 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:11 +0530 Subject: i2c: omap: get rid of the "complete" label we can ack stat and complete the command from the errata handling itself. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index f33bc5a55074..5d4bad44d370 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -775,6 +775,17 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev) if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); + if (stat & OMAP_I2C_STAT_NACK) { + dev->cmd_err |= OMAP_I2C_STAT_NACK; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + } + + if (stat & OMAP_I2C_STAT_AL) { + dev_err(dev->dev, "Arbitration lost\n"); + dev->cmd_err |= OMAP_I2C_STAT_AL; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + } + return -EIO; } @@ -875,7 +886,6 @@ omap_i2c_isr(int this_irq, void *dev_id) goto out; } -complete: if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); @@ -938,7 +948,7 @@ complete: ret = omap_i2c_transmit_data(dev, num_bytes, true); stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); if (ret < 0) - goto complete; + goto out; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR); continue; @@ -954,7 +964,7 @@ complete: ret = omap_i2c_transmit_data(dev, num_bytes, false); stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); if (ret < 0) - goto complete; + goto out; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY); continue; -- cgit v1.2.3 From d741d0c792bda4761fd3f0089e7b0d34e99acbff Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Wed, 12 Sep 2012 16:28:12 +0530 Subject: i2c: omap: remove redundant status read Currently omap_i2c_ack_stat doesn't use the stat variable. After the read of the I2C_STAT_REG it is not used. Remove the redundant read of the status register. Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 5d4bad44d370..498a462c49b7 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -946,7 +946,6 @@ omap_i2c_isr(int this_irq, void *dev_id) num_bytes = dev->buf_len; ret = omap_i2c_transmit_data(dev, num_bytes, true); - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); if (ret < 0) goto out; @@ -962,7 +961,6 @@ omap_i2c_isr(int this_irq, void *dev_id) num_bytes = dev->threshold; ret = omap_i2c_transmit_data(dev, num_bytes, false); - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); if (ret < 0) goto out; -- cgit v1.2.3 From 3b2f8f82dad7d1f79cdc8fc05bd1c94baf109bde Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:13 +0530 Subject: i2c: omap: switch to threaded IRQ support for OMAP2, we can easily switch over to threaded IRQs on the I2C driver. This will allow us to spend less time in hardirq context. Signed-off-by: Felipe Balbi [Trivial formating changes] Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 498a462c49b7..049331cebb7f 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -176,6 +176,7 @@ enum { #define I2C_OMAP_ERRATA_I462 (1 << 1) struct omap_i2c_dev { + spinlock_t lock; /* IRQ synchronization */ struct device *dev; void __iomem *base; /* virtual */ int irq; @@ -854,9 +855,30 @@ static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, } static irqreturn_t -omap_i2c_isr(int this_irq, void *dev_id) +omap_i2c_isr(int irq, void *dev_id) { struct omap_i2c_dev *dev = dev_id; + irqreturn_t ret = IRQ_HANDLED; + u16 mask; + u16 stat; + + spin_lock(&dev->lock); + mask = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + + if (stat & mask) + ret = IRQ_WAKE_THREAD; + + spin_unlock(&dev->lock); + + return ret; +} + +static irqreturn_t +omap_i2c_isr_thread(int this_irq, void *dev_id) +{ + struct omap_i2c_dev *dev = dev_id; + unsigned long flags; u16 bits; u16 stat; int err = 0, count = 0; @@ -864,6 +886,7 @@ omap_i2c_isr(int this_irq, void *dev_id) if (pm_runtime_suspended(dev->dev)) return IRQ_NONE; + spin_lock_irqsave(&dev->lock, flags); do { bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); @@ -877,6 +900,7 @@ omap_i2c_isr(int this_irq, void *dev_id) if (!stat) { /* my work here is done */ + spin_unlock_irqrestore(&dev->lock, flags); return IRQ_HANDLED; } @@ -985,6 +1009,8 @@ omap_i2c_isr(int this_irq, void *dev_id) out: omap_i2c_complete_cmd(dev, err); + spin_unlock_irqrestore(&dev->lock, flags); + return IRQ_HANDLED; } @@ -1028,7 +1054,6 @@ omap_i2c_probe(struct platform_device *pdev) struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; - irq_handler_t isr; int irq; int r; @@ -1078,6 +1103,8 @@ omap_i2c_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev->irq = irq; + spin_lock_init(&dev->lock); + platform_set_drvdata(pdev, dev); init_completion(&dev->cmd_complete); @@ -1130,10 +1157,14 @@ omap_i2c_probe(struct platform_device *pdev) /* reset ASAP, clearing any IRQs */ omap_i2c_init(dev); - isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr : - omap_i2c_isr; - r = devm_request_irq(&pdev->dev, dev->irq, isr, IRQF_NO_SUSPEND, - pdev->name, dev); + if (dev->rev < OMAP_I2C_OMAP1_REV_2) + r = devm_request_irq(&pdev->dev, dev->irq, omap_i2c_omap1_isr, + IRQF_NO_SUSPEND, pdev->name, dev); + else + r = devm_request_threaded_irq(&pdev->dev, dev->irq, + omap_i2c_isr, omap_i2c_isr_thread, + IRQF_NO_SUSPEND | IRQF_ONESHOT, + pdev->name, dev); if (r) { dev_err(dev->dev, "failure requesting irq %i\n", dev->irq); -- cgit v1.2.3 From e3a36b207f76364c281aeecaf14c1b22a7247278 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:14 +0530 Subject: i2c: omap: remove unnecessary pm_runtime_suspended check before starting any messages we call pm_runtime_get_sync() which will make sure that by the time we program a transfer and our IRQ handler gets called, we're not suspended anymore. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 049331cebb7f..6d38a570dc12 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -883,9 +883,6 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) u16 stat; int err = 0, count = 0; - if (pm_runtime_suspended(dev->dev)) - return IRQ_NONE; - spin_lock_irqsave(&dev->lock, flags); do { bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); -- cgit v1.2.3 From 6d8451d55a2a9467bc9647aafe8b6faee0251687 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:15 +0530 Subject: i2c: omap: switch over to autosuspend API this helps us reduce unnecessary pm transitions in case we have another i2c message starting soon. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 6d38a570dc12..122f517c5bcb 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -55,6 +55,9 @@ /* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) +/* timeout for pm runtime autosuspend */ +#define OMAP_I2C_PM_TIMEOUT 1000 /* ms */ + /* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */ enum { OMAP_I2C_REV_REG = 0, @@ -645,7 +648,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) omap_i2c_wait_for_bb(dev); out: - pm_runtime_put(dev->dev); + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); return r; } @@ -1113,6 +1117,9 @@ omap_i2c_probe(struct platform_device *pdev) dev->regs = (u8 *)reg_map_ip_v1; pm_runtime_enable(dev->dev); + pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(dev->dev); + r = pm_runtime_get_sync(dev->dev); if (IS_ERR_VALUE(r)) goto err_free_mem; @@ -1190,7 +1197,8 @@ omap_i2c_probe(struct platform_device *pdev) of_i2c_register_devices(adap); - pm_runtime_put(dev->dev); + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); return 0; -- cgit v1.2.3 From 0bdfe0cb803dce699ff337c35d8e97ac355fa417 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Sep 2012 16:28:16 +0530 Subject: i2c: omap: sanitize exit path move the goto out label one line down, so that it can be used when stat is read as zero. All other exits, can be done with a break statement. While at that, also break out as soon as we complete draining IRQ, since at that time we know we transferred everything there was to be transferred. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 122f517c5bcb..b149e3236da4 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -901,27 +901,26 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) if (!stat) { /* my work here is done */ - spin_unlock_irqrestore(&dev->lock, flags); - return IRQ_HANDLED; + goto out; } dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat); if (count++ == 100) { dev_warn(dev->dev, "Too much work in one IRQ\n"); - goto out; + break; } if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); - goto out; + break; } if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); - goto out; + break; } /* @@ -934,7 +933,7 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_ARDY)); - goto out; + break; } if (stat & OMAP_I2C_STAT_RDR) { @@ -949,7 +948,7 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) i2c_omap_errata_i207(dev, stat); omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); - continue; + break; } if (stat & OMAP_I2C_STAT_RRDY) { @@ -972,10 +971,10 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) ret = omap_i2c_transmit_data(dev, num_bytes, true); if (ret < 0) - goto out; + break; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR); - continue; + break; } if (stat & OMAP_I2C_STAT_XRDY) { @@ -987,7 +986,7 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) ret = omap_i2c_transmit_data(dev, num_bytes, false); if (ret < 0) - goto out; + break; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY); continue; @@ -997,19 +996,20 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) dev_err(dev->dev, "Receive overrun\n"); err |= OMAP_I2C_STAT_ROVR; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR); - goto out; + break; } if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); err |= OMAP_I2C_STAT_XUDF; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF); - goto out; + break; } } while (stat); -out: omap_i2c_complete_cmd(dev, err); + +out: spin_unlock_irqrestore(&dev->lock, flags); return IRQ_HANDLED; -- cgit v1.2.3 From c5d3cd6dc2dc106ca9fcc8cb6587754ee6cfc86e Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 31 Aug 2012 13:02:55 +0200 Subject: omap-i2c: fix incorrect log message when using a device tree When booting using a device tree, the adapter number is dynamically assigned after the log message is sent. This patch modifies the log message to get a correct adapter id. Signed-off-by: Florian Vaussard Tested-by: Benoit Cousson Acked-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index b149e3236da4..c78431a4970a 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1175,9 +1175,6 @@ omap_i2c_probe(struct platform_device *pdev) goto err_unuse_clocks; } - dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id, - dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); - adap = &dev->adapter; i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; @@ -1195,6 +1192,9 @@ omap_i2c_probe(struct platform_device *pdev) goto err_unuse_clocks; } + dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr, + dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); + of_i2c_register_devices(adap); pm_runtime_mark_last_busy(dev->dev); -- cgit v1.2.3 From 3db11feffc1ad2ab9dea27789e6b5b3032827adc Mon Sep 17 00:00:00 2001 From: Jean Pihet Date: Thu, 20 Sep 2012 18:08:03 +0200 Subject: ARM: OMAP: convert I2C driver to PM QoS for MPU latency constraints Convert the driver from the outdated omap_pm_set_max_mpu_wakeup_lat API to the new PM QoS API. Since the constraint is on the MPU subsystem, use the PM_QOS_CPU_DMA_LATENCY class of PM QoS. The resulting MPU constraints are used by cpuidle to decide the next power state of the MPU subsystem. The I2C device latency timing is derived from the FIFO size and the clock speed and so is applicable to all OMAP SoCs. Signed-off-by: Jean Pihet Acked-by: Shubhrajyoti D Acked-by: Tony Lindgren Acked-by: Kevin Hilman Signed-off-by: Wolfram Sang --- arch/arm/plat-omap/i2c.c | 21 --------------------- drivers/i2c/busses/i2c-omap.c | 32 ++++++++++++++++++-------------- include/linux/i2c-omap.h | 1 - 3 files changed, 18 insertions(+), 36 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index db071bc71c4d..dba8338f6cd7 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -34,7 +33,6 @@ #include #include #include -#include #include #define OMAP_I2C_SIZE 0x3f @@ -129,16 +127,6 @@ static inline int omap1_i2c_add_bus(int bus_id) #ifdef CONFIG_ARCH_OMAP2PLUS -/* - * XXX This function is a temporary compatibility wrapper - only - * needed until the I2C driver can be converted to call - * omap_pm_set_max_dev_wakeup_lat() and handle a return code. - */ -static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t) -{ - omap_pm_set_max_mpu_wakeup_lat(dev, t); -} - static inline int omap2_i2c_add_bus(int bus_id) { int l; @@ -170,15 +158,6 @@ static inline int omap2_i2c_add_bus(int bus_id) dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr; pdata->flags = dev_attr->flags; - /* - * When waiting for completion of a i2c transfer, we need to - * set a wake up latency constraint for the MPU. This is to - * ensure quick enough wakeup from idle, when transfer - * completes. - * Only omap3 has support for constraints - */ - if (cpu_is_omap34xx()) - pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat; pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(struct omap_i2c_bus_platform_data), NULL, 0, 0); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index c78431a4970a..b6c6b95d4a07 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,6 +43,7 @@ #include #include #include +#include /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -186,9 +187,8 @@ struct omap_i2c_dev { int reg_shift; /* bit shift for I2C register addresses */ struct completion cmd_complete; struct resource *ioarea; - u32 latency; /* maximum mpu wkup latency */ - void (*set_mpu_wkup_lat)(struct device *dev, - long latency); + u32 latency; /* maximum MPU wkup latency */ + struct pm_qos_request pm_qos_request; u32 speed; /* Speed of bus in kHz */ u32 dtrev; /* extra revision from DT */ u32 flags; @@ -494,9 +494,7 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - if (dev->set_mpu_wkup_lat != NULL) - dev->latency = (1000000 * dev->threshold) / - (1000 * dev->speed / 8); + dev->latency = (1000000 * dev->threshold) / (1000 * dev->speed / 8); } /* @@ -631,8 +629,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r < 0) goto out; - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, dev->latency); + /* + * When waiting for completion of a i2c transfer, we need to + * set a wake up latency constraint for the MPU. This is to + * ensure quick enough wakeup from idle, when transfer + * completes. + */ + if (dev->latency) + pm_qos_add_request(&dev->pm_qos_request, + PM_QOS_CPU_DMA_LATENCY, + dev->latency); for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); @@ -640,8 +646,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) break; } - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, -1); + if (dev->latency) + pm_qos_remove_request(&dev->pm_qos_request); if (r == 0) r = num; @@ -1097,7 +1103,6 @@ omap_i2c_probe(struct platform_device *pdev) } else if (pdata != NULL) { dev->speed = pdata->clkrate; dev->flags = pdata->flags; - dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; dev->dtrev = pdata->rev; } @@ -1153,9 +1158,8 @@ omap_i2c_probe(struct platform_device *pdev) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - if (dev->set_mpu_wkup_lat != NULL) - dev->latency = (1000000 * dev->fifo_size) / - (1000 * dev->speed / 8); + dev->latency = (1000000 * dev->fifo_size) / + (1000 * dev->speed / 8); } /* reset ASAP, clearing any IRQs */ diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index 92a0dc75bc74..df804ba73e0b 100644 --- a/include/linux/i2c-omap.h +++ b/include/linux/i2c-omap.h @@ -34,7 +34,6 @@ struct omap_i2c_bus_platform_data { u32 clkrate; u32 rev; u32 flags; - void (*set_mpu_wkup_lat)(struct device *dev, long set); }; #endif -- cgit v1.2.3