diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-omap.c')
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 54 |
1 files changed, 45 insertions, 9 deletions
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index fdd83277c8a8..827da0858136 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c | |||
@@ -672,9 +672,17 @@ omap_i2c_isr(int this_irq, void *dev_id) | |||
672 | break; | 672 | break; |
673 | } | 673 | } |
674 | 674 | ||
675 | omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat); | ||
676 | |||
677 | err = 0; | 675 | err = 0; |
676 | complete: | ||
677 | /* | ||
678 | * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be | ||
679 | * acked after the data operation is complete. | ||
680 | * Ref: TRM SWPU114Q Figure 18-31 | ||
681 | */ | ||
682 | omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat & | ||
683 | ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | | ||
684 | OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); | ||
685 | |||
678 | if (stat & OMAP_I2C_STAT_NACK) { | 686 | if (stat & OMAP_I2C_STAT_NACK) { |
679 | err |= OMAP_I2C_STAT_NACK; | 687 | err |= OMAP_I2C_STAT_NACK; |
680 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, | 688 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, |
@@ -685,16 +693,22 @@ omap_i2c_isr(int this_irq, void *dev_id) | |||
685 | err |= OMAP_I2C_STAT_AL; | 693 | err |= OMAP_I2C_STAT_AL; |
686 | } | 694 | } |
687 | if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | | 695 | if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | |
688 | OMAP_I2C_STAT_AL)) | 696 | OMAP_I2C_STAT_AL)) { |
697 | omap_i2c_ack_stat(dev, stat & | ||
698 | (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | | ||
699 | OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); | ||
689 | omap_i2c_complete_cmd(dev, err); | 700 | omap_i2c_complete_cmd(dev, err); |
701 | return IRQ_HANDLED; | ||
702 | } | ||
690 | if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { | 703 | if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { |
691 | u8 num_bytes = 1; | 704 | u8 num_bytes = 1; |
692 | if (dev->fifo_size) { | 705 | if (dev->fifo_size) { |
693 | if (stat & OMAP_I2C_STAT_RRDY) | 706 | if (stat & OMAP_I2C_STAT_RRDY) |
694 | num_bytes = dev->fifo_size; | 707 | num_bytes = dev->fifo_size; |
695 | else | 708 | else /* read RXSTAT on RDR interrupt */ |
696 | num_bytes = omap_i2c_read_reg(dev, | 709 | num_bytes = (omap_i2c_read_reg(dev, |
697 | OMAP_I2C_BUFSTAT_REG); | 710 | OMAP_I2C_BUFSTAT_REG) |
711 | >> 8) & 0x3F; | ||
698 | } | 712 | } |
699 | while (num_bytes) { | 713 | while (num_bytes) { |
700 | num_bytes--; | 714 | num_bytes--; |
@@ -731,9 +745,10 @@ omap_i2c_isr(int this_irq, void *dev_id) | |||
731 | if (dev->fifo_size) { | 745 | if (dev->fifo_size) { |
732 | if (stat & OMAP_I2C_STAT_XRDY) | 746 | if (stat & OMAP_I2C_STAT_XRDY) |
733 | num_bytes = dev->fifo_size; | 747 | num_bytes = dev->fifo_size; |
734 | else | 748 | else /* read TXSTAT on XDR interrupt */ |
735 | num_bytes = omap_i2c_read_reg(dev, | 749 | num_bytes = omap_i2c_read_reg(dev, |
736 | OMAP_I2C_BUFSTAT_REG); | 750 | OMAP_I2C_BUFSTAT_REG) |
751 | & 0x3F; | ||
737 | } | 752 | } |
738 | while (num_bytes) { | 753 | while (num_bytes) { |
739 | num_bytes--; | 754 | num_bytes--; |
@@ -760,6 +775,27 @@ omap_i2c_isr(int this_irq, void *dev_id) | |||
760 | "data to send\n"); | 775 | "data to send\n"); |
761 | break; | 776 | break; |
762 | } | 777 | } |
778 | |||
779 | /* | ||
780 | * OMAP3430 Errata 1.153: When an XRDY/XDR | ||
781 | * is hit, wait for XUDF before writing data | ||
782 | * to DATA_REG. Otherwise some data bytes can | ||
783 | * be lost while transferring them from the | ||
784 | * memory to the I2C interface. | ||
785 | */ | ||
786 | |||
787 | if (dev->rev <= OMAP_I2C_REV_ON_3430) { | ||
788 | while (!(stat & OMAP_I2C_STAT_XUDF)) { | ||
789 | if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { | ||
790 | omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); | ||
791 | err |= OMAP_I2C_STAT_XUDF; | ||
792 | goto complete; | ||
793 | } | ||
794 | cpu_relax(); | ||
795 | stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); | ||
796 | } | ||
797 | } | ||
798 | |||
763 | omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); | 799 | omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); |
764 | } | 800 | } |
765 | omap_i2c_ack_stat(dev, | 801 | omap_i2c_ack_stat(dev, |
@@ -879,7 +915,7 @@ omap_i2c_probe(struct platform_device *pdev) | |||
879 | i2c_set_adapdata(adap, dev); | 915 | i2c_set_adapdata(adap, dev); |
880 | adap->owner = THIS_MODULE; | 916 | adap->owner = THIS_MODULE; |
881 | adap->class = I2C_CLASS_HWMON; | 917 | adap->class = I2C_CLASS_HWMON; |
882 | strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); | 918 | strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); |
883 | adap->algo = &omap_i2c_algo; | 919 | adap->algo = &omap_i2c_algo; |
884 | adap->dev.parent = &pdev->dev; | 920 | adap->dev.parent = &pdev->dev; |
885 | 921 | ||