diff options
author | Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com> | 2011-05-13 06:30:23 -0400 |
---|---|---|
committer | Ben Dooks <ben-linux@fluff.org> | 2011-05-24 19:20:43 -0400 |
commit | ebd10e0783d9fb92a147e60902e22c2d3f3ad69d (patch) | |
tree | a7e6524ae0618638bbff0b74f3abeac1e2d4817a /drivers/i2c/busses/i2c-nomadik.c | |
parent | b0e751a925260e5998a76dad41d4565ef26870db (diff) |
i2c-nomadik: add code to retry on timeout failure
It is seen that i2c-nomadik controller randomly stops generating the
interrupts leading to a i2c timeout. As a workaround to this problem,
add retries to the on going transfer on failure.
Signed-off-by: Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers/i2c/busses/i2c-nomadik.c')
-rw-r--r-- | drivers/i2c/busses/i2c-nomadik.c | 97 |
1 files changed, 49 insertions, 48 deletions
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 234e4a9070b8..b49ff25a2688 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c | |||
@@ -255,8 +255,6 @@ static int init_hw(struct nmk_i2c_dev *dev) | |||
255 | { | 255 | { |
256 | int stat; | 256 | int stat; |
257 | 257 | ||
258 | clk_enable(dev->clk); | ||
259 | |||
260 | stat = flush_i2c_fifo(dev); | 258 | stat = flush_i2c_fifo(dev); |
261 | if (stat) | 259 | if (stat) |
262 | goto exit; | 260 | goto exit; |
@@ -271,8 +269,6 @@ static int init_hw(struct nmk_i2c_dev *dev) | |||
271 | dev->cli.operation = I2C_NO_OPERATION; | 269 | dev->cli.operation = I2C_NO_OPERATION; |
272 | 270 | ||
273 | exit: | 271 | exit: |
274 | /* TODO: Why disable clocks after init hw? */ | ||
275 | clk_disable(dev->clk); | ||
276 | /* | 272 | /* |
277 | * TODO: What is this delay for? | 273 | * TODO: What is this delay for? |
278 | * Must be pretty pointless since the hw block | 274 | * Must be pretty pointless since the hw block |
@@ -572,6 +568,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
572 | u32 cause; | 568 | u32 cause; |
573 | struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); | 569 | struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); |
574 | u32 i2c_sr; | 570 | u32 i2c_sr; |
571 | int j; | ||
575 | 572 | ||
576 | dev->busy = true; | 573 | dev->busy = true; |
577 | 574 | ||
@@ -579,63 +576,67 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
579 | regulator_enable(dev->regulator); | 576 | regulator_enable(dev->regulator); |
580 | pm_runtime_get_sync(&dev->pdev->dev); | 577 | pm_runtime_get_sync(&dev->pdev->dev); |
581 | 578 | ||
579 | clk_enable(dev->clk); | ||
580 | |||
582 | status = init_hw(dev); | 581 | status = init_hw(dev); |
583 | if (status) | 582 | if (status) |
584 | goto out2; | 583 | goto out; |
585 | 584 | ||
586 | clk_enable(dev->clk); | 585 | for (j = 0; j < 3; j++) { |
587 | 586 | /* setup the i2c controller */ | |
588 | /* setup the i2c controller */ | 587 | setup_i2c_controller(dev); |
589 | setup_i2c_controller(dev); | ||
590 | 588 | ||
591 | for (i = 0; i < num_msgs; i++) { | 589 | for (i = 0; i < num_msgs; i++) { |
592 | if (unlikely(msgs[i].flags & I2C_M_TEN)) { | 590 | if (unlikely(msgs[i].flags & I2C_M_TEN)) { |
593 | dev_err(&dev->pdev->dev, "10 bit addressing" | 591 | dev_err(&dev->pdev->dev, "10 bit addressing" |
594 | "not supported\n"); | 592 | "not supported\n"); |
595 | 593 | ||
596 | status = -EINVAL; | 594 | status = -EINVAL; |
597 | goto out; | 595 | goto out; |
598 | } | 596 | } |
599 | dev->cli.slave_adr = msgs[i].addr; | 597 | dev->cli.slave_adr = msgs[i].addr; |
600 | dev->cli.buffer = msgs[i].buf; | 598 | dev->cli.buffer = msgs[i].buf; |
601 | dev->cli.count = msgs[i].len; | 599 | dev->cli.count = msgs[i].len; |
602 | dev->stop = (i < (num_msgs - 1)) ? 0 : 1; | 600 | dev->stop = (i < (num_msgs - 1)) ? 0 : 1; |
603 | dev->result = 0; | 601 | dev->result = 0; |
604 | 602 | ||
605 | if (msgs[i].flags & I2C_M_RD) { | 603 | if (msgs[i].flags & I2C_M_RD) { |
606 | /* it is a read operation */ | 604 | /* it is a read operation */ |
607 | dev->cli.operation = I2C_READ; | 605 | dev->cli.operation = I2C_READ; |
608 | status = read_i2c(dev); | 606 | status = read_i2c(dev); |
609 | } else { | 607 | } else { |
610 | /* write operation */ | 608 | /* write operation */ |
611 | dev->cli.operation = I2C_WRITE; | 609 | dev->cli.operation = I2C_WRITE; |
612 | status = write_i2c(dev); | 610 | status = write_i2c(dev); |
613 | } | 611 | } |
614 | if (status || (dev->result)) { | 612 | if (status || (dev->result)) { |
615 | i2c_sr = readl(dev->virtbase + I2C_SR); | 613 | i2c_sr = readl(dev->virtbase + I2C_SR); |
616 | /* | 614 | /* |
617 | * Check if the controller I2C operation status is set | 615 | * Check if the controller I2C operation status |
618 | * to ABORT(11b). | 616 | * is set to ABORT(11b). |
619 | */ | 617 | */ |
620 | if (((i2c_sr >> 2) & 0x3) == 0x3) { | 618 | if (((i2c_sr >> 2) & 0x3) == 0x3) { |
621 | /* get the abort cause */ | 619 | /* get the abort cause */ |
622 | cause = (i2c_sr >> 4) | 620 | cause = (i2c_sr >> 4) |
623 | & 0x7; | 621 | & 0x7; |
624 | dev_err(&dev->pdev->dev, "%s\n", cause >= | 622 | dev_err(&dev->pdev->dev, "%s\n", cause |
625 | ARRAY_SIZE(abort_causes) ? | 623 | >= ARRAY_SIZE(abort_causes) ? |
626 | "unknown reason" : | 624 | "unknown reason" : |
627 | abort_causes[cause]); | 625 | abort_causes[cause]); |
628 | } | 626 | } |
629 | 627 | ||
630 | status = status ? status : dev->result; | 628 | status = status ? status : dev->result; |
631 | goto out; | 629 | |
630 | break; | ||
631 | } | ||
632 | udelay(I2C_DELAY); | ||
632 | } | 633 | } |
633 | udelay(I2C_DELAY); | 634 | if (status == 0) |
635 | break; | ||
634 | } | 636 | } |
635 | 637 | ||
636 | out: | 638 | out: |
637 | clk_disable(dev->clk); | 639 | clk_disable(dev->clk); |
638 | out2: | ||
639 | pm_runtime_put_sync(&dev->pdev->dev); | 640 | pm_runtime_put_sync(&dev->pdev->dev); |
640 | if (dev->regulator) | 641 | if (dev->regulator) |
641 | regulator_disable(dev->regulator); | 642 | regulator_disable(dev->regulator); |