drivers/i2c/dw_i2c: Adjust to handle 0-byte transfers
0-byte writes can be used as a way to probe/check presence of an i2c device, so adjust _dw_i2c_transfer() to immediately set the STOP bit and raise logger level for TX abort messages when the segment length is zero. Adjust dw_i2c_transfer() to allow zero-segment-length messages to be passed thru to _dw_i2c_transfer(). Tested as part of entire i2c-detect patch train. Change-Id: I518e849f4c476c264a1464886b1853af66c0b29d Signed-off-by: Matt DeVillier <matt.devillier@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/63561 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Martin L Roth <gaumless@tutanota.com> Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
This commit is contained in:
parent
1017a8fc5f
commit
57097130d5
|
@ -358,6 +358,7 @@ static enum cb_err _dw_i2c_transfer(unsigned int bus, const struct i2c_msg *segm
|
||||||
struct dw_i2c_regs *regs;
|
struct dw_i2c_regs *regs;
|
||||||
size_t byte;
|
size_t byte;
|
||||||
enum cb_err ret = CB_ERR;
|
enum cb_err ret = CB_ERR;
|
||||||
|
bool seg_zero_len = segments->len == 0;
|
||||||
|
|
||||||
regs = (struct dw_i2c_regs *)dw_i2c_base_address(bus);
|
regs = (struct dw_i2c_regs *)dw_i2c_base_address(bus);
|
||||||
if (!regs) {
|
if (!regs) {
|
||||||
|
@ -374,6 +375,10 @@ static enum cb_err _dw_i2c_transfer(unsigned int bus, const struct i2c_msg *segm
|
||||||
|
|
||||||
dw_i2c_enable(regs);
|
dw_i2c_enable(regs);
|
||||||
|
|
||||||
|
if (seg_zero_len)
|
||||||
|
/* stop immediately */
|
||||||
|
write32(®s->cmd_data, CMD_DATA_STOP);
|
||||||
|
|
||||||
/* Process each segment */
|
/* Process each segment */
|
||||||
while (count--) {
|
while (count--) {
|
||||||
if (CONFIG(DRIVERS_I2C_DESIGNWARE_DEBUG)) {
|
if (CONFIG(DRIVERS_I2C_DESIGNWARE_DEBUG)) {
|
||||||
|
@ -424,7 +429,7 @@ static enum cb_err _dw_i2c_transfer(unsigned int bus, const struct i2c_msg *segm
|
||||||
|
|
||||||
/* Check TX abort */
|
/* Check TX abort */
|
||||||
if (read32(®s->raw_intr_stat) & INTR_STAT_TX_ABORT) {
|
if (read32(®s->raw_intr_stat) & INTR_STAT_TX_ABORT) {
|
||||||
printk(BIOS_ERR, "I2C TX abort detected (%08x)\n",
|
printk(seg_zero_len ? BIOS_SPEW : BIOS_ERR, "I2C TX abort detected (%08x)\n",
|
||||||
read32(®s->tx_abort_source));
|
read32(®s->tx_abort_source));
|
||||||
/* clear INTR_STAT_TX_ABORT */
|
/* clear INTR_STAT_TX_ABORT */
|
||||||
read32(®s->clear_tx_abrt_intr);
|
read32(®s->clear_tx_abrt_intr);
|
||||||
|
@ -462,7 +467,7 @@ static enum cb_err dw_i2c_transfer(unsigned int bus, const struct i2c_msg *msg,
|
||||||
size_t start;
|
size_t start;
|
||||||
uint16_t addr;
|
uint16_t addr;
|
||||||
|
|
||||||
if (count == 0 || !msg)
|
if (!msg)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* Break up the transfers at the differing slave address boundary. */
|
/* Break up the transfers at the differing slave address boundary. */
|
||||||
|
|
Loading…
Reference in New Issue