Commit 79970db2 authored by Wolfram Sang's avatar Wolfram Sang

i2c: mv64xxx: refactor message start to ensure proper initialization

Because the offload mechanism can fall back to a standard transfer,
having two seperate initialization states is unfortunate. Let's just
have one state which does things consistently. This fixes a bug where
some preparation was missing when the fallback happened. And it makes
the code much easier to follow. To implement this, we put the check
if offload is possible at the top of the offload setup function.
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
Tested-by: default avatarGregory CLEMENT <gregory.clement@free-electrons.com>
Cc: stable@vger.kernel.org # v3.12+
Fixes: 930ab3d4 (i2c: mv64xxx: Add I2C Transaction Generator support)
parent b28a960c
...@@ -97,7 +97,6 @@ enum { ...@@ -97,7 +97,6 @@ enum {
enum { enum {
MV64XXX_I2C_ACTION_INVALID, MV64XXX_I2C_ACTION_INVALID,
MV64XXX_I2C_ACTION_CONTINUE, MV64XXX_I2C_ACTION_CONTINUE,
MV64XXX_I2C_ACTION_OFFLOAD_SEND_START,
MV64XXX_I2C_ACTION_SEND_START, MV64XXX_I2C_ACTION_SEND_START,
MV64XXX_I2C_ACTION_SEND_RESTART, MV64XXX_I2C_ACTION_SEND_RESTART,
MV64XXX_I2C_ACTION_OFFLOAD_RESTART, MV64XXX_I2C_ACTION_OFFLOAD_RESTART,
...@@ -204,6 +203,9 @@ static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data) ...@@ -204,6 +203,9 @@ static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data)
unsigned long ctrl_reg; unsigned long ctrl_reg;
struct i2c_msg *msg = drv_data->msgs; struct i2c_msg *msg = drv_data->msgs;
if (!drv_data->offload_enabled)
return -EOPNOTSUPP;
drv_data->msg = msg; drv_data->msg = msg;
drv_data->byte_posn = 0; drv_data->byte_posn = 0;
drv_data->bytes_left = msg->len; drv_data->bytes_left = msg->len;
...@@ -433,8 +435,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) ...@@ -433,8 +435,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
drv_data->msgs++; drv_data->msgs++;
drv_data->num_msgs--; drv_data->num_msgs--;
if (!(drv_data->offload_enabled && if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
mv64xxx_i2c_offload_msg(drv_data))) {
drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START; drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
writel(drv_data->cntl_bits, writel(drv_data->cntl_bits,
drv_data->reg_base + drv_data->reg_offsets.control); drv_data->reg_base + drv_data->reg_offsets.control);
...@@ -458,15 +459,14 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) ...@@ -458,15 +459,14 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
drv_data->reg_base + drv_data->reg_offsets.control); drv_data->reg_base + drv_data->reg_offsets.control);
break; break;
case MV64XXX_I2C_ACTION_OFFLOAD_SEND_START:
if (!mv64xxx_i2c_offload_msg(drv_data))
break;
else
drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
/* FALLTHRU */
case MV64XXX_I2C_ACTION_SEND_START: case MV64XXX_I2C_ACTION_SEND_START:
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, /* Can we offload this msg ? */
drv_data->reg_base + drv_data->reg_offsets.control); if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
/* No, switch to standard path */
mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
drv_data->reg_base + drv_data->reg_offsets.control);
}
break; break;
case MV64XXX_I2C_ACTION_SEND_ADDR_1: case MV64XXX_I2C_ACTION_SEND_ADDR_1:
...@@ -625,15 +625,10 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg, ...@@ -625,15 +625,10 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&drv_data->lock, flags); spin_lock_irqsave(&drv_data->lock, flags);
if (drv_data->offload_enabled) {
drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_SEND_START;
drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
} else {
mv64xxx_i2c_prepare_for_io(drv_data, msg);
drv_data->action = MV64XXX_I2C_ACTION_SEND_START; drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
}
drv_data->send_stop = is_last; drv_data->send_stop = is_last;
drv_data->block = 1; drv_data->block = 1;
mv64xxx_i2c_do_action(drv_data); mv64xxx_i2c_do_action(drv_data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment