diff options
| author | Laxman Dewangan <ldewangan@nvidia.com> | 2012-06-13 06:12:38 -0400 |
|---|---|---|
| committer | Wolfram Sang <w.sang@pengutronix.de> | 2012-07-08 06:49:15 -0400 |
| commit | c8f5af2f507d7f97a11065b98ec9f6c22aad8af0 (patch) | |
| tree | b2463605170abcce28e22d58e47ed0014a4ab45f | |
| parent | a70181049fc7b619ddc10cc1b956e7ee04b5bddd (diff) | |
i2c: tegra: support for I2C_M_NOSTART functionality
Adding support for functionality I2C_M_NOSTART.
When multiple message transfer request made through i2c
and if any message is flagged with I2C_M_NOSTART then
it will not send the start/repeat-start and address of
that message i.e. sends data directly.
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
| -rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 68433aeaa2e8..c4593a24331c 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c | |||
| @@ -97,8 +97,21 @@ | |||
| 97 | #define I2C_HEADER_10BIT_ADDR (1<<18) | 97 | #define I2C_HEADER_10BIT_ADDR (1<<18) |
| 98 | #define I2C_HEADER_IE_ENABLE (1<<17) | 98 | #define I2C_HEADER_IE_ENABLE (1<<17) |
| 99 | #define I2C_HEADER_REPEAT_START (1<<16) | 99 | #define I2C_HEADER_REPEAT_START (1<<16) |
| 100 | #define I2C_HEADER_CONTINUE_XFER (1<<15) | ||
| 100 | #define I2C_HEADER_MASTER_ADDR_SHIFT 12 | 101 | #define I2C_HEADER_MASTER_ADDR_SHIFT 12 |
| 101 | #define I2C_HEADER_SLAVE_ADDR_SHIFT 1 | 102 | #define I2C_HEADER_SLAVE_ADDR_SHIFT 1 |
| 103 | /* | ||
| 104 | * msg_end_type: The bus control which need to be send at end of transfer. | ||
| 105 | * @MSG_END_STOP: Send stop pulse at end of transfer. | ||
| 106 | * @MSG_END_REPEAT_START: Send repeat start at end of transfer. | ||
| 107 | * @MSG_END_CONTINUE: The following on message is coming and so do not send | ||
| 108 | * stop or repeat start. | ||
| 109 | */ | ||
| 110 | enum msg_end_type { | ||
| 111 | MSG_END_STOP, | ||
| 112 | MSG_END_REPEAT_START, | ||
| 113 | MSG_END_CONTINUE, | ||
| 114 | }; | ||
| 102 | 115 | ||
| 103 | /** | 116 | /** |
| 104 | * struct tegra_i2c_dev - per device i2c context | 117 | * struct tegra_i2c_dev - per device i2c context |
| @@ -453,7 +466,7 @@ err: | |||
| 453 | } | 466 | } |
| 454 | 467 | ||
| 455 | static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, | 468 | static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, |
| 456 | struct i2c_msg *msg, int stop) | 469 | struct i2c_msg *msg, enum msg_end_type end_state) |
| 457 | { | 470 | { |
| 458 | u32 packet_header; | 471 | u32 packet_header; |
| 459 | u32 int_mask; | 472 | u32 int_mask; |
| @@ -480,7 +493,9 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, | |||
| 480 | i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO); | 493 | i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO); |
| 481 | 494 | ||
| 482 | packet_header = I2C_HEADER_IE_ENABLE; | 495 | packet_header = I2C_HEADER_IE_ENABLE; |
| 483 | if (!stop) | 496 | if (end_state == MSG_END_CONTINUE) |
| 497 | packet_header |= I2C_HEADER_CONTINUE_XFER; | ||
| 498 | else if (end_state == MSG_END_REPEAT_START) | ||
| 484 | packet_header |= I2C_HEADER_REPEAT_START; | 499 | packet_header |= I2C_HEADER_REPEAT_START; |
| 485 | if (msg->flags & I2C_M_TEN) { | 500 | if (msg->flags & I2C_M_TEN) { |
| 486 | packet_header |= msg->addr; | 501 | packet_header |= msg->addr; |
| @@ -552,8 +567,14 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], | |||
| 552 | 567 | ||
| 553 | clk_enable(i2c_dev->clk); | 568 | clk_enable(i2c_dev->clk); |
| 554 | for (i = 0; i < num; i++) { | 569 | for (i = 0; i < num; i++) { |
| 555 | int stop = (i == (num - 1)) ? 1 : 0; | 570 | enum msg_end_type end_type = MSG_END_STOP; |
| 556 | ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop); | 571 | if (i < (num - 1)) { |
| 572 | if (msgs[i + 1].flags & I2C_M_NOSTART) | ||
| 573 | end_type = MSG_END_CONTINUE; | ||
| 574 | else | ||
| 575 | end_type = MSG_END_REPEAT_START; | ||
| 576 | } | ||
| 577 | ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], end_type); | ||
| 557 | if (ret) | 578 | if (ret) |
| 558 | break; | 579 | break; |
| 559 | } | 580 | } |
| @@ -564,7 +585,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], | |||
| 564 | static u32 tegra_i2c_func(struct i2c_adapter *adap) | 585 | static u32 tegra_i2c_func(struct i2c_adapter *adap) |
| 565 | { | 586 | { |
| 566 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | | 587 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | |
| 567 | I2C_FUNC_PROTOCOL_MANGLING; | 588 | I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART; |
| 568 | } | 589 | } |
| 569 | 590 | ||
| 570 | static const struct i2c_algorithm tegra_i2c_algo = { | 591 | static const struct i2c_algorithm tegra_i2c_algo = { |
