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: Wolfram Sang <wsa@the-dreams.de>
Tested-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Cc: stable@vger.kernel.org # v3.12+
Fixes: 930ab3d403
(i2c: mv64xxx: Add I2C Transaction Generator support)
This commit is contained in:
Родитель
b28a960c42
Коммит
79970db213
|
@ -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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
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);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче