diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 83 |
1 files changed, 51 insertions, 32 deletions
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 { | |||
193 | u8 *regs; | 193 | u8 *regs; |
194 | size_t buf_len; | 194 | size_t buf_len; |
195 | struct i2c_adapter adapter; | 195 | struct i2c_adapter adapter; |
196 | u8 threshold; | ||
196 | u8 fifo_size; /* use as flag and value | 197 | u8 fifo_size; /* use as flag and value |
197 | * fifo_size==0 implies no fifo | 198 | * fifo_size==0 implies no fifo |
198 | * if set, should be trsh+1 | 199 | * if set, should be trsh+1 |
@@ -418,13 +419,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) | |||
418 | omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); | 419 | omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); |
419 | omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); | 420 | omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); |
420 | 421 | ||
421 | if (dev->fifo_size) { | ||
422 | /* Note: setup required fifo size - 1. RTRSH and XTRSH */ | ||
423 | buf = (dev->fifo_size - 1) << 8 | OMAP_I2C_BUF_RXFIF_CLR | | ||
424 | (dev->fifo_size - 1) | OMAP_I2C_BUF_TXFIF_CLR; | ||
425 | omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); | ||
426 | } | ||
427 | |||
428 | /* Take the I2C module out of reset: */ | 422 | /* Take the I2C module out of reset: */ |
429 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); | 423 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); |
430 | 424 | ||
@@ -462,6 +456,45 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) | |||
462 | return 0; | 456 | return 0; |
463 | } | 457 | } |
464 | 458 | ||
459 | static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) | ||
460 | { | ||
461 | u16 buf; | ||
462 | |||
463 | if (dev->flags & OMAP_I2C_FLAG_NO_FIFO) | ||
464 | return; | ||
465 | |||
466 | /* | ||
467 | * Set up notification threshold based on message size. We're doing | ||
468 | * this to try and avoid draining feature as much as possible. Whenever | ||
469 | * we have big messages to transfer (bigger than our total fifo size) | ||
470 | * then we might use draining feature to transfer the remaining bytes. | ||
471 | */ | ||
472 | |||
473 | dev->threshold = clamp(size, (u8) 1, dev->fifo_size); | ||
474 | |||
475 | buf = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG); | ||
476 | |||
477 | if (is_rx) { | ||
478 | /* Clear RX Threshold */ | ||
479 | buf &= ~(0x3f << 8); | ||
480 | buf |= ((dev->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR; | ||
481 | } else { | ||
482 | /* Clear TX Threshold */ | ||
483 | buf &= ~0x3f; | ||
484 | buf |= (dev->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR; | ||
485 | } | ||
486 | |||
487 | omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); | ||
488 | |||
489 | if (dev->rev < OMAP_I2C_REV_ON_3630_4430) | ||
490 | dev->b_hw = 1; /* Enable hardware fixes */ | ||
491 | |||
492 | /* calculate wakeup latency constraint for MPU */ | ||
493 | if (dev->set_mpu_wkup_lat != NULL) | ||
494 | dev->latency = (1000000 * dev->threshold) / | ||
495 | (1000 * dev->speed / 8); | ||
496 | } | ||
497 | |||
465 | /* | 498 | /* |
466 | * Low level master read/write transaction. | 499 | * Low level master read/write transaction. |
467 | */ | 500 | */ |
@@ -478,6 +511,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, | |||
478 | if (msg->len == 0) | 511 | if (msg->len == 0) |
479 | return -EINVAL; | 512 | return -EINVAL; |
480 | 513 | ||
514 | dev->receiver = !!(msg->flags & I2C_M_RD); | ||
515 | omap_i2c_resize_fifo(dev, msg->len, dev->receiver); | ||
516 | |||
481 | omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr); | 517 | omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr); |
482 | 518 | ||
483 | /* REVISIT: Could the STB bit of I2C_CON be used with probing? */ | 519 | /* 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, | |||
493 | 529 | ||
494 | INIT_COMPLETION(dev->cmd_complete); | 530 | INIT_COMPLETION(dev->cmd_complete); |
495 | dev->cmd_err = 0; | 531 | dev->cmd_err = 0; |
496 | dev->receiver = !!(msg->flags & I2C_M_RD); | ||
497 | 532 | ||
498 | w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; | 533 | w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; |
499 | 534 | ||
@@ -760,12 +795,6 @@ static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, | |||
760 | u16 w; | 795 | u16 w; |
761 | 796 | ||
762 | while (num_bytes--) { | 797 | while (num_bytes--) { |
763 | if (!dev->buf_len) { | ||
764 | dev_err(dev->dev, "%s without data", | ||
765 | is_rdr ? "RDR" : "RRDY"); | ||
766 | break; | ||
767 | } | ||
768 | |||
769 | w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); | 798 | w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); |
770 | *dev->buf++ = w; | 799 | *dev->buf++ = w; |
771 | dev->buf_len--; | 800 | dev->buf_len--; |
@@ -775,10 +804,8 @@ static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, | |||
775 | * omap4 is 8 bit wide | 804 | * omap4 is 8 bit wide |
776 | */ | 805 | */ |
777 | if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { | 806 | if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { |
778 | if (dev->buf_len) { | 807 | *dev->buf++ = w >> 8; |
779 | *dev->buf++ = w >> 8; | 808 | dev->buf_len--; |
780 | dev->buf_len--; | ||
781 | } | ||
782 | } | 809 | } |
783 | } | 810 | } |
784 | } | 811 | } |
@@ -789,12 +816,6 @@ static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, | |||
789 | u16 w; | 816 | u16 w; |
790 | 817 | ||
791 | while (num_bytes--) { | 818 | while (num_bytes--) { |
792 | if (!dev->buf_len) { | ||
793 | dev_err(dev->dev, "%s without data", | ||
794 | is_xdr ? "XDR" : "XRDY"); | ||
795 | break; | ||
796 | } | ||
797 | |||
798 | w = *dev->buf++; | 819 | w = *dev->buf++; |
799 | dev->buf_len--; | 820 | dev->buf_len--; |
800 | 821 | ||
@@ -803,10 +824,8 @@ static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, | |||
803 | * omap4 is 8 bit wide | 824 | * omap4 is 8 bit wide |
804 | */ | 825 | */ |
805 | if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { | 826 | if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { |
806 | if (dev->buf_len) { | 827 | w |= *dev->buf++ << 8; |
807 | w |= *dev->buf++ << 8; | 828 | dev->buf_len--; |
808 | dev->buf_len--; | ||
809 | } | ||
810 | } | 829 | } |
811 | 830 | ||
812 | if (dev->errata & I2C_OMAP_ERRATA_I462) { | 831 | if (dev->errata & I2C_OMAP_ERRATA_I462) { |
@@ -901,8 +920,8 @@ complete: | |||
901 | if (stat & OMAP_I2C_STAT_RRDY) { | 920 | if (stat & OMAP_I2C_STAT_RRDY) { |
902 | u8 num_bytes = 1; | 921 | u8 num_bytes = 1; |
903 | 922 | ||
904 | if (dev->fifo_size) | 923 | if (dev->threshold) |
905 | num_bytes = dev->fifo_size; | 924 | num_bytes = dev->threshold; |
906 | 925 | ||
907 | omap_i2c_receive_data(dev, num_bytes, false); | 926 | omap_i2c_receive_data(dev, num_bytes, false); |
908 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY); | 927 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY); |
@@ -929,8 +948,8 @@ complete: | |||
929 | u8 num_bytes = 1; | 948 | u8 num_bytes = 1; |
930 | int ret; | 949 | int ret; |
931 | 950 | ||
932 | if (dev->fifo_size) | 951 | if (dev->threshold) |
933 | num_bytes = dev->fifo_size; | 952 | num_bytes = dev->threshold; |
934 | 953 | ||
935 | ret = omap_i2c_transmit_data(dev, num_bytes, false); | 954 | ret = omap_i2c_transmit_data(dev, num_bytes, false); |
936 | stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); | 955 | stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); |