Skip to content

Commit a4ea1a1

Browse files
ChiHuaLkartben
authored andcommitted
drivers: i2c: npcx: enhance the transfer efficiency
The i2c_transfer() API allows multiple msgs objects to be carried in a transaction. After handling the current msgs object in the interrupt context, the driver notifies the calling thread to buffer the next msgs object and generate the Re-Start if required. However, if the calling thread is preempted by higher priority threads, the I2C transaction time may become non-deterministic (depending on the execution time of higher-priority threads). This commits modifies the driver to handle msgs objects entirely in the interrupt context to improve the I2C transfer efficiency.. Signed-off-by: Jun Lin <[email protected]>
1 parent 18277b4 commit a4ea1a1

File tree

1 file changed

+51
-13
lines changed

1 file changed

+51
-13
lines changed

drivers/i2c/i2c_npcx_controller.c

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,12 @@ struct i2c_ctrl_data {
168168
enum npcx_i2c_oper_state oper_state; /* controller operation state */
169169
int trans_err; /* error code during transaction */
170170
struct i2c_msg *msg; /* cache msg for transaction state machine */
171+
struct i2c_msg *msg_head;
171172
int is_write; /* direction of current msg */
172173
uint8_t *ptr_msg; /* current msg pointer for FIFO read/write */
173174
uint16_t addr; /* slave address of transaction */
175+
uint8_t msg_max_num;
176+
uint8_t msg_curr_idx;
174177
uint8_t port; /* current port used the controller */
175178
bool is_configured; /* is port configured? */
176179
const struct npcx_i2c_timing_cfg *ptr_speed_confs;
@@ -639,6 +642,24 @@ static void i2c_ctrl_handle_write_int_event(const struct device *dev)
639642
/* Wait for STOP completed */
640643
data->oper_state = NPCX_I2C_WAIT_STOP;
641644
} else {
645+
uint8_t next_msg_idx = data->msg_curr_idx + 1;
646+
647+
if (next_msg_idx < data->msg_max_num) {
648+
struct i2c_msg *msg;
649+
650+
data->msg_curr_idx = next_msg_idx;
651+
msg = data->msg_head + next_msg_idx;
652+
data->msg = msg;
653+
data->ptr_msg = msg->buf;
654+
if ((msg->flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
655+
data->oper_state = NPCX_I2C_WRITE_FIFO;
656+
} else {
657+
data->is_write = 0;
658+
data->oper_state = NPCX_I2C_WAIT_RESTART;
659+
i2c_ctrl_start(dev);
660+
}
661+
return;
662+
}
642663
/* Disable interrupt and handle next message */
643664
i2c_ctrl_irq_enable(dev, 0);
644665
}
@@ -702,6 +723,27 @@ static void i2c_ctrl_handle_read_int_event(const struct device *dev)
702723
/* Release bus */
703724
i2c_ctrl_hold_bus(dev, 0);
704725
return;
726+
} else if ((data->msg->flags & I2C_MSG_STOP) == 0) {
727+
uint8_t next_msg_idx = data->msg_curr_idx + 1;
728+
729+
if (next_msg_idx < data->msg_max_num) {
730+
struct i2c_msg *msg;
731+
732+
msg = data->msg_head + next_msg_idx;
733+
if ((msg->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) {
734+
735+
data->msg_curr_idx = next_msg_idx;
736+
data->msg = msg;
737+
data->ptr_msg = msg->buf;
738+
739+
/* Setup threshold of RX FIFO first */
740+
i2c_ctrl_fifo_rx_setup_threshold_nack(
741+
dev, msg->len, (msg->flags & I2C_MSG_STOP) != 0);
742+
/* Release bus */
743+
i2c_ctrl_hold_bus(dev, 0);
744+
return;
745+
}
746+
}
705747
}
706748
}
707749

@@ -1258,7 +1300,7 @@ int npcx_i2c_ctrl_transfer(const struct device *i2c_dev, struct i2c_msg *msgs,
12581300
{
12591301
struct i2c_ctrl_data *const data = i2c_dev->data;
12601302
int ret = 0;
1261-
uint8_t i;
1303+
struct i2c_msg *msg = msgs;
12621304

12631305
#ifdef CONFIG_I2C_TARGET
12641306
/* I2c module has been configured to target mode */
@@ -1297,25 +1339,21 @@ int npcx_i2c_ctrl_transfer(const struct device *i2c_dev, struct i2c_msg *msgs,
12971339
data->trans_err = 0;
12981340
data->addr = addr;
12991341

1342+
data->msg_head = msgs;
1343+
data->msg_max_num = num_msgs;
1344+
data->msg_curr_idx = 0;
1345+
13001346
/*
13011347
* Reset i2c event-completed semaphore before starting transactions.
13021348
* Some interrupt events such as BUS_ERROR might change its counter
13031349
* when bus is idle.
13041350
*/
13051351
k_sem_reset(&data->sync_sem);
13061352

1307-
for (i = 0U; i < num_msgs; i++) {
1308-
struct i2c_msg *msg = msgs + i;
1309-
1310-
/* Handle write transaction */
1311-
if ((msg->flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
1312-
ret = i2c_ctrl_proc_write_msg(i2c_dev, msg);
1313-
} else {/* Handle read transaction */
1314-
ret = i2c_ctrl_proc_read_msg(i2c_dev, msg);
1315-
}
1316-
if (ret < 0) {
1317-
break;
1318-
}
1353+
if ((msg->flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
1354+
ret = i2c_ctrl_proc_write_msg(i2c_dev, msg);
1355+
} else { /* Handle read transaction */
1356+
ret = i2c_ctrl_proc_read_msg(i2c_dev, msg);
13191357
}
13201358

13211359
/* Check STOP completed? */

0 commit comments

Comments
 (0)