diff options
| -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); |
