summaryrefslogtreecommitdiff
path: root/chip/it83xx/i2c.c
diff options
context:
space:
mode:
authorDino Li <Dino.Li@ite.com.tw>2016-08-16 15:41:07 +0800
committerchrome-bot <chrome-bot@chromium.org>2016-08-22 00:11:58 -0700
commit81fd1393fa3ecb4709a7e6f83c402d7a6a1ccf00 (patch)
tree9abd9872f8ad8706d992ee2391dfeea06321d1d8 /chip/it83xx/i2c.c
parente3297d725517de90a657e157f3ceafe53b2b13f2 (diff)
downloadchrome-ec-81fd1393fa3ecb4709a7e6f83c402d7a6a1ccf00.tar.gz
it83xx: fix i2c module
1. If one i2c transaction includes timeout and done events at the same time, the transaction result will be timeout. Fixed: The transaction is succeed instead of timeout. 2. The interrupt of i2c will not be enabled if an i2c write transaction is split into two or more xfer. Signed-off-by: Dino Li <dino.li@ite.com.tw> BRANCH=none BUG=none TEST=1. Console commands:'i2cscan', 'i2cxfer', and 'battery'. 2. Use two or more i2c_xfer(the first with flag 'I2C_XFER_START' and the last with flag 'I2C_XFER_STOP') to do a i2c write transaction and no error. Change-Id: Ieb2cb229748ac9504cf1636a2826bbb3097aa55c Reviewed-on: https://chromium-review.googlesource.com/360762 Commit-Ready: Dino Li <Dino.Li@ite.com.tw> Tested-by: Dino Li <Dino.Li@ite.com.tw> Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'chip/it83xx/i2c.c')
-rw-r--r--chip/it83xx/i2c.c34
1 files changed, 22 insertions, 12 deletions
diff --git a/chip/it83xx/i2c.c b/chip/it83xx/i2c.c
index 2f5dd31fff..b76c04ba1e 100644
--- a/chip/it83xx/i2c.c
+++ b/chip/it83xx/i2c.c
@@ -184,9 +184,9 @@ const struct i2c_ctrl_t i2c_ctrl_regs[] = {
enum i2c_ch_status {
I2C_CH_NORMAL = 0,
- I2C_CH_W2R,
+ I2C_CH_REPEAT_START,
I2C_CH_WAIT_READ,
- I2C_CH_DIRECT_W2R = 4,
+ I2C_CH_WAIT_NEXT_XFER,
};
/* I2C port state data */
@@ -401,6 +401,10 @@ static int i2c_tran_write(int p)
pd->widx++;
/* W/C byte done for next byte */
IT83XX_SMB_HOSTA(p) = HOSTA_NEXT_BYTE;
+ if (pd->i2ccs == I2C_CH_REPEAT_START) {
+ pd->i2ccs = I2C_CH_NORMAL;
+ task_enable_irq(i2c_ctrl_regs[p].irq);
+ }
} else {
/* done */
pd->out_size = 0;
@@ -415,7 +419,7 @@ static int i2c_tran_write(int p)
IT83XX_SMB_HOSTA(p) =
HOSTA_NEXT_BYTE;
} else {
- pd->i2ccs = I2C_CH_W2R;
+ pd->i2ccs = I2C_CH_REPEAT_START;
return 0;
}
}
@@ -451,9 +455,9 @@ static int i2c_tran_read(int p)
else
IT83XX_SMB_HOCTL(p) = 0x5D;
} else {
- if ((pd->i2ccs == I2C_CH_W2R) ||
+ if ((pd->i2ccs == I2C_CH_REPEAT_START) ||
(pd->i2ccs == I2C_CH_WAIT_READ)) {
- if (pd->i2ccs == I2C_CH_W2R) {
+ if (pd->i2ccs == I2C_CH_REPEAT_START) {
/* write to read */
i2c_w2r_change_direction(p);
} else {
@@ -535,12 +539,16 @@ static int enhanced_i2c_tran_write(int p)
/* Send Byte */
i2c_pio_trans_data(p, TX_DIRECT, out_data, 0);
+ if (pd->i2ccs == I2C_CH_WAIT_NEXT_XFER) {
+ pd->i2ccs = I2C_CH_NORMAL;
+ task_enable_irq(i2c_ctrl_regs[p].irq);
+ }
} else {
/* done */
pd->out_size = 0;
if (pd->in_size > 0) {
/* Write to read protocol */
- pd->i2ccs = I2C_CH_W2R;
+ pd->i2ccs = I2C_CH_REPEAT_START;
/* Repeat Start */
i2c_pio_trans_data(p, RX_DIRECT,
(pd->addr + 1), 1);
@@ -555,7 +563,7 @@ static int enhanced_i2c_tran_write(int p)
return 0;
}
/* Direct write with direct read */
- pd->i2ccs = I2C_CH_DIRECT_W2R;
+ pd->i2ccs = I2C_CH_WAIT_NEXT_XFER;
return 0;
}
}
@@ -586,7 +594,7 @@ static int enhanced_i2c_tran_read(int p)
i2c_pio_trans_data(p, RX_DIRECT, (pd->addr + 1), 1);
} else {
if (pd->i2ccs) {
- if (pd->i2ccs == I2C_CH_W2R) {
+ if (pd->i2ccs == I2C_CH_REPEAT_START) {
pd->i2ccs = I2C_CH_NORMAL;
/* Receive data */
i2c_pio_trans_data(p, RX_DIRECT, in_data, 0);
@@ -718,9 +726,7 @@ int chip_i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
if (out_size == 0 && in_size == 0)
return EC_SUCCESS;
- if ((pd->i2ccs == I2C_CH_W2R) ||
- (pd->i2ccs == I2C_CH_WAIT_READ) ||
- (pd->i2ccs & I2C_CH_DIRECT_W2R)) {
+ if (pd->i2ccs) {
if ((flags & I2C_XFER_SINGLE) == I2C_XFER_SINGLE)
flags &= ~I2C_XFER_START;
}
@@ -774,12 +780,16 @@ int chip_i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
pd->task_waiting = TASK_ID_INVALID;
/* Handle timeout */
- if (events & TASK_EVENT_TIMER) {
+ if (!(events & TASK_EVENT_I2C_IDLE)) {
pd->err = EC_ERROR_TIMEOUT;
/* reset i2c port */
i2c_reset(port, I2C_RC_TIMEOUT);
}
+ /* reset i2c channel status */
+ if (pd->err)
+ pd->i2ccs = I2C_CH_NORMAL;
+
return pd->err;
}