Commit eda6bee6 authored by Rodolfo Giometti's avatar Rodolfo Giometti Committed by Ben Dooks

i2c-mv64xxx: send repeated START between messages in xfer

As stated into file include/linux/i2c.h we must send a repeated START
between messages in the same xfer groupset:

 * Except when I2C "protocol mangling" is used, all I2C adapters implement
 * the standard rules for I2C transactions.  Each transaction begins with a
 * START.  That is followed by the slave address, and a bit encoding read
 * versus write.  Then follow all the data bytes, possibly including a byte
 * with SMBus PEC.  The transfer terminates with a NAK, or when all those
 * bytes have been transferred and ACKed.  If this is the last message in a
 * group, it is followed by a STOP.  Otherwise it is followed by the next
 * @i2c_msg transaction segment, beginning with a (repeated) START.
Signed-off-by: default avatarRodolfo Giometti <giometti@linux.it>
Signed-off-by: default avatarMauro Barella <mbarella@vds-it.com>
Signed-off-by: default avatarBen Dooks <ben-linux@fluff.org>
parent 03ed6a3a
...@@ -59,6 +59,7 @@ enum { ...@@ -59,6 +59,7 @@ enum {
MV64XXX_I2C_STATE_INVALID, MV64XXX_I2C_STATE_INVALID,
MV64XXX_I2C_STATE_IDLE, MV64XXX_I2C_STATE_IDLE,
MV64XXX_I2C_STATE_WAITING_FOR_START_COND, MV64XXX_I2C_STATE_WAITING_FOR_START_COND,
MV64XXX_I2C_STATE_WAITING_FOR_RESTART,
MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK, MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK,
MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK, MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK,
MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK, MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK,
...@@ -70,6 +71,7 @@ enum { ...@@ -70,6 +71,7 @@ enum {
MV64XXX_I2C_ACTION_INVALID, MV64XXX_I2C_ACTION_INVALID,
MV64XXX_I2C_ACTION_CONTINUE, MV64XXX_I2C_ACTION_CONTINUE,
MV64XXX_I2C_ACTION_SEND_START, MV64XXX_I2C_ACTION_SEND_START,
MV64XXX_I2C_ACTION_SEND_RESTART,
MV64XXX_I2C_ACTION_SEND_ADDR_1, MV64XXX_I2C_ACTION_SEND_ADDR_1,
MV64XXX_I2C_ACTION_SEND_ADDR_2, MV64XXX_I2C_ACTION_SEND_ADDR_2,
MV64XXX_I2C_ACTION_SEND_DATA, MV64XXX_I2C_ACTION_SEND_DATA,
...@@ -91,6 +93,7 @@ struct mv64xxx_i2c_data { ...@@ -91,6 +93,7 @@ struct mv64xxx_i2c_data {
u32 addr2; u32 addr2;
u32 bytes_left; u32 bytes_left;
u32 byte_posn; u32 byte_posn;
u32 send_stop;
u32 block; u32 block;
int rc; int rc;
u32 freq_m; u32 freq_m;
...@@ -159,8 +162,15 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) ...@@ -159,8 +162,15 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
if ((drv_data->bytes_left == 0) if ((drv_data->bytes_left == 0)
|| (drv_data->aborting || (drv_data->aborting
&& (drv_data->byte_posn != 0))) { && (drv_data->byte_posn != 0))) {
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; if (drv_data->send_stop) {
drv_data->state = MV64XXX_I2C_STATE_IDLE; drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
drv_data->state = MV64XXX_I2C_STATE_IDLE;
} else {
drv_data->action =
MV64XXX_I2C_ACTION_SEND_RESTART;
drv_data->state =
MV64XXX_I2C_STATE_WAITING_FOR_RESTART;
}
} else { } else {
drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
drv_data->state = drv_data->state =
...@@ -228,6 +238,15 @@ static void ...@@ -228,6 +238,15 @@ static void
mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
{ {
switch(drv_data->action) { switch(drv_data->action) {
case MV64XXX_I2C_ACTION_SEND_RESTART:
drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
writel(drv_data->cntl_bits,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->block = 0;
wake_up_interruptible(&drv_data->waitq);
break;
case MV64XXX_I2C_ACTION_CONTINUE: case MV64XXX_I2C_ACTION_CONTINUE:
writel(drv_data->cntl_bits, writel(drv_data->cntl_bits,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
...@@ -386,7 +405,8 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) ...@@ -386,7 +405,8 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
} }
static int static int
mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
int is_first, int is_last)
{ {
unsigned long flags; unsigned long flags;
...@@ -406,10 +426,18 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) ...@@ -406,10 +426,18 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg)
drv_data->bytes_left--; drv_data->bytes_left--;
} }
} else { } else {
drv_data->action = MV64XXX_I2C_ACTION_SEND_START; if (is_first) {
drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
drv_data->state =
MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
} else {
drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
drv_data->state =
MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
}
} }
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);
spin_unlock_irqrestore(&drv_data->lock, flags); spin_unlock_irqrestore(&drv_data->lock, flags);
...@@ -437,9 +465,12 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -437,9 +465,12 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
int i, rc; int i, rc;
for (i=0; i<num; i++) for (i = 0; i < num; i++) {
if ((rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i])) < 0) rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i],
i == 0, i + 1 == num);
if (rc < 0)
return rc; return rc;
}
return num; return num;
} }
......
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