Skip to content

Commit e1b5b8b

Browse files
GTLin08kartben
authored andcommitted
drivers/i2c: ite: Add handling for read operation with 0-byte length
The current I2C driver assumes that at least one byte will be read in CQ (command queue) mode. However, when a 0-byte read is issued (e.g., by cmd_i2c_scan), The read handler uses (len - 1) to set the command queue length. When len is 0, this underflows to 0xFF, leading to an incorrect transfer length and possible crash. To fix this, add a check in cq_mode_allowed() for reads with length 0: -Fallback to PIO mode in such cases. -Properly handle 0-byte reads by issuing STOP (E_FINISH) when the slave address is acknowledged. -Add appropriate handling for NACK conditions when the slave address is not acknowledged. Signed-off-by: Tim Lin <tim2.lin@ite.corp-partner.google.com>
1 parent d1deb20 commit e1b5b8b

File tree

1 file changed

+32
-9
lines changed

1 file changed

+32
-9
lines changed

drivers/i2c/i2c_ite_enhance.c

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ LOG_MODULE_REGISTER(i2c_ite_enhance, CONFIG_I2C_LOG_LEVEL);
2323
#include "i2c-priv.h"
2424

2525
/* Start smbus session from idle state */
26-
#define I2C_MSG_START BIT(5)
26+
#define I2C_MSG_START BIT(5)
27+
#define I2C_MSG_W2R_MASK (I2C_MSG_RESTART | I2C_MSG_READ | I2C_MSG_STOP)
2728

2829
#define I2C_LINE_SCL_HIGH BIT(0)
2930
#define I2C_LINE_SDA_HIGH BIT(1)
@@ -136,6 +137,8 @@ struct i2c_enhance_data {
136137
uint8_t stop;
137138
/* Number of messages. */
138139
uint8_t num_msgs;
140+
/* NACK */
141+
bool nack;
139142
#ifdef CONFIG_I2C_IT8XXX2_CQ_MODE
140143
/* Store command queue mode messages. */
141144
struct i2c_msg *cq_msgs;
@@ -408,6 +411,7 @@ static int enhanced_i2c_error(const struct device *dev)
408411
} else if ((i2c_str & E_HOSTA_BDS_AND_ACK) == E_HOSTA_BDS) {
409412
if (IT8XXX2_I2C_CTR(base) & E_ACK) {
410413
data->err = E_HOSTA_ACK;
414+
data->nack = true;
411415
/* STOP */
412416
IT8XXX2_I2C_CTR(base) = E_FINISH;
413417
}
@@ -520,6 +524,12 @@ static int enhanced_i2c_tran_read(const struct device *dev)
520524
}
521525
/* read next byte */
522526
i2c_pio_trans_data(dev, RX_DIRECT, in_data, 0);
527+
} else if (data->active_msg->len == 0) {
528+
/* Handle data length of 0 */
529+
data->i2ccs = I2C_CH_NORMAL;
530+
IT8XXX2_I2C_CTR(base) = E_FINISH;
531+
/* wait for stop bit interrupt */
532+
data->stop = 1;
523533
}
524534
}
525535
}
@@ -589,6 +599,19 @@ static int i2c_transaction(const struct device *dev)
589599
}
590600
}
591601
}
602+
603+
/*
604+
* When a transaction results in NACK, ensure that the IT8XXX2_I2C_CTR
605+
* register has been updated E_FINISH before proceeding with the
606+
* following i2c_reset.
607+
*/
608+
if (data->nack) {
609+
data->nack = false;
610+
data->stop = 1;
611+
612+
return 1;
613+
}
614+
592615
/* reset i2c port */
593616
i2c_reset(dev);
594617
IT8XXX2_I2C_CTR1(base) = 0;
@@ -659,6 +682,8 @@ static int i2c_enhance_pio_transfer(const struct device *dev,
659682
if (data->err || (data->active_msg->flags & I2C_MSG_STOP)) {
660683
data->i2ccs = I2C_CH_NORMAL;
661684
}
685+
/* Clear the flag */
686+
data->nack = false;
662687

663688
return data->err;
664689
}
@@ -886,11 +911,10 @@ static bool cq_mode_allowed(const struct device *dev, struct i2c_msg *msgs)
886911
return false;
887912
}
888913
/*
889-
* Write of I2C target address without writing data, used by
890-
* cmd_i2c_scan. Use PIO mode.
914+
* Use PIO mode when no data is written and read, such as in the
915+
* case of cmd_i2c_scan.
891916
*/
892-
if (((msgs[0].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) &&
893-
(msgs[0].len == 0)) {
917+
if (msgs[0].len == 0) {
894918
return false;
895919
}
896920
return true;
@@ -915,10 +939,9 @@ static bool cq_mode_allowed(const struct device *dev, struct i2c_msg *msgs)
915939
* msg[1].flags = I2C_MSG_RESTART | I2C_MSG_READ |
916940
* I2C_MSG_STOP;
917941
*/
918-
if ((msgs[1].flags & I2C_MSG_RESTART) &&
919-
((msgs[1].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) &&
920-
(msgs[1].flags & I2C_MSG_STOP) &&
921-
(msgs[1].len <= CONFIG_I2C_CQ_MODE_MAX_PAYLOAD_SIZE)) {
942+
if (((msgs[1].flags & I2C_MSG_W2R_MASK) == I2C_MSG_W2R_MASK) &&
943+
(msgs[1].len <= CONFIG_I2C_CQ_MODE_MAX_PAYLOAD_SIZE) &&
944+
(msgs[1].len != 0)) {
922945
return true;
923946
}
924947
}

0 commit comments

Comments
 (0)