[PATCH linux dev-4.17] i2c: fsi: Sync with v12 upstream submission
Joel Stanley
joel at jms.id.au
Thu Jul 19 14:42:58 AEST 2018
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.
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);
--
2.17.1
More information about the openbmc
mailing list