Messages in this thread | | | Date | Tue, 31 Oct 2023 13:36:18 +0100 | Subject | Re: [PATCH 1/2] [i2c-bcm2835] Fully clean up hardware state machine after a timeout | From | Stefan Wahren <> |
| |
[Forward to Dave and Phil]
Am 30.10.23 um 17:21 schrieb mike.isely@cobaltdigital.com: > From: Mike Isely <mike.isely@cobaltdigital.com> > > When the driver detects a timeout, there's no guarantee that the ISR > would have fired. Thus after a timeout, it's the foreground that > becomes responsible to reset the hardware state machine. The change > here just duplicates what is already implemented in the ISR. > > Signed-off-by: Mike Isely <isely@pobox.com> > --- > drivers/i2c/busses/i2c-bcm2835.c | 4 ++++ > 1 file changed, 4 insertions(+) > > diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c > index 8ce6d3f49551..96de875394e1 100644 > --- a/drivers/i2c/busses/i2c-bcm2835.c > +++ b/drivers/i2c/busses/i2c-bcm2835.c > @@ -345,42 +345,46 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) > static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], > int num) > { > struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap); > unsigned long time_left; > int i; > > for (i = 0; i < (num - 1); i++) > if (msgs[i].flags & I2C_M_RD) { > dev_warn_once(i2c_dev->dev, > "only one read message supported, has to be last\n"); > return -EOPNOTSUPP; > } > > i2c_dev->curr_msg = msgs; > i2c_dev->num_msgs = num; > reinit_completion(&i2c_dev->completion); > > bcm2835_i2c_start_transfer(i2c_dev); > > time_left = wait_for_completion_timeout(&i2c_dev->completion, > adap->timeout); > > bcm2835_i2c_finish_transfer(i2c_dev); > > if (!time_left) { > + /* Since we can't trust the ISR to have cleaned up, do the > + * full cleanup here... */ > bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, > BCM2835_I2C_C_CLEAR); > + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, BCM2835_I2C_S_CLKT | > + BCM2835_I2C_S_ERR | BCM2835_I2C_S_DONE); > dev_err(i2c_dev->dev, "i2c transfer timed out\n"); > return -ETIMEDOUT; > } > > if (!i2c_dev->msg_err) > return num; > > dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err); > > if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) > return -EREMOTEIO; > > return -EIO; > }
| |