diff options
| -rw-r--r-- | drivers/i2c/busses/i2c-designware.c | 47 |
1 files changed, 40 insertions, 7 deletions
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c index e6b1e6ece5d7..887aed6601fb 100644 --- a/drivers/i2c/busses/i2c-designware.c +++ b/drivers/i2c/busses/i2c-designware.c | |||
| @@ -123,9 +123,27 @@ | |||
| 123 | #define ABRT_SBYTE_ACKDET 7 | 123 | #define ABRT_SBYTE_ACKDET 7 |
| 124 | #define ABRT_SBYTE_NORSTRT 9 | 124 | #define ABRT_SBYTE_NORSTRT 9 |
| 125 | #define ABRT_10B_RD_NORSTRT 10 | 125 | #define ABRT_10B_RD_NORSTRT 10 |
| 126 | #define ARB_MASTER_DIS 11 | 126 | #define ABRT_MASTER_DIS 11 |
| 127 | #define ARB_LOST 12 | 127 | #define ARB_LOST 12 |
| 128 | 128 | ||
| 129 | #define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK) | ||
| 130 | #define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK) | ||
| 131 | #define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK) | ||
| 132 | #define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK) | ||
| 133 | #define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK) | ||
| 134 | #define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ) | ||
| 135 | #define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET) | ||
| 136 | #define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT) | ||
| 137 | #define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT) | ||
| 138 | #define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS) | ||
| 139 | #define DW_IC_TX_ARB_LOST (1UL << ARB_LOST) | ||
| 140 | |||
| 141 | #define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \ | ||
| 142 | DW_IC_TX_ABRT_10ADDR1_NOACK | \ | ||
| 143 | DW_IC_TX_ABRT_10ADDR2_NOACK | \ | ||
| 144 | DW_IC_TX_ABRT_TXDATA_NOACK | \ | ||
| 145 | DW_IC_TX_ABRT_GCALL_NOACK) | ||
| 146 | |||
| 129 | static char *abort_sources[] = { | 147 | static char *abort_sources[] = { |
| 130 | [ABRT_7B_ADDR_NOACK] = | 148 | [ABRT_7B_ADDR_NOACK] = |
| 131 | "slave address not acknowledged (7bit mode)", | 149 | "slave address not acknowledged (7bit mode)", |
| @@ -472,6 +490,24 @@ i2c_dw_read(struct dw_i2c_dev *dev) | |||
| 472 | } | 490 | } |
| 473 | } | 491 | } |
| 474 | 492 | ||
| 493 | static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) | ||
| 494 | { | ||
| 495 | unsigned long abort_source = dev->abort_source; | ||
| 496 | int i; | ||
| 497 | |||
| 498 | for_each_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) | ||
| 499 | dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]); | ||
| 500 | |||
| 501 | if (abort_source & DW_IC_TX_ARB_LOST) | ||
| 502 | return -EAGAIN; | ||
| 503 | else if (abort_source & DW_IC_TX_ABRT_NOACK) | ||
| 504 | return -EREMOTEIO; | ||
| 505 | else if (abort_source & DW_IC_TX_ABRT_GCALL_READ) | ||
| 506 | return -EINVAL; /* wrong msgs[] data */ | ||
| 507 | else | ||
| 508 | return -EIO; | ||
| 509 | } | ||
| 510 | |||
| 475 | /* | 511 | /* |
| 476 | * Prepare controller for a transaction and call i2c_dw_xfer_msg | 512 | * Prepare controller for a transaction and call i2c_dw_xfer_msg |
| 477 | */ | 513 | */ |
| @@ -493,6 +529,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | |||
| 493 | dev->msg_read_idx = 0; | 529 | dev->msg_read_idx = 0; |
| 494 | dev->msg_err = 0; | 530 | dev->msg_err = 0; |
| 495 | dev->status = STATUS_IDLE; | 531 | dev->status = STATUS_IDLE; |
| 532 | dev->abort_source = 0; | ||
| 496 | 533 | ||
| 497 | ret = i2c_dw_wait_bus_not_busy(dev); | 534 | ret = i2c_dw_wait_bus_not_busy(dev); |
| 498 | if (ret < 0) | 535 | if (ret < 0) |
| @@ -526,12 +563,8 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | |||
| 526 | 563 | ||
| 527 | /* We have an error */ | 564 | /* We have an error */ |
| 528 | if (dev->cmd_err == DW_IC_ERR_TX_ABRT) { | 565 | if (dev->cmd_err == DW_IC_ERR_TX_ABRT) { |
| 529 | unsigned long abort_source = dev->abort_source; | 566 | ret = i2c_dw_handle_tx_abort(dev); |
| 530 | int i; | 567 | goto done; |
| 531 | |||
| 532 | for_each_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) { | ||
| 533 | dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]); | ||
| 534 | } | ||
| 535 | } | 568 | } |
| 536 | ret = -EIO; | 569 | ret = -EIO; |
| 537 | 570 | ||
