[PATCH linux dev-4.17] i2c: fsi: Sync with v12 upstream submission
Eddie James
eajames at linux.vnet.ibm.com
Fri Jul 20 00:04:10 AEST 2018
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 at 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 at 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);
More information about the openbmc
mailing list