diff options
author | Tom Rini <trini@konsulko.com> | 2023-08-15 17:44:20 +0300 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2023-08-15 17:44:20 +0300 |
commit | ae9de10d5fbfad99384994d51f8748e23a5477d8 (patch) | |
tree | d32de20b74b9a5c3fa28e813a056d44989cb0aad | |
parent | 832148f675e427060be074c276956962fa9b5cb6 (diff) | |
parent | 250454c59b1b056d47cbb0c6d8d09a68416c9776 (diff) | |
download | u-boot-ae9de10d5fbfad99384994d51f8748e23a5477d8.tar.xz |
Merge tag 'i2c-updates-for-v2023.10-rc3' of https://source.denx.de/u-boot/custodians/u-boot-i2c
i2c updates for v2023.10-rc3
Bugfixes:
- mvtwsi driver fix stuck "bus error" state
from Sam
-rw-r--r-- | drivers/i2c/mvtwsi.c | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c index 93bbc6916e..14cdb0f663 100644 --- a/drivers/i2c/mvtwsi.c +++ b/drivers/i2c/mvtwsi.c @@ -142,6 +142,8 @@ enum mvtwsi_ctrl_register_fields { * code. */ enum mvstwsi_status_values { + /* Protocol violation on bus; this is a terminal state */ + MVTWSI_BUS_ERROR = 0x00, /* START condition transmitted */ MVTWSI_STATUS_START = 0x08, /* Repeated START condition transmitted */ @@ -526,6 +528,36 @@ static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed, } /* + * __twsi_i2c_reinit() - Reset and reinitialize the I2C controller. + * + * This function should be called to get the MVTWSI controller out of the + * "bus error" state. It saves and restores the baud and address registers. + * + * @twsi: The MVTWSI register structure to use. + * @tick: The duration of a clock cycle at the current I2C speed. + */ +static void __twsi_i2c_reinit(struct mvtwsi_registers *twsi, uint tick) +{ + uint baud; + uint slaveadd; + + /* Save baud, address registers */ + baud = readl(&twsi->baudrate); + slaveadd = readl(&twsi->slave_address); + + /* Reset controller */ + twsi_reset(twsi); + + /* Restore baud, address registers */ + writel(baud, &twsi->baudrate); + writel(slaveadd, &twsi->slave_address); + writel(0, &twsi->xtnd_slave_addr); + + /* Assert STOP, but don't care for the result */ + (void) twsi_stop(twsi, tick); +} + +/* * i2c_begin() - Start a I2C transaction. * * Begin a I2C transaction with a given expected start status and chip address. @@ -621,6 +653,11 @@ static int __twsi_i2c_read(struct mvtwsi_registers *twsi, uchar chip, int stop_status; int expected_start = MVTWSI_STATUS_START; + /* Check for (and clear) a bus error from a previous failed transaction + * or another master on the same bus */ + if (readl(&twsi->status) == MVTWSI_BUS_ERROR) + __twsi_i2c_reinit(twsi, tick); + if (alen > 0) { /* Begin i2c write to send the address bytes */ status = i2c_begin(twsi, expected_start, (chip << 1), tick); @@ -668,6 +705,11 @@ static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip, { int status, stop_status; + /* Check for (and clear) a bus error from a previous failed transaction + * or another master on the same bus */ + if (readl(&twsi->status) == MVTWSI_BUS_ERROR) + __twsi_i2c_reinit(twsi, tick); + /* Begin i2c write to send first the address bytes, then the * data bytes */ status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1), tick); |