[PATCH] i2c: mvtwsi: reset controller if stuck in "bus error" state

Stefan Roese sr at denx.de
Tue Aug 1 10:27:53 CEST 2023


On 7/26/23 00:13, Sam Edwards wrote:
> The MVTWSI controller can act either as a master or slave device. When
> acting as a master, the FSM is driven by the CPU. As a slave, the FSM is
> driven by the bus directly. In what is (apparently) a safety mechanism,
> if the bus transitions our FSM in any improper way, the FSM goes to a
> "bus error" state (0x00). I could find no documented or experimental way
> to get the FSM out of this state, except for a controller reset.
> 
> Since U-Boot only uses the MVTWSI controller as a bus master, this
> feature only gets in the way: we do not care what happened on the bus
> previously as long as the bus is ready for a new transaction. So, when
> trying to start a new transaction, check for this state and reset the
> controller if necessary.
> 
> Note that this should not be confused with the "deblocking" technique
> (used by the `i2c reset` command), which involves pulsing SCL repeatedly
> if SDA is found to be held low, in an attempt to force the bus back to
> an idle state. This patch only resets the controller in case something
> else had previously upset it, and (in principle) results in no
> externally-observable change in behavior.
> 
> Signed-off-by: Sam Edwards <CFSworks at gmail.com>

Reviewed-by: Stefan Roese <sr at denx.de>

Thanks,
Stefan

> ---
>   drivers/i2c/mvtwsi.c | 42 ++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 42 insertions(+)
> 
> 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 */
> @@ -525,6 +527,36 @@ static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed,
>   #endif
>   }
>   
> +/*
> + * __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.
>    *
> @@ -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);

Viele Grüße,
Stefan Roese

-- 
DENX Software Engineering GmbH,      Managing Director: Erika Unter
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr at denx.de


More information about the U-Boot mailing list