Message ID | 20180719044258.11706-1-joel@jms.id.au |
---|---|
State | Accepted, archived |
Headers | show |
Series | [linux,dev-4.17] i2c: fsi: Sync with v12 upstream submission | expand |
On 07/18/2018 11:42 PM, Joel Stanley wrote: > This incorporates the changes made with the recent cycles of review on > the linux-i2c mailing list. > > Signed-off-by: Joel Stanley <joel@jms.id.au> > --- > Eddie, I've used your latest submission to update the openbmc tree. I > think it makes sense to get it into the tree for testing as soon as > possible. Yep, agreed. Patch looks correct, thanks! Reviewed-by: Eddie James <eajames@linux.vnet.ibm.com> > > The patch was created bit removing the i2c-fsi changes, applying your > series, and then squishing it all into one patch. > > drivers/i2c/busses/i2c-fsi.c | 202 ++++++++++++++++++++--------------- > 1 file changed, 113 insertions(+), 89 deletions(-) > > diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c > index ee219c7131a0..1e2be2219a60 100644 > --- a/drivers/i2c/busses/i2c-fsi.c > +++ b/drivers/i2c/busses/i2c-fsi.c > @@ -247,7 +247,7 @@ static int fsi_i2c_start(struct fsi_i2c_port *port, struct i2c_msg *msg, > if (stop || msg->flags & I2C_M_STOP) > cmd |= I2C_CMD_WITH_STOP; > > - cmd |= FIELD_PREP(I2C_CMD_ADDR, msg->addr >> 1); > + cmd |= FIELD_PREP(I2C_CMD_ADDR, msg->addr); > cmd |= FIELD_PREP(I2C_CMD_LEN, msg->len); > > return fsi_i2c_write_reg(i2c->fsi, I2C_FSI_CMD, &cmd); > @@ -326,72 +326,119 @@ static int fsi_i2c_read_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg, > return 0; > } > > -static int fsi_i2c_reset_bus(struct fsi_i2c_master *i2c) > +static int fsi_i2c_get_scl(struct i2c_adapter *adap) > { > - int i, rc; > - u32 mode, stat, ext, dummy = 0; > + u32 stat = 0; > + struct fsi_i2c_port *port = adap->algo_data; > + struct fsi_i2c_master *i2c = port->master; > > - rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); > - if (rc) > - return rc; > + fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); > > - mode |= I2C_MODE_DIAG; > - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); > - if (rc) > - return rc; > + return !!(stat & I2C_STAT_SCL_IN); > +} > > - for (i = 0; i < 9; i++) { > - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy); > - if (rc) > - return rc; > +static void fsi_i2c_set_scl(struct i2c_adapter *adap, int val) > +{ > + u32 dummy = 0; > + struct fsi_i2c_port *port = adap->algo_data; > + struct fsi_i2c_master *i2c = port->master; > > - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy); > - if (rc) > - return rc; > - } > + if (val) > + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy); > + else > + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy); > +} > > - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy); > - if (rc) > - return rc; > +static int fsi_i2c_get_sda(struct i2c_adapter *adap) > +{ > + u32 stat = 0; > + struct fsi_i2c_port *port = adap->algo_data; > + struct fsi_i2c_master *i2c = port->master; > > - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SDA, &dummy); > - if (rc) > - return rc; > + fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); > + > + return !!(stat & I2C_STAT_SDA_IN); > +} > + > +static void fsi_i2c_set_sda(struct i2c_adapter *adap, int val) > +{ > + u32 dummy = 0; > + struct fsi_i2c_port *port = adap->algo_data; > + struct fsi_i2c_master *i2c = port->master; > + > + if (val) > + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SDA, &dummy); > + else > + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SDA, &dummy); > +} > + > +static void fsi_i2c_prepare_recovery(struct i2c_adapter *adap) > +{ > + int rc; > + u32 mode; > + struct fsi_i2c_port *port = adap->algo_data; > + struct fsi_i2c_master *i2c = port->master; > > - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy); > + rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); > if (rc) > - return rc; > + return; > + > + mode |= I2C_MODE_DIAG; > + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); > +} > > - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SDA, &dummy); > +static void fsi_i2c_unprepare_recovery(struct i2c_adapter *adap) > +{ > + int rc; > + u32 mode; > + struct fsi_i2c_port *port = adap->algo_data; > + struct fsi_i2c_master *i2c = port->master; > + > + rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); > if (rc) > - return rc; > + return; > > mode &= ~I2C_MODE_DIAG; > - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); > + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); > +} > + > +static int fsi_i2c_reset_bus(struct fsi_i2c_master *i2c, > + struct fsi_i2c_port *port) > +{ > + int rc; > + u32 stat, dummy = 0; > + > + /* force bus reset, ignore errors */ > + i2c_recover_bus(&port->adapter); > + > + /* reset errors */ > + rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy); > if (rc) > return rc; > > + /* wait for command complete */ > + usleep_range(I2C_RESET_SLEEP_MIN_US, I2C_RESET_SLEEP_MAX_US); > + > rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); > if (rc) > return rc; > > - /* check for hardware fault */ > - if (!(stat & I2C_STAT_SCL_IN) || !(stat & I2C_STAT_SDA_IN)) { > - rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_ESTAT, &ext); > - if (rc) > - return rc; > + if (stat & I2C_STAT_CMD_COMP) > + return 0; > > - dev_err(&i2c->fsi->dev, "bus stuck status[%08X] ext[%08X]\n", > - stat, ext); > - } > + /* failed to get command complete; reset engine again */ > + rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy); > + if (rc) > + return rc; > > - return 0; > + /* re-init engine again */ > + return fsi_i2c_dev_init(i2c); > } > > -static int fsi_i2c_reset(struct fsi_i2c_master *i2c, u16 port) > +static int fsi_i2c_reset_engine(struct fsi_i2c_master *i2c, u16 port) > { > int rc; > - u32 mode, stat, dummy = 0; > + u32 mode, dummy = 0; > > /* reset engine */ > rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy); > @@ -422,34 +469,7 @@ static int fsi_i2c_reset(struct fsi_i2c_master *i2c, u16 port) > if (rc) > return rc; > > - /* force bus reset */ > - rc = fsi_i2c_reset_bus(i2c); > - if (rc) > - return rc; > - > - /* reset errors */ > - dummy = 0; > - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy); > - if (rc) > - return rc; > - > - /* wait for command complete */ > - usleep_range(I2C_RESET_SLEEP_MIN_US, I2C_RESET_SLEEP_MAX_US); > - > - rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); > - if (rc) > - return rc; > - > - if (stat & I2C_STAT_CMD_COMP) > - return rc; > - > - /* failed to get command complete; reset engine again */ > - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy); > - if (rc) > - return rc; > - > - /* re-init engine again */ > - return fsi_i2c_dev_init(i2c); > + return 0; > } > > static int fsi_i2c_abort(struct fsi_i2c_port *port, u32 status) > @@ -457,12 +477,25 @@ static int fsi_i2c_abort(struct fsi_i2c_port *port, u32 status) > int rc; > unsigned long start; > u32 cmd = I2C_CMD_WITH_STOP; > - struct fsi_device *fsi = port->master->fsi; > + u32 stat; > + struct fsi_i2c_master *i2c = port->master; > + struct fsi_device *fsi = i2c->fsi; > + > + rc = fsi_i2c_reset_engine(i2c, port->port); > + if (rc) > + return rc; > > - rc = fsi_i2c_reset(port->master, port->port); > + rc = fsi_i2c_read_reg(fsi, I2C_FSI_STAT, &stat); > if (rc) > return rc; > > + /* if sda is low, peform full bus reset */ > + if (!(stat & I2C_STAT_SDA_IN)) { > + rc = fsi_i2c_reset_bus(i2c, port); > + if (rc) > + return rc; > + } > + > /* skip final stop command for these errors */ > if (status & (I2C_STAT_PARITY | I2C_STAT_LOST_ARB | I2C_STAT_STOP_ERR)) > return 0; > @@ -607,26 +640,17 @@ static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, > static u32 fsi_i2c_functionality(struct i2c_adapter *adap) > { > return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING | > - I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL | > - I2C_FUNC_SMBUS_BLOCK_DATA; > -} > - > -static int fsi_i2c_recover_bus(struct i2c_adapter *adap) > -{ > - int rc; > - struct fsi_i2c_port *port = adap->algo_data; > - struct fsi_i2c_master *master = port->master; > - > - mutex_lock(&master->lock); > - > - rc = fsi_i2c_reset(master, port->port); > - > - mutex_unlock(&master->lock); > - return rc; > + I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; > } > > static struct i2c_bus_recovery_info fsi_i2c_bus_recovery_info = { > - .recover_bus = fsi_i2c_recover_bus, > + .recover_bus = i2c_generic_scl_recovery, > + .get_scl = fsi_i2c_get_scl, > + .set_scl = fsi_i2c_set_scl, > + .get_sda = fsi_i2c_get_sda, > + .set_sda = fsi_i2c_set_sda, > + .prepare_recovery = fsi_i2c_prepare_recovery, > + .unprepare_recovery = fsi_i2c_unprepare_recovery, > }; > > static const struct i2c_algorithm fsi_i2c_algorithm = { > @@ -697,7 +721,7 @@ static int fsi_i2c_remove(struct device *dev) > struct fsi_i2c_master *i2c = dev_get_drvdata(dev); > struct fsi_i2c_port *port, *tmp; > > - list_for_each_entry_safe(port,tmp, &i2c->ports, list) { > + list_for_each_entry_safe(port, tmp, &i2c->ports, list) { > list_del(&port->list); > i2c_del_adapter(&port->adapter); > kfree(port);
diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c index ee219c7131a0..1e2be2219a60 100644 --- a/drivers/i2c/busses/i2c-fsi.c +++ b/drivers/i2c/busses/i2c-fsi.c @@ -247,7 +247,7 @@ static int fsi_i2c_start(struct fsi_i2c_port *port, struct i2c_msg *msg, if (stop || msg->flags & I2C_M_STOP) cmd |= I2C_CMD_WITH_STOP; - cmd |= FIELD_PREP(I2C_CMD_ADDR, msg->addr >> 1); + cmd |= FIELD_PREP(I2C_CMD_ADDR, msg->addr); cmd |= FIELD_PREP(I2C_CMD_LEN, msg->len); return fsi_i2c_write_reg(i2c->fsi, I2C_FSI_CMD, &cmd); @@ -326,72 +326,119 @@ static int fsi_i2c_read_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg, return 0; } -static int fsi_i2c_reset_bus(struct fsi_i2c_master *i2c) +static int fsi_i2c_get_scl(struct i2c_adapter *adap) { - int i, rc; - u32 mode, stat, ext, dummy = 0; + u32 stat = 0; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *i2c = port->master; - rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); - if (rc) - return rc; + fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); - mode |= I2C_MODE_DIAG; - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); - if (rc) - return rc; + return !!(stat & I2C_STAT_SCL_IN); +} - for (i = 0; i < 9; i++) { - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy); - if (rc) - return rc; +static void fsi_i2c_set_scl(struct i2c_adapter *adap, int val) +{ + u32 dummy = 0; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *i2c = port->master; - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy); - if (rc) - return rc; - } + if (val) + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy); + else + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy); +} - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy); - if (rc) - return rc; +static int fsi_i2c_get_sda(struct i2c_adapter *adap) +{ + u32 stat = 0; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *i2c = port->master; - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SDA, &dummy); - if (rc) - return rc; + fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); + + return !!(stat & I2C_STAT_SDA_IN); +} + +static void fsi_i2c_set_sda(struct i2c_adapter *adap, int val) +{ + u32 dummy = 0; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *i2c = port->master; + + if (val) + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SDA, &dummy); + else + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SDA, &dummy); +} + +static void fsi_i2c_prepare_recovery(struct i2c_adapter *adap) +{ + int rc; + u32 mode; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *i2c = port->master; - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy); + rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); if (rc) - return rc; + return; + + mode |= I2C_MODE_DIAG; + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); +} - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SDA, &dummy); +static void fsi_i2c_unprepare_recovery(struct i2c_adapter *adap) +{ + int rc; + u32 mode; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *i2c = port->master; + + rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); if (rc) - return rc; + return; mode &= ~I2C_MODE_DIAG; - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); +} + +static int fsi_i2c_reset_bus(struct fsi_i2c_master *i2c, + struct fsi_i2c_port *port) +{ + int rc; + u32 stat, dummy = 0; + + /* force bus reset, ignore errors */ + i2c_recover_bus(&port->adapter); + + /* reset errors */ + rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy); if (rc) return rc; + /* wait for command complete */ + usleep_range(I2C_RESET_SLEEP_MIN_US, I2C_RESET_SLEEP_MAX_US); + rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); if (rc) return rc; - /* check for hardware fault */ - if (!(stat & I2C_STAT_SCL_IN) || !(stat & I2C_STAT_SDA_IN)) { - rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_ESTAT, &ext); - if (rc) - return rc; + if (stat & I2C_STAT_CMD_COMP) + return 0; - dev_err(&i2c->fsi->dev, "bus stuck status[%08X] ext[%08X]\n", - stat, ext); - } + /* failed to get command complete; reset engine again */ + rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy); + if (rc) + return rc; - return 0; + /* re-init engine again */ + return fsi_i2c_dev_init(i2c); } -static int fsi_i2c_reset(struct fsi_i2c_master *i2c, u16 port) +static int fsi_i2c_reset_engine(struct fsi_i2c_master *i2c, u16 port) { int rc; - u32 mode, stat, dummy = 0; + u32 mode, dummy = 0; /* reset engine */ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy); @@ -422,34 +469,7 @@ static int fsi_i2c_reset(struct fsi_i2c_master *i2c, u16 port) if (rc) return rc; - /* force bus reset */ - rc = fsi_i2c_reset_bus(i2c); - if (rc) - return rc; - - /* reset errors */ - dummy = 0; - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy); - if (rc) - return rc; - - /* wait for command complete */ - usleep_range(I2C_RESET_SLEEP_MIN_US, I2C_RESET_SLEEP_MAX_US); - - rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); - if (rc) - return rc; - - if (stat & I2C_STAT_CMD_COMP) - return rc; - - /* failed to get command complete; reset engine again */ - rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy); - if (rc) - return rc; - - /* re-init engine again */ - return fsi_i2c_dev_init(i2c); + return 0; } static int fsi_i2c_abort(struct fsi_i2c_port *port, u32 status) @@ -457,12 +477,25 @@ static int fsi_i2c_abort(struct fsi_i2c_port *port, u32 status) int rc; unsigned long start; u32 cmd = I2C_CMD_WITH_STOP; - struct fsi_device *fsi = port->master->fsi; + u32 stat; + struct fsi_i2c_master *i2c = port->master; + struct fsi_device *fsi = i2c->fsi; + + rc = fsi_i2c_reset_engine(i2c, port->port); + if (rc) + return rc; - rc = fsi_i2c_reset(port->master, port->port); + rc = fsi_i2c_read_reg(fsi, I2C_FSI_STAT, &stat); if (rc) return rc; + /* if sda is low, peform full bus reset */ + if (!(stat & I2C_STAT_SDA_IN)) { + rc = fsi_i2c_reset_bus(i2c, port); + if (rc) + return rc; + } + /* skip final stop command for these errors */ if (status & (I2C_STAT_PARITY | I2C_STAT_LOST_ARB | I2C_STAT_STOP_ERR)) return 0; @@ -607,26 +640,17 @@ static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, static u32 fsi_i2c_functionality(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING | - I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL | - I2C_FUNC_SMBUS_BLOCK_DATA; -} - -static int fsi_i2c_recover_bus(struct i2c_adapter *adap) -{ - int rc; - struct fsi_i2c_port *port = adap->algo_data; - struct fsi_i2c_master *master = port->master; - - mutex_lock(&master->lock); - - rc = fsi_i2c_reset(master, port->port); - - mutex_unlock(&master->lock); - return rc; + I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; } static struct i2c_bus_recovery_info fsi_i2c_bus_recovery_info = { - .recover_bus = fsi_i2c_recover_bus, + .recover_bus = i2c_generic_scl_recovery, + .get_scl = fsi_i2c_get_scl, + .set_scl = fsi_i2c_set_scl, + .get_sda = fsi_i2c_get_sda, + .set_sda = fsi_i2c_set_sda, + .prepare_recovery = fsi_i2c_prepare_recovery, + .unprepare_recovery = fsi_i2c_unprepare_recovery, }; static const struct i2c_algorithm fsi_i2c_algorithm = { @@ -697,7 +721,7 @@ static int fsi_i2c_remove(struct device *dev) struct fsi_i2c_master *i2c = dev_get_drvdata(dev); struct fsi_i2c_port *port, *tmp; - list_for_each_entry_safe(port,tmp, &i2c->ports, list) { + list_for_each_entry_safe(port, tmp, &i2c->ports, list) { list_del(&port->list); i2c_del_adapter(&port->adapter); kfree(port);
This incorporates the changes made with the recent cycles of review on the linux-i2c mailing list. Signed-off-by: Joel Stanley <joel@jms.id.au> --- Eddie, I've used your latest submission to update the openbmc tree. I think it makes sense to get it into the tree for testing as soon as possible. The patch was created bit removing the i2c-fsi changes, applying your series, and then squishing it all into one patch. drivers/i2c/busses/i2c-fsi.c | 202 ++++++++++++++++++++--------------- 1 file changed, 113 insertions(+), 89 deletions(-)