diff options
author | Rodolfo Giometti <giometti@linux.it> | 2010-11-26 11:06:56 -0500 |
---|---|---|
committer | Ben Dooks <ben-linux@fluff.org> | 2011-01-03 20:19:43 -0500 |
commit | eda6bee6c7e67b5bd17bdbced0926f5687f686d5 (patch) | |
tree | 3f2be4bb958e1fd320494973d55c45f91381ef4a /drivers/i2c | |
parent | 03ed6a3aa600c48593c3984812fda2d5945ddb46 (diff) |
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: Rodolfo Giometti <giometti@linux.it>
Signed-off-by: Mauro Barella <mbarella@vds-it.com>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-mv64xxx.c | 45 |
1 files changed, 38 insertions, 7 deletions
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 16242063144f..a9941c65f226 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c | |||
@@ -59,6 +59,7 @@ enum { | |||
59 | MV64XXX_I2C_STATE_INVALID, | 59 | MV64XXX_I2C_STATE_INVALID, |
60 | MV64XXX_I2C_STATE_IDLE, | 60 | MV64XXX_I2C_STATE_IDLE, |
61 | MV64XXX_I2C_STATE_WAITING_FOR_START_COND, | 61 | MV64XXX_I2C_STATE_WAITING_FOR_START_COND, |
62 | MV64XXX_I2C_STATE_WAITING_FOR_RESTART, | ||
62 | MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK, | 63 | MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK, |
63 | MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK, | 64 | MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK, |
64 | MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK, | 65 | MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK, |
@@ -70,6 +71,7 @@ enum { | |||
70 | MV64XXX_I2C_ACTION_INVALID, | 71 | MV64XXX_I2C_ACTION_INVALID, |
71 | MV64XXX_I2C_ACTION_CONTINUE, | 72 | MV64XXX_I2C_ACTION_CONTINUE, |
72 | MV64XXX_I2C_ACTION_SEND_START, | 73 | MV64XXX_I2C_ACTION_SEND_START, |
74 | MV64XXX_I2C_ACTION_SEND_RESTART, | ||
73 | MV64XXX_I2C_ACTION_SEND_ADDR_1, | 75 | MV64XXX_I2C_ACTION_SEND_ADDR_1, |
74 | MV64XXX_I2C_ACTION_SEND_ADDR_2, | 76 | MV64XXX_I2C_ACTION_SEND_ADDR_2, |
75 | MV64XXX_I2C_ACTION_SEND_DATA, | 77 | MV64XXX_I2C_ACTION_SEND_DATA, |
@@ -91,6 +93,7 @@ struct mv64xxx_i2c_data { | |||
91 | u32 addr2; | 93 | u32 addr2; |
92 | u32 bytes_left; | 94 | u32 bytes_left; |
93 | u32 byte_posn; | 95 | u32 byte_posn; |
96 | u32 send_stop; | ||
94 | u32 block; | 97 | u32 block; |
95 | int rc; | 98 | int rc; |
96 | u32 freq_m; | 99 | u32 freq_m; |
@@ -159,8 +162,15 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) | |||
159 | if ((drv_data->bytes_left == 0) | 162 | if ((drv_data->bytes_left == 0) |
160 | || (drv_data->aborting | 163 | || (drv_data->aborting |
161 | && (drv_data->byte_posn != 0))) { | 164 | && (drv_data->byte_posn != 0))) { |
162 | drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; | 165 | if (drv_data->send_stop) { |
163 | drv_data->state = MV64XXX_I2C_STATE_IDLE; | 166 | drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; |
167 | drv_data->state = MV64XXX_I2C_STATE_IDLE; | ||
168 | } else { | ||
169 | drv_data->action = | ||
170 | MV64XXX_I2C_ACTION_SEND_RESTART; | ||
171 | drv_data->state = | ||
172 | MV64XXX_I2C_STATE_WAITING_FOR_RESTART; | ||
173 | } | ||
164 | } else { | 174 | } else { |
165 | drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; | 175 | drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; |
166 | drv_data->state = | 176 | drv_data->state = |
@@ -228,6 +238,15 @@ static void | |||
228 | mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) | 238 | mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) |
229 | { | 239 | { |
230 | switch(drv_data->action) { | 240 | switch(drv_data->action) { |
241 | case MV64XXX_I2C_ACTION_SEND_RESTART: | ||
242 | drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START; | ||
243 | drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; | ||
244 | writel(drv_data->cntl_bits, | ||
245 | drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); | ||
246 | drv_data->block = 0; | ||
247 | wake_up_interruptible(&drv_data->waitq); | ||
248 | break; | ||
249 | |||
231 | case MV64XXX_I2C_ACTION_CONTINUE: | 250 | case MV64XXX_I2C_ACTION_CONTINUE: |
232 | writel(drv_data->cntl_bits, | 251 | writel(drv_data->cntl_bits, |
233 | drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); | 252 | drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); |
@@ -386,7 +405,8 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) | |||
386 | } | 405 | } |
387 | 406 | ||
388 | static int | 407 | static int |
389 | mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) | 408 | mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg, |
409 | int is_first, int is_last) | ||
390 | { | 410 | { |
391 | unsigned long flags; | 411 | unsigned long flags; |
392 | 412 | ||
@@ -406,10 +426,18 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) | |||
406 | drv_data->bytes_left--; | 426 | drv_data->bytes_left--; |
407 | } | 427 | } |
408 | } else { | 428 | } else { |
409 | drv_data->action = MV64XXX_I2C_ACTION_SEND_START; | 429 | if (is_first) { |
410 | drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; | 430 | drv_data->action = MV64XXX_I2C_ACTION_SEND_START; |
431 | drv_data->state = | ||
432 | MV64XXX_I2C_STATE_WAITING_FOR_START_COND; | ||
433 | } else { | ||
434 | drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1; | ||
435 | drv_data->state = | ||
436 | MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK; | ||
437 | } | ||
411 | } | 438 | } |
412 | 439 | ||
440 | drv_data->send_stop = is_last; | ||
413 | drv_data->block = 1; | 441 | drv_data->block = 1; |
414 | mv64xxx_i2c_do_action(drv_data); | 442 | mv64xxx_i2c_do_action(drv_data); |
415 | spin_unlock_irqrestore(&drv_data->lock, flags); | 443 | 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 | struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); | 465 | struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); |
438 | int i, rc; | 466 | int i, rc; |
439 | 467 | ||
440 | for (i=0; i<num; i++) | 468 | for (i = 0; i < num; i++) { |
441 | if ((rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i])) < 0) | 469 | rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i], |
470 | i == 0, i + 1 == num); | ||
471 | if (rc < 0) | ||
442 | return rc; | 472 | return rc; |
473 | } | ||
443 | 474 | ||
444 | return num; | 475 | return num; |
445 | } | 476 | } |