diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-nomadik.c | 80 |
1 files changed, 48 insertions, 32 deletions
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index fa7b10639ce2..0c731ca69f15 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c | |||
@@ -525,6 +525,51 @@ static int write_i2c(struct nmk_i2c_dev *dev) | |||
525 | } | 525 | } |
526 | 526 | ||
527 | /** | 527 | /** |
528 | * nmk_i2c_xfer_one() - transmit a single I2C message | ||
529 | * @dev: device with a message encoded into it | ||
530 | * @flags: message flags | ||
531 | */ | ||
532 | static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) | ||
533 | { | ||
534 | int status; | ||
535 | |||
536 | if (flags & I2C_M_RD) { | ||
537 | /* read operation */ | ||
538 | dev->cli.operation = I2C_READ; | ||
539 | status = read_i2c(dev); | ||
540 | } else { | ||
541 | /* write operation */ | ||
542 | dev->cli.operation = I2C_WRITE; | ||
543 | status = write_i2c(dev); | ||
544 | } | ||
545 | |||
546 | if (status || (dev->result)) { | ||
547 | u32 i2c_sr; | ||
548 | u32 cause; | ||
549 | |||
550 | i2c_sr = readl(dev->virtbase + I2C_SR); | ||
551 | /* | ||
552 | * Check if the controller I2C operation status | ||
553 | * is set to ABORT(11b). | ||
554 | */ | ||
555 | if (((i2c_sr >> 2) & 0x3) == 0x3) { | ||
556 | /* get the abort cause */ | ||
557 | cause = (i2c_sr >> 4) & 0x7; | ||
558 | dev_err(&dev->pdev->dev, "%s\n", cause | ||
559 | >= ARRAY_SIZE(abort_causes) ? | ||
560 | "unknown reason" : | ||
561 | abort_causes[cause]); | ||
562 | } | ||
563 | |||
564 | (void) init_hw(dev); | ||
565 | |||
566 | status = status ? status : dev->result; | ||
567 | } | ||
568 | |||
569 | return status; | ||
570 | } | ||
571 | |||
572 | /** | ||
528 | * nmk_i2c_xfer() - I2C transfer function used by kernel framework | 573 | * nmk_i2c_xfer() - I2C transfer function used by kernel framework |
529 | * @i2c_adap: Adapter pointer to the controller | 574 | * @i2c_adap: Adapter pointer to the controller |
530 | * @msgs: Pointer to data to be written. | 575 | * @msgs: Pointer to data to be written. |
@@ -576,9 +621,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
576 | { | 621 | { |
577 | int status; | 622 | int status; |
578 | int i; | 623 | int i; |
579 | u32 cause; | ||
580 | struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); | 624 | struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); |
581 | u32 i2c_sr; | ||
582 | int j; | 625 | int j; |
583 | 626 | ||
584 | dev->busy = true; | 627 | dev->busy = true; |
@@ -593,6 +636,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
593 | if (status) | 636 | if (status) |
594 | goto out; | 637 | goto out; |
595 | 638 | ||
639 | /* Attempt three times to send the message queue */ | ||
596 | for (j = 0; j < 3; j++) { | 640 | for (j = 0; j < 3; j++) { |
597 | /* setup the i2c controller */ | 641 | /* setup the i2c controller */ |
598 | setup_i2c_controller(dev); | 642 | setup_i2c_controller(dev); |
@@ -611,37 +655,9 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
611 | dev->stop = (i < (num_msgs - 1)) ? 0 : 1; | 655 | dev->stop = (i < (num_msgs - 1)) ? 0 : 1; |
612 | dev->result = 0; | 656 | dev->result = 0; |
613 | 657 | ||
614 | if (msgs[i].flags & I2C_M_RD) { | 658 | status = nmk_i2c_xfer_one(dev, msgs[i].flags); |
615 | /* it is a read operation */ | 659 | if (status != 0) |
616 | dev->cli.operation = I2C_READ; | ||
617 | status = read_i2c(dev); | ||
618 | } else { | ||
619 | /* write operation */ | ||
620 | dev->cli.operation = I2C_WRITE; | ||
621 | status = write_i2c(dev); | ||
622 | } | ||
623 | if (status || (dev->result)) { | ||
624 | i2c_sr = readl(dev->virtbase + I2C_SR); | ||
625 | /* | ||
626 | * Check if the controller I2C operation status | ||
627 | * is set to ABORT(11b). | ||
628 | */ | ||
629 | if (((i2c_sr >> 2) & 0x3) == 0x3) { | ||
630 | /* get the abort cause */ | ||
631 | cause = (i2c_sr >> 4) | ||
632 | & 0x7; | ||
633 | dev_err(&dev->pdev->dev, "%s\n", cause | ||
634 | >= ARRAY_SIZE(abort_causes) ? | ||
635 | "unknown reason" : | ||
636 | abort_causes[cause]); | ||
637 | } | ||
638 | |||
639 | (void) init_hw(dev); | ||
640 | |||
641 | status = status ? status : dev->result; | ||
642 | |||
643 | break; | 660 | break; |
644 | } | ||
645 | } | 661 | } |
646 | if (status == 0) | 662 | if (status == 0) |
647 | break; | 663 | break; |