diff options
author | Tang Yuantian <B29983@freescale.com> | 2012-02-23 04:42:45 -0500 |
---|---|---|
committer | Wolfram Sang <w.sang@pengutronix.de> | 2012-02-24 16:25:30 -0500 |
commit | 3f0e1e4bb6a73dce9aed9f82a86f4ae161bf9b06 (patch) | |
tree | a2f41a012d830ef732feb16be462697beda0c77b /drivers | |
parent | 237ab4062d084a3350ff2516d1b39401b2cb87c6 (diff) |
i2c: mpc: Add support for SMBUS_READ_BLOCK_DATA
Add support for SMBUS_READ_BLOCK_DATA to the i2c-mpc bus driver.
Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/busses/i2c-mpc.c | 63 |
1 files changed, 49 insertions, 14 deletions
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index a8ebb84e23f9..206caacd30d7 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c | |||
@@ -454,7 +454,7 @@ static int mpc_write(struct mpc_i2c *i2c, int target, | |||
454 | } | 454 | } |
455 | 455 | ||
456 | static int mpc_read(struct mpc_i2c *i2c, int target, | 456 | static int mpc_read(struct mpc_i2c *i2c, int target, |
457 | u8 *data, int length, int restart) | 457 | u8 *data, int length, int restart, bool recv_len) |
458 | { | 458 | { |
459 | unsigned timeout = i2c->adap.timeout; | 459 | unsigned timeout = i2c->adap.timeout; |
460 | int i, result; | 460 | int i, result; |
@@ -470,7 +470,7 @@ static int mpc_read(struct mpc_i2c *i2c, int target, | |||
470 | return result; | 470 | return result; |
471 | 471 | ||
472 | if (length) { | 472 | if (length) { |
473 | if (length == 1) | 473 | if (length == 1 && !recv_len) |
474 | writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK); | 474 | writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK); |
475 | else | 475 | else |
476 | writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA); | 476 | writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA); |
@@ -479,17 +479,46 @@ static int mpc_read(struct mpc_i2c *i2c, int target, | |||
479 | } | 479 | } |
480 | 480 | ||
481 | for (i = 0; i < length; i++) { | 481 | for (i = 0; i < length; i++) { |
482 | u8 byte; | ||
483 | |||
482 | result = i2c_wait(i2c, timeout, 0); | 484 | result = i2c_wait(i2c, timeout, 0); |
483 | if (result < 0) | 485 | if (result < 0) |
484 | return result; | 486 | return result; |
485 | 487 | ||
486 | /* Generate txack on next to last byte */ | 488 | /* |
487 | if (i == length - 2) | 489 | * For block reads, we have to know the total length (1st byte) |
488 | writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK); | 490 | * before we can determine if we are done. |
489 | /* Do not generate stop on last byte */ | 491 | */ |
490 | if (i == length - 1) | 492 | if (i || !recv_len) { |
491 | writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX); | 493 | /* Generate txack on next to last byte */ |
492 | data[i] = readb(i2c->base + MPC_I2C_DR); | 494 | if (i == length - 2) |
495 | writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | ||
496 | | CCR_TXAK); | ||
497 | /* Do not generate stop on last byte */ | ||
498 | if (i == length - 1) | ||
499 | writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | ||
500 | | CCR_MTX); | ||
501 | } | ||
502 | |||
503 | byte = readb(i2c->base + MPC_I2C_DR); | ||
504 | |||
505 | /* | ||
506 | * Adjust length if first received byte is length. | ||
507 | * The length is 1 length byte plus actually data length | ||
508 | */ | ||
509 | if (i == 0 && recv_len) { | ||
510 | if (byte == 0 || byte > I2C_SMBUS_BLOCK_MAX) | ||
511 | return -EPROTO; | ||
512 | length += byte; | ||
513 | /* | ||
514 | * For block reads, generate txack here if data length | ||
515 | * is 1 byte (total length is 2 bytes). | ||
516 | */ | ||
517 | if (length == 2) | ||
518 | writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | ||
519 | | CCR_TXAK); | ||
520 | } | ||
521 | data[i] = byte; | ||
493 | } | 522 | } |
494 | 523 | ||
495 | return length; | 524 | return length; |
@@ -532,12 +561,17 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | |||
532 | "Doing %s %d bytes to 0x%02x - %d of %d messages\n", | 561 | "Doing %s %d bytes to 0x%02x - %d of %d messages\n", |
533 | pmsg->flags & I2C_M_RD ? "read" : "write", | 562 | pmsg->flags & I2C_M_RD ? "read" : "write", |
534 | pmsg->len, pmsg->addr, i + 1, num); | 563 | pmsg->len, pmsg->addr, i + 1, num); |
535 | if (pmsg->flags & I2C_M_RD) | 564 | if (pmsg->flags & I2C_M_RD) { |
536 | ret = | 565 | bool recv_len = pmsg->flags & I2C_M_RECV_LEN; |
537 | mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); | 566 | |
538 | else | 567 | ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i, |
568 | recv_len); | ||
569 | if (recv_len && ret > 0) | ||
570 | pmsg->len = ret; | ||
571 | } else { | ||
539 | ret = | 572 | ret = |
540 | mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); | 573 | mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); |
574 | } | ||
541 | } | 575 | } |
542 | mpc_i2c_stop(i2c); | 576 | mpc_i2c_stop(i2c); |
543 | return (ret < 0) ? ret : num; | 577 | return (ret < 0) ? ret : num; |
@@ -545,7 +579,8 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | |||
545 | 579 | ||
546 | static u32 mpc_functionality(struct i2c_adapter *adap) | 580 | static u32 mpc_functionality(struct i2c_adapter *adap) |
547 | { | 581 | { |
548 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | 582 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
583 | | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL; | ||
549 | } | 584 | } |
550 | 585 | ||
551 | static const struct i2c_algorithm mpc_algo = { | 586 | static const struct i2c_algorithm mpc_algo = { |