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 /drivers | |
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>
Diffstat (limited to 'drivers')
-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 = { |